线索二叉树及若干操作
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 }