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


樹是一種比較復雜的數據結構,它的操作也比較多。常用的有二叉樹創建遍歷線索化線索化二叉樹的遍歷,這些操作又可以分為前序中序后序。其中,二叉樹的操作有遞歸迭代兩種方式,鑒於我個人的習慣,在這里我是使用遞歸來操作的,另外,層序遍歷需要借助隊列來實現。代碼親測,可執行。

 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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM