前言:
关于二叉线索树有什么作用,为什么要建立这里就不介绍。因为时间问题,只是总结一下线索化和遍历的算法。这个算法和前面总结过的非递归法遍历二叉树都算是数据结构里面难度系数比栈,队列,线性表那些大的算法。限定时间内要写出来还是有些难度,最好是能有所总结,才能做到得心应手。
先序:
先序线索化
void PreThreading(BiTreeNode *p, BiTreeNode *pre==NULL) { //在数据结构中我比较喜欢用p指针指向正在操作的结点
if(p != NULL){
if(p->lchild == NULL) { //当前结点的左孩子为空可作索引(前继索引)
p->lchild = prev;
p->ltag = 1; //1表示索引,0表示结点
}
if(prev != NULL && prev->rchlid == NULL) { //上一个结点的右孩子为空可作索引(后继索引)
prev->rchild = p;
prev->ltag = 1;
}
prev = p; //前驱往后走一步
if(p->ltag == 0) //p也往前走, 先左走后右,按照先序遍历的顺序 根-左-右
PreThreading(p->lchild);
PreThreading(p->rchild);
}
}
前序遍历
//用前序线索化建立的线索树来进行前序遍历,实际上ltag为1,即前续索引指针是没什么卵用的。主要用的是后续索引指针,这个指针也就使得我们进行前序遍历不需要借助递归和栈也能完成。
void PreOrder(BiTreeNode *ROOT) {
if(ROOT == NULL)
return;
BiTreeNode *p = ROOT;//工作指针
while(p != NULL) {
//将左子树遍历完,之所以只需要tag为0,是因为空指针直接标1了,即空指针=索引结点
while(p->ltag == 0) {
cout << p->data << " ";
p = p->lchild;
}
cout << p->data << " "; //最左一个结点,自身也要访问
//这就是后续线索指针的作用了,直接访问后续
if(p->ltag == 1)
p = p->rchild;//这一步结束之后如果p是NULL,则这次循环完就结束了
while(p != NULL) {
if (p->ltag = 0) //左边还有结点
break; //跳出小循环,回到大循环继续做
cout << p->data << " ";
p = p->rchild; //由于上面已经过滤了有左孩子的情况,只要一直往右走就是。
}
}
}
中序
中序线索化
void InThreading(ThreadTree &p,ThreadTree &pre) {
if(p != NULL)
InThreading(p->lchild,pre);
if(p->lchild == NULL) { //前驱线索
p->lchild = pre;
p->ltag = 1;
}
if(pre!=NULL && pre->rchild==NULL) { //后续线索
pre->rchild = p;
pre->rtag = 1;
}
InThreading(p->rchild,pre);
}
中序遍历线索树
TheradNode *FirstNode(ThreadNode *p) { //找到最左边结点(前序在这一步就要边走边访问)
while(p->Itag==0) p=p->lchild;
return p;
}
ThreadNode *NextNode(ThreadNode *p) {
if(p->rtag == 0) return FirstNode(p->rchild);//继续访问右结点的前序
else return p->rchild;//直接返回后续线索(这个就是中序序列下一个结点,注意区别于之前的前序序列)
}
void Inorder(ThreadNode *T) {
for(ThreadNode *p=FirstNode(T);p!=NULL;p=NextNode())
visit(p);
}
后序
后序线索化
void PostThreading(ThreadTree &p,ThreadTree &pre) {
if(p!=NULL) {
PostThreading(p->rchild);
PostThreading(p->lchild);
if(p->lchild==NULL) {
p->lchild = pre;
p->ltag = 1;
}
if(pre!=NULL && pre->rchild == NULL) {
pre->rchild = p;
pre->rtag = 1;
}
pre = p;
}
}
后续遍历
后续如果没有添加双亲指针,是无法实现的。
怎么理解呢:
如图,遍历到E的时候,下一个结点是B,但是E的左右都有孩子结点,没有多余的指针可以指向B,所以除非借助双亲指针或者栈的帮助,否则无法实现。