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 }