实战数据结构(12)_二叉树的线索化

来源:互联网 发布:15年广东省的经济数据 编辑:程序博客网 时间:2024/05/01 09:05
     二叉树的线索化,花了点时间去整理。整个递归过程还是有些抽象的。为什么要进行二叉树的线索化,目的就是为了节省使用二叉链表实现过程中,太多的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:30void 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;} 


0 0
原创粉丝点击