二叉树的线索化,花了点时间去整理。整个递归过程还是有些抽象的。为什么要进行二叉树的线索化,目的就是为了节省使用二叉链表实现过程中,太多的NULL指针。如果把这些空指针都利用起来,串起来一个循环双向链表,那么对于查找是非常方便的。对于查找而言,如中序遍历,我们关心的是一个节点的后继节点和前驱节点。 因为对于未线索化的二叉树而言,只能从某个节点来获取它的左右孩子节点,也就说只能置顶向下,而不能同过节点快速找到其前驱节点,如果要获取的话,又要遍历一次。 所以,线索化,就能清楚的知道某个节点的前驱和后继节点,这样将那些空余的节点利用起来了,而且查找也方便了。 下面就是代码的实现: (1) 线索二叉树的数据结构 (2) 创建二叉树,并且线索化 (3)线索化的二叉树的遍历,注意不能使用递归了。 (4)线索化的二叉树的查找。
/*********************************************************************** 二叉树的线索化 (1)创建二叉树(按照带括号的字符串) (2)二叉树的线索化 (3)二叉树线索化后遍历 (4)查找某个值的 先驱节点 (5)查找某个值的 后继节点 ************************************************************************/ #include <cstdio> typedef enum {Link,Thread} PointFlag; //定义枚举量 pointflag为二者之一 typedef struct Node { char ch; // 数据域 struct Node *plchild,*prchild; // 左右节点指针 PointFlag lflag,rflag; // 标志位 link为 连接 thread为线索标志 }BiTreeNode; const int MAX=20; //按照字符串创建 A(B(,D(G)),C(E(,H),F)) 16:30 void CreateBiTree_ByString(BiTreeNode * &T,char str[]) { BiTreeNode *p=NULL; int flag=0,top=0;//flag=1左孩子,flag=2右孩子 top为栈量 BiTreeNode *Stack[MAX]; //栈 用于存父节点 while(*str) { switch(*str) { case ‘(‘: //则刚创建的节点为 父节点入栈 Stack[top++]=p; flag=1; break; case ‘,‘: flag=2; break; case ‘)‘: top--; //构造完毕了栈顶节点的左右孩子 出栈 break; default: p=new BiTreeNode ; if(NULL==p) return ; p->ch=*str; p->plchild=p->prchild=NULL; p->lflag=p->rflag=Link; if(T==NULL) //创建根节点 T=p; else { switch(flag) { case 1: Stack[top-1]->plchild=p; //p为左孩子 break; case 2: Stack[top-1]->prchild=p; //p为右孩子 break; } /* if(Stack[top-1]->plchild) Stack[top-1]->lflag=Link; if(Stack[top-1]->prchild) Stack[top-1]->rflag=Link;*/ } break; } ++str; } } void LDR_Traverse(BiTreeNode *T) { if(T) { LDR_Traverse(T->plchild); printf("%2c",T->ch); LDR_Traverse(T->prchild); } } BiTreeNode *g_pre; //全局 /*********************************************************************** 二叉树进行中序遍历线索化 难点:写法上和中序遍历一样。先不断的访问左子树的最左节点(中序的思路) 那么如何进行前驱和后继节点的连接呢? 前驱: 是完成当前指针p的前驱 后继:是完成之前节点的后继 ***********************************************************************/ void LDR_Traverse_Thread(BiTreeNode *p) { if(p) { LDR_Traverse_Thread(p->plchild); //将左子树线索化 if(p->plchild==NULL) //一直遍历到最左子节点 叶子节点或者只有右子树 { //p更新 前驱节点 p->lflag=Thread; //p的左孩子节点 标志为 前驱 p->plchild=g_pre; // g_pre保存为上一个访问的节点(按照中序遍历顺序) } if(g_pre->prchild==NULL) // { g_pre->rflag=Thread; g_pre->prchild=p; } g_pre=p; //p已经遍历过 pre指向刚遍历过的节点 LDR_Traverse_Thread(p->prchild); } } //二叉树的线索化 BiTreeNode* BiTreeThread(BiTreeNode* &T) { //构造头结点 BiTreeNode *p=new BiTreeNode; if(!p || !T) return NULL; //头节点处理 p->lflag=Link; p->rflag=Thread; p->plchild=T; //头结点左孩子 指向根节点 p->prchild=p; //头结点右孩子 指向自己 g_pre=p; //g_pre初始化 指向头节点 LDR_Traverse_Thread(T); //将T树进行线索化 //最后一个节点处理 g_pre->rflag=Thread; //最后一个节点 标志位 g_pre->prchild=p; //最后一个节点 后继指向头节点 p->prchild=g_pre; //头节点后继为 最后一个节点 return p; //返回头节点 } //中序非递归 遍历线索化 后 void LDR_Travese_AfterThread(BiTreeNode *T) { BiTreeNode *p=T->plchild; //p为根节点 while(p!=T) { while(p->lflag==Link) p=p->plchild; printf("%2d %2c %2d \n",p->lflag,p->ch,p->rflag); while(p->rflag==Thread && p->prchild !=T) //如果 p有后继节点则 直接通过后继节点访问下一个 节点 { p=p->prchild; printf("%2d %2c %2d \n",p->lflag,p->ch,p->rflag); } p=p->prchild; } } //找到指定节点的前驱节点 BiTreeNode *FindPointNode(BiTreeNode *Head,char key) { BiTreeNode *p=Head->plchild; //获取根节点 while(p!=Head) { while(p->lflag==Link) p=p->plchild; if(p->ch== key) return p; while(p->rflag == Thread && p->prchild !=Head ) { p=p->prchild; if(p->ch == key) return p; } p=p->prchild; } return NULL; } //找到指定节点的后继节点 //就是根据 rflag==1直接找到,后者去找该节点右子树最左节点 BiTreeNode *FindNextNode(BiTreeNode *p) { BiTreeNode *pre=NULL; if(p->rflag==Thread) return p->prchild; else { pre=p->prchild; while(pre->lflag==Link) pre=pre->plchild; return pre; } } //找指定节点的前驱节点 //如果该节点的lflag==1直接返回,否则就找到该节点的左子树的最右节点 BiTreeNode *FindPreNode(BiTreeNode *p) { BiTreeNode *pre=NULL; if(p->lflag==Thread) return p->plchild; else { pre=p->plchild; while(pre->rflag==Link) pre=pre->prchild; return pre; } } int main() { BiTreeNode *T=NULL; CreateBiTree_ByString(T,"A(B(,D(G)),C(E(,H),F))"); puts("中序递归遍历为:"); LDR_Traverse(T); printf("\n"); BiTreeNode *head=BiTreeThread(T); puts("中序遍历线索化后"); LDR_Travese_AfterThread(head); BiTreeNode *pos=FindPointNode(head,‘D‘); printf("D的后继节点为\t%2c\n",FindNextNode(pos)->ch); pos=FindPointNode(head,‘C‘); printf("C的前驱节点为\t%2c\n",FindPreNode(pos)->ch); printf("\n"); return 0; }
实战数据结构(12)_二叉树的线索化,布布扣,bubuko.com
原文:http://blog.csdn.net/lynnbest/article/details/22324173