二叉樹的操作--C語言實現
阿新 • • 發佈:2019-02-10
div break 叠代 二叉樹 node 若是 postorder 元素 初始化
樹是一種比較復雜的數據結構,它的操作也比較多。常用的有二叉樹的創建,遍歷,線索化,線索化二叉樹的遍歷,這些操作又可以分為前序,中序和後序。其中,二叉樹的操作有遞歸與叠代兩種方式,鑒於我個人的習慣,在這裏我是使用遞歸來操作的,另外,層序遍歷需要借助隊列來實現。代碼親測,可執行。
1 #include<stdio.h>
2 #include<malloc.h>
3 typedef int ElemType; //數據類型
4
5 typedef struct BiTreeNode //二叉樹結構體
6 {
7 ElemType date; //結點數據
8 struct BiTreeNode *lChild; //左指針
9 int lFlag; //左標記(==0時,左指針存儲左孩子結點;==1時,左指針存儲前驅結點)
10 struct BiTreeNode *rChild; //右指針
11 int rFlag; //右標記(==0時,右指針存儲右孩子結點;==1時,右指針存儲後繼結點)
12 }*BiTree;
13 BiTree pre;
14
15 typedef struct QNode //結點結構體
16 {
17 BiTree date; //結點數據
18 struct QNode *next; //結點指針
19 }*LinkQuePtr; //結點名
20
21 typedef struct //鏈隊結構體
22 {
23 LinkQuePtr front; //隊頭結點
24 LinkQuePtr rear; //隊尾結點
25 }LinkQue; //隊名
26
27 LinkQuePtr head = (LinkQuePtr)malloc(sizeof(QNode)); //頭結點
28
29 /*鏈隊的入隊操作*/
30 int EnQueue(LinkQue *Q, BiTree e)
31 {
32 LinkQuePtr s = (LinkQuePtr)malloc(sizeof(QNode)); //申請新結點空間
33 if(!s)
34 return 0;
35 s->date = e; //新結點的數據等於e
36 s->next = NULL; //新結點的指針指向空
37 Q->rear->next = s; //原隊尾結點的指針指向新結點
38 Q->rear = s; //隊尾指針指向新結點(使新結點成為隊尾結點)
39 return 1;
40 }
41
42 /*鏈隊的出隊操作*/
43 int DeQueue(LinkQue *Q)
44 {
45 if(Q->front == Q->rear) //判斷隊列是否為空
46 return 0;
47 LinkQuePtr s = (LinkQuePtr)malloc(sizeof(QNode)); //申請結點空間s
48 s = Q->front->next; //s結點等於隊頭結點(頭指針所指向的結點)
49 Q->front->next = s->next; //頭結點的指針指向s結點的下一結點(使s結點的下一結點成為隊頭元素)
50 if(Q->rear == s) //判斷s是否為隊尾元素,若是,說明隊列中僅有一個結點
51 Q->rear = Q->front; //使隊尾結點指向頭結點
52 free(s); //釋放s結點
53 return 1;
54 }
55
56 /*創建二叉樹函數*/
57 void CreatBiTree(BiTree *T)
58 {
59 ElemType e; //結點數據
60 scanf("%d", &e);
61 if(e == -1) //如果輸入為-1,當前結點為空
62 (*T) = NULL;
63 else
64 {
65 (*T) = (BiTree)malloc(sizeof(BiTreeNode)); //申請結點空間
66 (*T)->date = e; //為當前結點賦值
67 printf("請輸入當前結點 %d 的左孩子,若沒有左孩子,請輸入-1\n", e);
68 CreatBiTree(&((*T)->lChild)); //遞歸創建左子樹
69 printf("請輸入當前結點 %d 的右孩子,若沒有右孩子,請輸入-1\n", e);
70 CreatBiTree(&((*T)->rChild)); //遞歸創建右子樹
71 }
72 }
73
74 /*先序遍歷二叉樹*/
75 void PreorderTraversal(BiTree T)
76 {
77 if(T == NULL) //判空
78 return;
79 printf("%d ", T->date); //打印當前結點
80 PreorderTraversal(T->lChild); //遞歸遍歷左子樹
81 PreorderTraversal(T->rChild); //遞歸遍歷右子樹
82 }
83
84 /*中序遍歷二叉樹*/
85 void InorderTraversal(BiTree T)
86 {
87 if(T == NULL) //判空
88 return;
89 InorderTraversal(T->lChild); //遞歸左子樹
90 printf("%d ", T->date); //打印當前結點
91 InorderTraversal(T->rChild); //遞歸右子樹
92 }
93
94 /*後序遍歷二叉樹*/
95 void PostorderTraversal(BiTree T)
96 {
97 if(T == NULL) //判空
98 return;
99 PostorderTraversal(T->lChild); //遞歸左子樹
100 PostorderTraversal(T->rChild); //遞歸右子樹
101 printf("%d ", T->date); //打印當前結點
102 }
103
104 /*層序遍歷二叉樹*/
105 void LevelTraversal(BiTree T)
106 {
107 if(T == NULL) //判空
108 return;
109 LinkQue Q; //創建隊Q
110 Q.front = head; //初始化隊列
111 Q.rear = head;
112 EnQueue(&Q, T); //將根結點入隊
113 while(Q.front != Q.rear) //判斷隊列是否為空
114 {
115 BiTree s = Q.front->next->date; //獲得隊列中第一個結點的數據
116 printf("%d ", s->date); //打印當前結點的數據
117 if(s->lChild) //若該結點有左孩子,將其左孩子入隊
118 EnQueue(&Q, s->lChild);
119 if(s->rChild) //若該結點有右孩子,將其右孩子入隊
120 EnQueue(&Q, s->rChild);
121 DeQueue(&Q); //將隊列中第一個結點出隊
122 }
123 }
124
125 /*計算樹的深度*/
126 int Depth(BiTree T)
127 {
128 if(T == NULL) //如果當前結點為空,返回0
129 return 0;
130 int L = Depth(T->lChild); //遍歷左子樹
131 int R = Depth(T->rChild); //遍歷右子樹
132 if(L > R) //取最大值返回
133 return (L+1);
134 else
135 return (R+1);
136 }
137
138 /*中序遍歷線索化*/
139 void Inorder_Traversal_Cue(BiTree &T)
140 {
141 if(T)
142 {
143 Inorder_Traversal_Cue(T->lChild); //遞歸左子樹
144 if(T->lChild == NULL) //左孩子為空
145 {
146 T->lFlag = 1; //左標記為1
147 T->lChild = pre; //左指針指向前一結點
148 }
149 else
150 {
151 T->lFlag = 0;
152 }
153 if(pre->rChild == NULL) //前一結點的右孩子為空
154 {
155 pre->rFlag = 1; //前一結點的右標記為1
156 pre->rChild = T; //前一結點的右指針指向當前結點
157 }
158 else
159 {
160 T->rFlag = 0;
161 }
162 pre = T; //使當前結點成為前一結點
163 Inorder_Traversal_Cue(T->rChild); //遞歸右子樹
164 }
165 }
166
167 /*添加頭結點,將二叉樹線索化*/
168 BiTree AddHead(BiTree &T)
169 {
170 BiTree head = (BiTree)malloc(sizeof(BiTreeNode)); //申請頭結點
171 head->lFlag = 0; //頭結點左標記為0
172 head->rFlag = 1; //右標記為1
173 if(!T) //若二叉樹為空
174 {
175 head->lChild = head; //左指針回指
176 head->rChild = head; //右指針回指
177 return NULL;
178 }
179 pre = head; //前一結點指向頭結點
180 head->lChild = T; //頭結點的左孩子指向根結點
181 Inorder_Traversal_Cue(T); //中序線索化
182 pre->rChild = head; //為最後一個結點設置右指針指向頭結點
183 pre->rFlag = 1; //右標記為1
184 head->rChild = pre; //頭結點的右指針指向尾結點
185 return head; //返回頭結點
186 }
187
188 /*遍歷線索二叉樹*/
189 void TreeCueTraversal(BiTree T)
190 {
191 BiTree p = T->lChild; //申請結點p指向根結點
192 while(p != T) //根結點不為空
193 {
194 while(p->lFlag == 0) //一直尋找第一個左標記為1的結點
195 p = p->lChild;
196 printf("%d ", p->date); //打印第一個結點
197 while(p->rFlag == 1 && p->rChild != T) //若右標記是1,且右孩子不是頭結點
198 {
199 p = p->rChild; //一直遍歷
200 printf("%d ", p->date);
201 }
202 p = p->rChild; //若右標記為0,p賦值為p的右子樹
203 }
204 printf("\n");
205 }
206
207 void main()
208 {
209 BiTree T; //聲明一個樹變量
210 int dep = 0; //樹深度變量
211
212 while(true)
213 {
214 printf("請選擇對二叉樹的操作:\n");
215 printf("1.創建\n");
216 printf("2.先序遍歷\n");
217 printf("3.中序遍歷\n");
218 printf("4.後序遍歷\n");
219 printf("5.層序遍歷\n");
220 printf("6.獲取深度\n");
221 printf("7.中序線索化\n");
222 printf("8.遍歷線索化二叉樹\n");
223 printf("9.退出\n");
224 int a;
225 scanf("%d", &a);
226 switch(a)
227 {
228 case 1:
229 printf("請輸入根節點:\n");
230 CreatBiTree(&T);
231 break;
232 case 2:
233 PreorderTraversal(T);
234 break;
235 case 3:
236 InorderTraversal(T);
237 break;
238 case 4:
239 PostorderTraversal(T);
240 break;
241 case 5:
242 LevelTraversal(T);
243 break;
244 case 6:
245 dep = Depth(T);
246 printf("樹的深度為 %d\n", dep);
247 break;
248 case 7:
249 T = AddHead(T);
250 break;
251 case 8:
252 TreeCueTraversal(T);
253 break;
254 case 9:
255 return;
256 default:
257 printf("選擇錯誤\n");
258 break;
259 }
260 }
261 }
二叉樹的操作--C語言實現