1.1 说明 因为很多篇幅都和前面帖子内容重合 故本次只给出伪代码
//二叉树结构体
typedef struct ThreadNode {
int data;
struct ThreadNode *lchild , *rchild;
int ltag,rtag; //1是线索
} ThreadNode, *ThreadTree;
ThreadNode *pre=NULL; //定义一个全局变量作为pre前序
/**
二叉树的创建、线索化、省略
*/
1.2 中序线索树的遍历
//线索树的遍历
/**
中序线索遍历
中序遍历: 左 根 右
(1)前驱
对于一个结点p来说,它有两种情况
1.1) p->ltag == 1
则p的左孩子为p的前驱
1.2) p->ltag == 0
左线索化== 0 则p一定有左孩子
因为是左根右的遍历 所以p的前驱一定是它的左子树最右下角的那个结点
(2)后继
对于一个结点p来说,它有两种情况
2.1) p->rtag == 1
则p的右孩子为p的后继
2.2) p->rtag == 0
则是右子树中第一个左子树的最左下角结点
*/
//(1)找前驱
//获取当前树最后一个结点
ThreadNode *lastNode(ThreadNode *p){
while(p->rtag == 0){
//循环找到左子树最右下的结点 即最后一个结点
p = p->rchild;
}
return p;
}
ThreadNode *preNode(ThreadNode *p){
if(p->ltag == 1) return p->lchild;
else return lastNode(p->lchild); //返回左子树的最后一个结点
// 下面内容应该耦合为一个函数,这样可以方便在总体遍历的时候找到开始节点
// else{
// ThreadNode *q = p->lchild;
// //0.2) 左子树最右下角的元素
// while(q->rtag == 0){ //得是未被线索化的右孩子 而且最右下角的孩子右节点一定会被线索化
// //循环找到左子树最右下的结点 即最后一个结点
// q = q->rchild;
// }
// return q;
// }
}
//(2)找后继
//获取当前树的第一个结点
ThreadNode *firstNode(ThreadNode *p){
while(p->ltag == 0){
p = p->lchild;
}
return p;
}
ThreadNode *nextNode(ThreadNode *p){
if(p->rtag == 1) return p->rchild;
//否则返回右子树的第一个结点
else return firstNode(p->rchild);
}
1.3 main函数及运行测试
int main() {
ThreadTree root = createNode(1); //root
//第二层
root->lchild = createNode(2);
root->rchild = createNode(3);
//第三层
root->lchild->lchild = createNode(4);
root->lchild->rchild = createNode(5);
root->rchild->lchild = createNode(6);
//第四层
root->lchild->rchild->lchild = createNode(7);
//中序线索化(详细代码见前贴)
createInThreadTree(root);
//中序正向线索遍历
printf("\n开始正向遍历:\n");
for(ThreadNode *i = firstNode(root) ; i != NULL ; i = nextNode(i) ){
printf("i: %d\n",i->data);
}
//中序逆向线索遍历
printf("\n开始逆向遍历:\n");
for(ThreadNode *i = lastNode(root) ; i != NULL ; i = preNode(i)){
printf("i: %d\n",i->data);
}
/*
1
/ \
2 3
/ \ /
4 5 6
/
7
*/
return 0;
}
可以看到遍历成功