线索二叉树及若干操作

  1 /* 遍历二叉树就是以一定的规则将二叉树中的节点排列成一个线性
  2  * 序列,从而得到二叉树节点的各种遍历序列,其实质是:对一个
  3  * 非线性的结构进行线性化。使得在这个访问序列中每一个节点都
  4  * 有一个直接前驱和直接后继。
  5  * 传统的链式结构只能体现一种父子关系,¥不能直接得到节点在
  6  * 遍历中的前驱和后继¥,而我们知道二叉链表表示的二叉树中有
  7  * 大量的空指针,当使用这些空的指针存放指向节点的前驱和后继
  8  * 的指针时,则可以更加方便的运用二叉树的某些操作。
  9  * 引入线索二叉树的目的是: 为了加快查找节点的前驱和后继。
 10  *
 11  * 对二叉树的线索化就是对二叉树进行一次遍历,在遍历的过程中
 12  * 检测节点的左右指针是否为空,如果是空,则将他们改为指向前
 13  * 驱和后继节点的线索。
 14  * */
 15 #include<stdio.h>
 16 #include<stdlib.h>
 17 
 18 #define OK 1
 19 #define ERROR 0
 20 
 21 typedef char ElemType;
 22 typedef int Status;
 23 
 24 /* 定义枚举类型,其值只能是Link和Thread
 25  * Link表示的该指针指示的是孩子
 26  * Thread表示的是还指针指示的是前驱或者是后缀
 27  * */
 28 typedef enum {
 29     Link,Thread
 30 }PointerTag;
 31 
 32 typedef struct ThrBiTrNode{
 33     ElemType data;
 34     struct ThrBiTrNode *lchild, *rchild;
 35     PointerTag rTag, lTag;
 36 }ThrBiTrNode, *ThrBiTree;
 37 
 38 ThrBiTree Pre;
 39 
 40 Status InitThreadBinaryTree(ThrBiTree* T){
 41     *T = NULL;
 42     return OK;
 43 }
 44 //先序建立二叉树,lchild和rchild都是指示做孩子和右孩子,所以lTag和rTag为Link
 45 Status ThreadBinaryTree_PreOrderInput(ThrBiTree* T){
 46     ElemType c;
 47     scanf("%c", &c);
 48     if( ' ' == c ){
 49         *T = NULL;
 50     }
 51     else{
 52         *T = (ThrBiTrNode*)malloc(sizeof(ThrBiTrNode));
 53         if( !*T ){
 54             return ERROR;
 55         }
 56         (*T)->data = c;
 57         (*T)->lTag = Link;
 58         (*T)->rTag = Link;
 59         ThreadBinaryTree_PreOrderInput(&(*T)->lchild);
 60         ThreadBinaryTree_PreOrderInput(&(*T)->rchild);
 61     }
 62     return OK;
 63 }
 64 //<<中序遍历>>对二叉树进行<<线索化>>,但是没有提供Pre的初始值,只是给出了
 65 //中间的过程,递归的思想和思考方式。
 66 //1  线索化左子树
 67 //2  对双亲节点处理//递归中的base
 68 //3  线索化右子树
 69 Status InOrderThread(ThrBiTree T){
 70     if( T != NULL ){
 71         InOrderThread(T->lchild);        //线索化左子树
 72         
 73         //对双亲节点进行线索化处理
 74         if( T->lchild == NULL ){    //如果左孩子为空,则将lchild作为索引
 75                         //Pre指向刚刚访问的节点
 76             T->lTag = Thread;
 77             T->lchild = Pre;
 78         }
 79         if( Pre->rchild == NULL ){    //直到现在才知道Pre的后缀是T,所以
 80                         //要对Pre进行设置,如果Pre的rchild为空
 81                         //则将Pre的rchild设置为后缀,指向T
 82             Pre->rTag = Thread;
 83             Pre->rchild = T;
 84         }
 85 
 86         Pre = T;            //标记当前的节点称为刚刚访问过的节点
 87                         //Pre最后会指向树的中序遍历的最后的
 88                         //一个节点
 89 
 90         InOrderThread(T->rchild);    //线索化右子树
 91     }
 92     return OK;
 93 }
 94 //创建中序线索二叉树,为上个函数提供Pre
 95 Status CreateInOrderThreadBinaryTree(ThrBiTree T, ThrBiTree* headOfTree){
 96     *headOfTree = (ThrBiTrNode*)malloc(sizeof(struct ThrBiTrNode));
 97     if( !headOfTree )
 98         return ERROR;
 99     (*headOfTree)->lTag = Link;        //将要指向T
100     (*headOfTree)->rTag = Thread;        //将头节点的rchild用于索引
101     (*headOfTree)->rchild = *headOfTree;       //指向自身
102     if( T == NULL ){
103         (*headOfTree)->lchild = *headOfTree;    //若T为空树,则头节点的lchild
104                             //指向自身
105     }
106     else{
107         (*headOfTree)->lchild = T;
108         Pre = *headOfTree;            //赋值了全局变量Pre
109         InOrderThread(T);                //中序线索化
110         //printf("\n%c\n",Pre->data);
111                         //执行完InOrderThread之后Pre指向最后
112                         //一个节点
113         Pre->rTag = Thread;        
114         Pre->rchild = *headOfTree;
115         //(*headOfTree)->rchild = Pre;
116     }
117     return OK;
118 }
119 //对中序线索化后的线索二叉树使用<<非递归>>的代码进行中序遍历
120 //并且原来的递归形式的代码在这里是不再可以进行遍历。
121 //    如果二叉树没有被线索化,也是使用<<非递归>>的代码进行遍
122 //    历的,但是那就需要借助于<<栈>>,但是在线索化之后,对线索
123 //    化的二叉树进行<<非递归>>的遍历就不再需要栈的辅助。
124 Status visit(ElemType c){
125     printf("%c ", c);
126     return OK;
127 }
128 Status InOrderTeaverse_NoRecursion(ThrBiTree T, ThrBiTree headOfTree){
129 //headOfTree是T的头节点的指针,headOfTree->lchild = T;
130     while( T != headOfTree ){
131         while( T->lTag == Link ){    //找到树(子树)的最左节点
132                         //用while接替if//
133                         //用if理解while//
134             T = T->lchild;
135         }                
136         visit(T->data);
137 
138         while( T->rTag == Thread && T->rchild != headOfTree){
139                         //这个while和下面的T=T->rchild
140                         //可用ifelse语句理解。
141                         //if(rchild是线索 && 不是最后一个节点) 
142                         //else(rchild不是线索)-->走到右孩子
143                         //也就是代码T=T->rchild
144             T = T->rchild;
145             visit(T->data);
146         }
147         T = T->rchild;
148     }
149     return OK;
150 }
151 //求中序线索二叉树中中序序列下的第一个节点
152 ThrBiTrNode* SeekFirstNode_InOrderThrBiTree(ThrBiTree T){
153     if( T != NULL ){
154         while( T->lTag == Link ){
155             T = T->lchild;
156         }
157         return T;
158     }
159     return ERROR;
160 }
161 //求中序线索二叉树中节点P在中序序列下的下一个节点
162 ThrBiTrNode* GetNextNode(ThrBiTrNode* CurrentP){
163     if( CurrentP->rTag == Link ){    //有右孩子的时候,那么下一个就是以
164                     //右孩子为root的树的最左下角元素。
165                     //即seekFirstNode的返回值。
166         return SeekFirstNode_InOrderThrBiTree(CurrentP->rchild);
167     }
168     else{                //没有右孩子,则rchild指向后缀
169         return CurrentP->rchild;
170     }
171 }
172 //使用上面两个函数,SeekFirstNode_InOrderThrBiTree和GetNextNode来实现对
173 //中序先做二叉树的遍历
174 Status InOrderTraverse_NoRecursion_Method(ThrBiTree T, ThrBiTree head){
175     for( T = SeekFirstNode_InOrderThrBiTree(T) ; T != head ; T = GetNextNode(T) )
176         visit(T->data);
177     return OK;
178 }
179 
180 //test
181 /* ShowThread函数的目的是想在将T中序线索化之后,使用函数InOrderTraverse
182  * 函数中序遍历,输出一下节点中的信息以检验线索化,但是失败。原因是:在
183  * 线索化之后,空指针域都被应用,所有InOrderTraverse函数中的if( T )是满
184  * 足不了的,故失败。
185 Status ShowThread(ThrBiTree C){
186     printf("%d %d %d %d\n",(C->lchild)->data,(C->rchild)->data,C->lTag,C->rTag);
187     printf("%d %d\n",C->lTag,C->rTag);
188     return OK;
189  * */
190 
191 //中序遍历二叉树
192 Status InOrderTraverse(ThrBiTree T){
193     if( T ){
194         InOrderTraverse(T->lchild);
195         visit(T->data);
196         InOrderTraverse(T->rchild);
197     }
198     return OK;
199 }
200 int main(){
201     ThrBiTree T,R,Head = NULL;
202     InitThreadBinaryTree(&T);
203 
204     printf("Please Input Binary Tree By PreOrder\n    ");
205     ThreadBinaryTree_PreOrderInput(&T);
206 
207     printf("    InOrder Traverse before Thread with Recursion\n");
208     InOrderTraverse(T);
209     printf("\n");
210 
211     CreateInOrderThreadBinaryTree(T,&Head);
212     printf("    InOrder Traverse after Thread with no-Recursion\n");
213     InOrderTeaverse_NoRecursion(T,Head);
214     printf("\n");
215 
216     printf("The root is %c \n", T->data);    //不能够通过指针形参的值改变指针实参的值
217                         //或者说,对指针形参的改变不会作用到指针
218                         //实参上。
219 
220     ThrBiTrNode *firstOfInOrder = NULL,*secondOfInOrder = NULL;
221     if( SeekFirstNode_InOrderThrBiTree(T) != ERROR ){
222         firstOfInOrder = SeekFirstNode_InOrderThrBiTree(T);
223         printf("the value of First Node of InOrderThreadBinaryTree is %c\n", firstOfInOrder->data);
224     }
225     secondOfInOrder = GetNextNode(firstOfInOrder);
226     printf("the value of Node after D is: %c \n", secondOfInOrder->data);
227     secondOfInOrder = GetNextNode(secondOfInOrder);
228     printf("the value of Node after B is: %c \n", secondOfInOrder->data);
229     secondOfInOrder = GetNextNode(secondOfInOrder);
230     printf("the value of Node after E is: %c \n", secondOfInOrder->data);
231     secondOfInOrder = GetNextNode(secondOfInOrder);
232     printf("the value of Node after A is: %c \n", secondOfInOrder->data);
233     secondOfInOrder = GetNextNode(secondOfInOrder);
234     printf("the value of Node after C is: %c \n", secondOfInOrder->data);
235     secondOfInOrder = GetNextNode(secondOfInOrder);
236     printf("the value of Node after G is: %c \n", secondOfInOrder->data);
237     secondOfInOrder = GetNextNode(secondOfInOrder);
238     printf("the value of Node after root is: %c \n", secondOfInOrder->data);
239 
240     printf("    InOrder Traverse after Thread with no-Recursion Method_2\n");
241     InOrderTraverse_NoRecursion_Method(T,Head);
242 
243     return 0;
244 }

 

posted @ 2016-03-06 21:36  robin_X  阅读(506)  评论(0编辑  收藏  举报