目录
B站up:tyrantlucifer的视频
1、问题
(1)树是否是一个线性结构?
答案是否定的,线性结构一般具有前驱和后继。我们可以使用线索将二叉树转换成一个类似的线性结构。
(2)什么是线索?
线索其实就是将节点连在一起的指针;如果一个二叉树有n个节点,那么有n-1个指针指向他们,但所有节点一共拥有2n个指针,因此有n+1个指针没有利用。使用这n+1个指针,来指向我们二叉树遍历序列的前驱和后继,线索化之后就形成了线索二叉树。
2、中序线索二叉树
(1)线索二叉树的数据结构定义
typedef struct TreeNode{
char data;
struct TreeNode* lchild;
struct TreeNode* rchild;
int ltag; //左指针是否为线索化指针标志位,1为线索化,0为非线索化
int rtag; //左指针是否为线索化指针标志位,1为线索化,0为非线索化
}
(2)普通二叉树的创建
void createTree(TreeNode** T, 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)->ltag = 0;
(*T)->rtag = 0;
//创建左子树,逻辑一致,递归
createTree(&((*T)->lchild), data, index);
//创建右子树,逻辑一致
createTree(&((*T)->rchild), data, index);
}
}
(3)二叉树线索化
根据以上定义,暂时肤浅的认为线索二叉树与普通二叉树的区别只是将未利用的n+1个指针,指向该节点的前驱和后继。因此中序线索二叉树就是在二叉树中序遍历的过程中,将这n+1个指针线索化。
//递归线索化,但会遗漏最后一个
void inThreadTree(TreeNode* T, TreeNode** pre){
if(T){
inThreadTree(T->lchild, pre);
if(T->lchild == NULL){
T->ltag =1;
T->lchild = *pre;
}
if(*pre != NULL && (*pre)->rchild == NULL){
(*pre)->rtag = 1;
(*pre)->rchild = T;
}
*pre = T;
inTreadTree(T->rchild, pre);
}
}
//最终线索化二叉树
void getThread(TreeNode* T, TreeNode** pre){
inThreadTree(T, &pre);
pre -> rtag = 1;
pre -> rchild = NULL;
}
(4)遍历中序线索二叉树
找到中序的第一个节点
TreeNode* getFirst(TreeNode* T){
while(T->ltag == 0){
T = T->lchild;
return T;
找到下一个节点的函数
TreeNode* getNext(TreeNode* node){
if(node->rtag ==1)
return node->rchild;
else
return getFirst(node->rchild);
}
主函数
int main(int argc, char* argv[]) {
TreeNode* T;
TreeNode* pre = NULL;
int index = 0;
createTree(&T, argv[1], &index);
getThread(T, &pre);
for (TreeNode* node = getFirst(T); node != NULL; node = getNext(node)) {
printf("%c ", node -> data);
}
printf("\n");
return 0;
}