赞
踩
线索化二叉树。(至于,这里怎么定义二叉树的类型,我就不多说了,可以看书本上的定义即可)首先看一下这部分代码:
void InOrderThreading(BiThrTree& Thrt, BiThrTree T) { Thrt = (BiThrTree)malloc(sizeof(BiThrNode)); if (Thrt == NULL) { printf("内存分配失败\n"); exit(-1); } Thrt->data = -1;//头指针数据域为无效值-1 Thrt->RTag = Thread;//头指针有其后继 Thrt->rchild = Thrt;//暂时令其后继为自己 Thrt->LTag = Link;//头指针没有前驱 if (!T)//如果T为空树时,令其左指针指向自己 { Thrt->lchild = Thrt; } else { Thrt->lchild = T; pre = Thrt; InThreading(T); //线索化最后一个节点 pre->rchild = Thrt; pre->RTag = Thread; Thrt->rchild = pre; } } //end** //start** void InThreading(BiThrTree P) { if (P) { InThreading(P->lchild);//先线索化左子树 /* 如果满足该if语句,说明已经到了某个子树的左边的尽头 */ if (!P->lchild) { P->LTag = Thread; P->lchild = pre; } /* 不管上面if语句是否满足,相对P来说,其都是有一个前驱元素X存在的 从另一方面来说,就是X的后继就是P 而pre的定义就是P刚刚访问后的节点,对于中序遍历来说,pre就是P的前驱 所以,下一步应该计算pre的后继元素 */ if (!pre->rchild) { pre->RTag = Thread; pre->rchild = P; } pre = P;//因为P马上就要==P->rchild了,在此之前,用pre来来保存P访问节点 InThreading(P->rchild);//再线索化左子树 } } //end**
我认为难点就在 void InThreading(BiThrTree P)函数中,他是怎么就写出来的,我最近也一直在“研究”递归,被弄得云里雾里的。但是,我还是在这里写一哈自己的想法,一是为了方便之后的复习,二是希望万能的网友能和我一起交流这个问题,共同进步。
首先明白一点,我在这里实现的是中序遍历的线索化,所以,第一个要设置为Thread的节点必然是最左边的那个节点,即P->lchild==NULL。对应的代码就是if§这个判断语句,因为只有当该节点不为NULL时才可以继续走下去。InThreading(P->lchild);这条语句明显是一个递归语句,那么什么时候才能执行下面的语句捏。根据递归的定义可知,只有当最后一个InThreading(P->lchild)执行完毕后,就会返回到上一个InThreading(P->lchild)这里,然后接着往下执行。
现在的p是什么捏?是根的左子树中第一个没有左孩子的节点。所以,这个是我们要线索化的节点。自然的就会去写
if (!P->lchild)
{
P->LTag = Thread;
P->lchild = pre;
}
// 这个代码。因为pre的定义可知,所以p->lchild应该赋值为pre。
那么,你找了p是否会有前驱(因为在之后的递归中,可能不满足if(!P->lchild)这个条件),那么自然你现在得去找pre的后继。这里就得用到我之前所讲的那个后继这个概念了。
所以现在去找pre的后继。执行代码
if (!pre->rchild)
{
pre->RTag = Thread;
pre->rchild = P;
}
后继线索也寻找完毕后,那么就要去看p有没有右孩子了。但是,在此之前,根据pre的定义可知,pre要始终指向p之前访问过的节点。所以,在p=p->rchild之前,先执行
pre=p;
然后执行
InThreading(P->rchild);
那么,这样这个 void InThreading(BiThree p)函数分析完毕。
可能还不是特别清楚,我现在拿一颗树来做个演示。下面还有我的实例代码,可以参考一下,对着这个图分析一下。(好吧,这个图画的太丑了,大家还是尽力理解吧,可以自己尝试画图,这样才可以深入理解递归)
这个是完整代码,可能对着分析一下
//start** void InOrderTraverse_Thr(BiThrTree T) { BiThrTree P = T->lchild;//P指向根节点 while (T != P) { while (P->LTag == Link) { P = P->lchild;//中序遍历的老套路 } printf("%5d", P->data);//所以此时该输出数据了 /* 进入这个while循环,代表该节点左边没有子树了, 右边也没有子树了,并且不是中序遍历的最后一个节点 因为最后一个节点的rchild指向头指针 */ while (P->RTag == Thread && P->rchild != T) { P = P->rchild; printf("%5d", P->data); } P = P->rchild; } } //end** //start** void InOrderThreading(BiThrTree& Thrt, BiThrTree T) { Thrt = (BiThrTree)malloc(sizeof(BiThrNode)); if (Thrt == NULL) { printf("内存分配失败\n"); exit(-1); } Thrt->data = -1;//头指针数据域为无效值-1 Thrt->RTag = Thread;//头指针有其后继 Thrt->rchild = Thrt;//暂时令其后继为自己 Thrt->LTag = Link;//头指针没有前驱 if (!T)//如果T为空树时,令其左指针指向自己 { Thrt->lchild = Thrt; } else { Thrt->lchild = T; pre = Thrt; InThreading(T); //线索化最后一个节点 pre->rchild = Thrt; pre->RTag = Thread; Thrt->rchild = pre; } } //end** //start** void InThreading(BiThrTree P) { if (P) { InThreading(P->lchild);//先线索化左子树 /* 如果满足该if语句,说明已经到了某个子树的左边的尽头 */ if (!P->lchild) { P->LTag = Thread; P->lchild = pre; } /* 不管上面if语句是否满足,相对P来说,其都是有一个前驱元素X存在的 从另一方面来说,就是X的后继就是P 而pre的定义就是P刚刚访问后的节点,对于中序遍历来说,pre就是P的前驱 所以,下一步应该计算pre的后继元素 */ if (!pre->rchild) { pre->RTag = Thread; pre->rchild = P; } pre = P;//因为P马上就要==P->rchild了,在此之前,用pre来来保存P访问节点 InThreading(P->rchild);//再线索化左子树 } } //end**
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。