考研C語言資料結構-二叉樹(二叉樹的鏈式儲存實現 + 常見題型解法)
阿新 • • 發佈:2022-05-19
二叉樹的結構如圖:
二叉樹的儲存實現:
#include <stdio.h> #include <stdlib.h> // 定義結點資料型別 typedef struct TNode { char data; struct TNode *lChild, *rChild; int weight; // 權值 }TNode, *BiTree; // 初始化二叉樹 void initBiTree(BiTree &T) { TNode *A = (TNode *)malloc(sizeof(TNode)); A->data = 'A'; A->weight = 1; A->lChild = NULL; A->rChild = NULL; TNode *B = (TNode *)malloc(sizeof(TNode)); B->data = 'B'; B->weight = 2; B->lChild = NULL; B->rChild = NULL; A->lChild = B; TNode *C = (TNode *)malloc(sizeof(TNode)); C->data = 'C'; C->weight = 3; C->lChild = NULL; C->rChild = NULL; B->rChild = C; TNode *D = (TNode *)malloc(sizeof(TNode)); D->data = 'D'; D->weight = 4; D->lChild = NULL; D->rChild = NULL; C->lChild = D; TNode *E = (TNode *)malloc(sizeof(TNode)); E->data = 'E'; E->weight = 5; E->lChild = NULL; E->rChild = NULL; A->rChild = E; TNode *F = (TNode *)malloc(sizeof(TNode)); F->data = 'F'; F->weight = 6; F->lChild = NULL; F->rChild = NULL; E->rChild = F; T = A; } // 先序遍歷 void preOrder(BiTree T) { if(T != NULL) { printf("先序遍歷結點值:%c\n", T->data); preOrder(T->lChild); preOrder(T->rChild); } } // 中序遍歷 void inOrder(BiTree T) { if(T != NULL) { inOrder(T->lChild); printf("中序遍歷結點值:%c\n", T->data); inOrder(T->rChild); } } // 後序遍歷 void postOrder(BiTree T) { if(T != NULL) { postOrder(T->lChild); postOrder(T->rChild); printf("後序遍歷結點值:%c\n", T->data); } } // 定義結點資料型別 typedef struct LNode { TNode* data; struct LNode *next; }LNode; // 定義鏈隊資料型別 typedef struct { LNode *front, *rear; }LiQueue; void initLiQueue(LiQueue &Q) { Q.front = Q.rear = (LNode *)malloc(sizeof(LNode)); Q.front->next = NULL; } // 判斷佇列空 bool isEmpty(LiQueue Q) { if(Q.front == Q.rear) return true; return false; } // 入隊操作 void enQueue(LiQueue &Q, TNode* T) { LNode *p = (LNode *)malloc(sizeof(LNode)); p->data = T; p->next = NULL; Q.rear->next = p; Q.rear = p; } // 出隊操作 bool deQueue(LiQueue &Q, TNode* &T) { if(isEmpty(Q)) return false; LNode *p = Q.front->next; T = p->data; Q.front->next = p->next; // 如果出隊元素是佇列的最後一個元素,需要修改尾指標 if(p == Q.rear) Q.rear = Q.front; free(p); return true; } // 層序遍歷 void levelOrder(BiTree T) { LiQueue Q; initLiQueue(Q); // 根節點入隊 enQueue(Q, T); TNode * p = NULL; while(!isEmpty(Q)) { deQueue(Q, p); printf("層序遍歷結點值:%c\n", p->data); if(p->lChild != NULL) enQueue(Q, p->lChild); if(p->rChild != NULL) enQueue(Q, p->rChild); } } // 二叉樹葉子節點的統計 void calculateLeafNodes(BiTree T, int &leafNodes) { // leafNodes 初始值0 if(T != NULL) { calculateLeafNodes(T->lChild, leafNodes); calculateLeafNodes(T->rChild, leafNodes); if(T->lChild == NULL && T->rChild == NULL) leafNodes++; } } // 求二叉樹深度操作 int calculateDepth(BiTree T) { if (T == NULL) return 0; //如果是空樹,深度為0,遞迴結束 else { int leftHeight = calculateDepth(T->lChild); //遞迴計算左子樹的深度記為leftHeight int rightHeight = calculateDepth(T->rChild); //遞迴計算右子樹的深度記為rightHeight if (leftHeight > rightHeight) return (leftHeight + 1); //二叉樹的深度為leftHeight 與rightHeight的較大者加1 else return (rightHeight + 1); } } // 利用先序遍歷計算樹的帶權路徑長度(WPL) void calculateWPL(BiTree T, int deep, int &WPL) {// deep, WPL初始為0 if(T->lChild == NULL && T->rChild == NULL) WPL += deep * T->weight; if(T->lChild != NULL) calculateWPL(T->lChild, deep + 1, WPL); if(T->rChild != NULL) calculateWPL(T->rChild, deep + 1, WPL); } // 求二叉樹根結點至某一結點的路徑序列 // 定義結點資料型別 typedef struct LSNode { TNode * data; // 資料域 struct LSNode *next; // 指標域 }LSNode, *LiStack; // 初始化鏈棧(帶頭結點) void initLiStack(LiStack &S) { S = (LSNode *)malloc(sizeof(LSNode)); S->next = NULL; } // 判斷棧空 bool isEmpty(LiStack S) { if(S->next == NULL) return true; return false; } // 入棧(頭插法LIFO) void push(LiStack &S, TNode * T) { LSNode *p = (LSNode *)malloc(sizeof(LSNode)); p->data = T; p->next = S->next; S->next = p; } // 出棧 bool pop(LiStack &S, TNode * &T) { if(isEmpty(S)) return false; LSNode *p = S->next; T = p->data; S->next = p->next; free(p); return true; } // 求二叉樹根結點至某一結點的路徑序列 void calculateTrack(BiTree T, char ch, LiStack &S, bool &flag) {// flag 初始為false if(T->data == ch) { push(S, T); flag = true; return; } if(T->lChild != NULL && !flag) { calculateTrack(T->lChild, ch, S, flag); if(flag) push(S, T); } if(T->rChild != NULL && !flag) { calculateTrack(T->rChild, ch, S, flag); if(flag) push(S, T); } } int main(void) { BiTree T; initBiTree(T); preOrder(T); printf("\n"); inOrder(T); printf("\n"); postOrder(T); printf("\n"); levelOrder(T); printf("\n"); int leafNodes = 0; calculateLeafNodes(T, leafNodes); printf("二叉樹葉子結點數:%d\n", leafNodes); printf("\n"); int height = calculateDepth(T); printf("二叉樹的深度:%d\n", height); printf("\n"); int WPL = 0; calculateWPL(T, 0, WPL); printf("二叉樹的帶權路徑長度WPL:%d\n", WPL); printf("\n"); LiStack S; initLiStack(S); bool flag = false; calculateTrack(T, 'D', S, flag); TNode * t = NULL; while(!isEmpty(S)) { pop(S, t); printf("從根結點A至'D'的路徑為:%c\n", t->data); } system("pause"); return 0; }