线索二叉树
* 线性结构有前驱有后继。我们使用线索将二叉树转换成类似的线性结构
* 什么是线索?线索其实就是将节点连在一起的指针;
* 如果一个二叉树有 n 个节点,那么有多少个指针指向这些节点?
* 有 n-1 个指针指向他们。
* 一共有多少个指针?
* 有 2n 个指针,2n - (n - 1) = n + 1 个指针没有用
* 利用这个n + 1个指针,来指向我们二叉树遍历序列当中的前驱和后继。
以此二叉树为例:
前序遍历算法代码:
先序线索二叉树:是指如果节点没有左右孩子,则指针指向先序遍历的前驱和后继
* 左 --> 前驱
* 右 --> 后继
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct TreeNode
{
char data;
struct TreeNode *leftChild;
struct TreeNode *rightChild;
int leftTag; // 0 --> 指向Child
int rightTag; // 0 --> 指向Child
} TreeNode;
// 当字符为 # 时 --> 空节点
void createTree(TreeNode **T, const char *data, int *index) // 以先序遍历创建
{
char ch;
ch = data[*index];
*index += 1;
if (ch == '#')
{
// 此时为空节点
*T = NULL;
}
else
{
// 此时不为空
*T = (TreeNode *)malloc(sizeof(TreeNode));
(*T)->data = ch;
(*T)->leftTag = 0;
(*T)->rightTag = 0;
// 创建左子树,逻辑一致,进行递归
createTree(&((*T)->leftChild), data, index);
// 创建右子树,逻辑一致,进行递归
createTree(&((*T)->rightChild), data, index);
}
}
void preThreadTree(TreeNode *T, TreeNode **pre)
{
if (T != NULL)
{
if (T->leftChild == NULL) // 左孩子为空,则 左孩子可以指向前驱
{
T->leftTag = 1;
T->leftChild = *pre;
}
if (*pre != NULL && (*pre)->rightChild == NULL)
{
(*pre)->rightTag = 1;
(*pre)->rightChild = T;
}
*pre = T;
if (T->leftTag == 0) // 是有左孩子的
{
preThreadTree(T->leftChild, pre);
}
preThreadTree(T->rightChild, pre);
}
}
TreeNode *getNext(TreeNode *node)
{
if (node->rightTag == 1)
{
return node->rightChild;
}
else
{
if (node->leftTag == 0)
{
return node->leftChild;
}
else
{
return node->rightChild;
}
}
return node->leftChild;
}
void print(TreeNode *T) // 前序遍历
{
for (TreeNode *node = T; node != NULL; node = getNext(node))
{
printf("%c ", node->data);
}
}
int main(int argc, char const *argv[])
{
TreeNode *T;
TreeNode *pre = NULL;
int index = 0;
createTree(&T, argv[1], &index);
preThreadTree(T, &pre);
pre->rightTag = 1;
pre->rightChild = NULL;
printf("前序遍历,线索二叉树 > ");
print(T);
putchar(10);
printf("----------------------------------------------------------\n");
return 0;
}
运行结果:
superlan@GodFather:~/C_Language/data_structure$ ./a.out ABD#F##E##C##
前序遍历,线索二叉树 > A B D F E C
----------------------------------------------------------
中序遍历算法代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct TreeNode
{
char data;
struct TreeNode *leftChild;
struct TreeNode *rightChild;
int leftTag; // 0 --> 指向Child
int rightTag; // 0 --> 指向Child
} TreeNode;
// 当字符为 # 时 --> 空节点
void createTree(TreeNode **T, const char *data, int *index) // 以先序遍历创建
{
char ch;
ch = data[*index];
*index += 1;
if (ch == '#')
{
// 此时为空节点
*T = NULL;
}
else
{
// 此时不为空
*T = (TreeNode *)malloc(sizeof(TreeNode));
(*T)->data = ch;
(*T)->leftTag = 0;
(*T)->rightTag = 0;
// 创建左子树,逻辑一致,进行递归
createTree(&((*T)->leftChild), data, index);
// 创建右子树,逻辑一致,进行递归
createTree(&((*T)->rightChild), data, index);
}
}
void inThreadTree(TreeNode *T, TreeNode **pre)
{
if (T != NULL)
{
inThreadTree(T->leftChild, pre);
// 处理
if (T->leftChild == NULL) // 左孩子为空,则 左孩子可以指向前驱
{
T->leftTag = 1;
T->leftChild = *pre;
}
if (*pre != NULL && (*pre)->rightChild == NULL)
{
(*pre)->rightTag = 1;
(*pre)->rightChild = T;
}
*pre = T;
inThreadTree(T->rightChild, pre);
}
}
TreeNode *getFirst(TreeNode *T)
{
while (T->leftTag == 0)
{
T = T->leftChild;
}
return T;
}
TreeNode *getNext(TreeNode *node)
{
if (node->rightTag == 1)
{
return node->rightChild;
}
else
{
return getFirst(node->rightChild);
}
}
void inprint(TreeNode *T) // 中序遍历
{
for (TreeNode *node = getFirst(T); node != NULL; node = getNext(node))
{
printf("%c ", node->data);
}
}
int main(int argc, char const *argv[])
{
TreeNode *T;
TreeNode *pre = NULL;
int index = 0;
createTree(&T, argv[1], &index);
inThreadTree(T, &pre);
pre->rightTag = 1;
pre->rightChild = NULL;
printf("中序遍历,线索二叉树 > ");
inprint(T);
putchar(10);
printf("----------------------------------------------------------\n");
return 0;
}
运行结果:
superlan@GodFather:~/C_Language/data_structure$ ./a.out ABD#F##E##C##
中序遍历,线索二叉树 > D F B E A C
----------------------------------------------------------
后序遍历算法代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct TreeNode
{
char data;
struct TreeNode *leftChild;
struct TreeNode *rightChild;
struct TreeNode *parent;
int leftTag; // 0 --> 指向Child
int rightTag; // 0 --> 指向Child
} TreeNode;
// 当字符为 # 时 --> 空节点
void createTree(TreeNode **T, const char *data, int *index, TreeNode *parent) // 以先序遍历创建
{
char ch;
ch = data[*index];
*index += 1;
if (ch == '#')
{
// 此时为空节点
*T = NULL;
}
else
{
// 此时不为空
*T = (TreeNode *)malloc(sizeof(TreeNode));
(*T)->data = ch;
(*T)->leftTag = 0;
(*T)->rightTag = 0;
(*T)->parent = parent;
// 创建左子树,逻辑一致,进行递归
createTree(&((*T)->leftChild), data, index, *T);
// 创建右子树,逻辑一致,进行递归
createTree(&((*T)->rightChild), data, index, *T);
}
}
TreeNode *getFirst(TreeNode *T)
{
while (T->leftTag == 0)
{
T = T->leftChild;
}
if (T->rightTag == 0)
{
return getFirst(T->rightChild);
}
return T;
}
void postThreadTree(TreeNode *T, TreeNode **pre)
{
if (T != NULL)
{
postThreadTree(T->leftChild, pre);
postThreadTree(T->rightChild, pre);
if (T->leftChild == NULL)
{
T->leftTag = 1;
T->leftChild = *pre;
}
if (*pre != NULL && (*pre)->rightChild == NULL)
{
(*pre)->rightTag = 1;
(*pre)->rightChild = T;
}
*pre = T;
}
}
TreeNode *getNext(TreeNode *node)
{
if (node->rightTag == 1)
{
return node->rightChild;
}
else
{
// 如果是根节点
if (node->parent == NULL)
{
return NULL;
}
// 如果是右孩子
else if (node->parent->rightChild == node)
{
return node->parent;
}
// 如果是左孩子
else
{
if (node->parent->leftTag == 0)
{
return getFirst(node->parent->rightChild);
}
else
{
return node->parent;
}
}
}
}
/**
* 寻找第一个节点:
* 1、找到最左边的节点
* 2、判断这个节点,是否有右子树,如果有的话,继续寻找以右子树为根树的最左边节点
* 如果没有那么就是第一个节点
*/
void print(TreeNode *T) // 中序遍历
{
for (TreeNode *node = getFirst(T); node != NULL; node = getNext(node))
{
printf("%c ", node->data);
}
}
int main(int argc, char const *argv[])
{
TreeNode *T;
TreeNode *pre = NULL;
int index = 0;
createTree(&T, argv[1], &index, NULL);
postThreadTree(T, &pre);
printf("后序遍历,线索二叉树 > ");
print(T);
putchar(10);
printf("----------------------------------------------------------\n");
return 0;
}
运行结果如下:
superlan@GodFather:~/C_Language/data_structure$ ./a.out ABD#F##E##C##
后序遍历,线索二叉树 > F D E B C A
----------------------------------------------------------