1. 程式人生 > >二叉樹的操作--C語言實現

二叉樹的操作--C語言實現

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語言實現