有一棵二叉樹,以下圖所示:node
其中 #
表示空結點。web
先序遍歷:A B D E G C Fsvg
問題:怎麼獲得從根結點到任意結點的路徑呢?函數
示例:輸入 G
,怎麼獲得從結點 A
到結點 G
的路徑呢?優化
很明顯,咱們一眼就能看出來路徑是 A B E G。如何經過程序獲得這條路徑就是咱們接下來須要作的。spa
定義二叉樹的 鏈式存儲結構 以下:.net
typedef struct BiTNode { char data; struct BiTNode* lchild, * rchild; }BiTNode, * BiTree;// 二叉樹結點的存儲結構
二叉樹的遍歷有三種方式:即先序遍歷,中序遍歷,後序遍歷。code
先序遍歷是先訪問結點再遞歸子樹。咱們只須要訪問到目標結點的時候就知道了路徑就能夠結束遞歸,所以正好符合要求。另外兩個也能夠獲得路徑,可是還要先訪問子樹,顯然是不必的。xml
先序遍歷能夠經過遞歸實現,咱們只須要加個容器來保存路徑便可。棧 正好知足要求。因爲不知道路徑的長度,所以採用 鏈棧 來實現。blog
鏈棧 結構以下:
typedef struct StackNode { char data; struct StackNode* next; }StackNode, * Stack;// 鏈棧
/************************************************************************* 實現功能: 輸出從根結點到指定結點的路徑 編譯環境: Visual Studio 2019 更新日期: 2019年10月10日15:16:28 更新內容: 增長清空二叉樹和棧的函數 優化if判斷條件 博客連接: https://blog.csdn.net/pfdvnah/article/details/102387839 做者: wowpH *************************************************************************/ #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h>// exit,malloc,free頭文件 #define EMPTY_NODE '#' #define TRUE 1 #define FALSE 0 #define STACK_EMPTY TRUE #define STACK_NOT_EMPTY FALSE #define FOUND TRUE #define NOT_FOUND FALSE typedef struct BiTNode { char data; struct BiTNode* lchild, * rchild; }BiTNode, * BiTree;// 二叉鏈表 typedef struct StackNode { char data; struct StackNode* next; }StackNode, * Stack;// 鏈棧 // 建立二叉樹結點,返回建立的二叉樹結點 BiTree createBiTNode(); // 建立二叉樹,返回根結點 BiTree createBiTree(); // 初始化二叉樹,返回根結點 BiTree initBiTree(); // 清空二叉樹 void clearBiTree(BiTree T); // 建立棧結點,返回建立的棧結點 Stack createStackNode(); // 初始化棧,返回棧的頭結點 Stack initStack(); // 棧是否初始化 int isStackExist(Stack S); // 棧是否爲空 int isStackEmpty(Stack S); // 入棧 char push(Stack S, char data); // 出棧 char pop(Stack S); // 查看棧頂元素 char peek(Stack S); // 清空棧 void clearStack(Stack S); // 尋找路徑,返回是否找到目標結點 int searchPath(BiTree T, Stack S); // 是否找到目標結點 int isFindTargetNode(Stack S); // 顯示路徑 void showPath(Stack S); // 輸出路徑 void outputPath(Stack S); // 輸出程序提示信息 void outputTips(); int main() { outputTips();// 輸出程序提示信息 BiTree tree = initBiTree(); Stack stack = initStack();// 頭結點存儲目標結點信息 searchPath(tree, stack);// 尋找路徑 showPath(stack);// 輸出路徑信息 clearBiTree(tree);// 清空二叉樹 clearStack(stack);// 清空棧 return 0; } /******************************** 二叉樹 ********************************/ // 建立二叉樹結點 BiTree createBiTNode() { BiTree newNode = (BiTree)malloc(sizeof(BiTNode)); if (newNode == NULL) { printf("錯誤(%d):建立二叉樹結點錯誤!\n", __LINE__); exit(0); } newNode->lchild = NULL; newNode->rchild = NULL; return newNode; } // 建立二叉樹 BiTree createBiTree() { char ch = getchar(); if (ch != '\n' && ch != EMPTY_NODE) { BiTree T = createBiTNode(); T->data = ch; T->lchild = createBiTree();// 左子樹 T->rchild = createBiTree();// 右子樹 return T; } return NULL; } // 初始化二叉樹 BiTree initBiTree() { printf("輸入二叉樹:"); BiTree tree = createBiTree(); char enter = getchar(); return tree; } // 清空二叉樹 void clearBiTree(BiTree T) { if (T != NULL) { clearBiTree(T->lchild); clearBiTree(T->rchild); free(T); } } /********************************** 棧 **********************************/ // 建立棧結點 Stack createStackNode() { Stack newNode = (Stack)malloc(sizeof(StackNode)); if (newNode == NULL) { printf("錯誤(%d):建立棧結點錯誤!\n", __LINE__); exit(0); } newNode->next = NULL; return newNode; } // 初始化棧,並返回頭結點 Stack initStack() { printf("輸入指定結點:"); char targetNode = getchar(); Stack stack = createStackNode();// 頭結點存儲目標結點數據 stack->data = targetNode; return stack; } // 棧頭結點是否存在 int isStackExist(Stack S) { if (S == NULL) { printf("錯誤(%d):棧的頭結點未初始化!\n", __LINE__); exit(0); } return TRUE; } // 棧是否爲空 int isStackEmpty(Stack S) { if (isStackExist(S) == FALSE) { return STACK_EMPTY; } if (S->next == NULL) { return STACK_EMPTY; } return STACK_NOT_EMPTY; } // 入棧,data是要入棧的結點的數據 char push(Stack S, char data) { if (isStackExist(S) == TRUE) { Stack node = createStackNode(); node->data = data; node->next = S->next; S->next = node; } return data; } // 出棧,返回棧頂結點的數據 char pop(Stack S) { char ret = STACK_EMPTY; if (isStackEmpty(S) == STACK_NOT_EMPTY) { Stack delete = S->next; S->next = delete->next; ret = delete->data; free(delete); } return ret; } // 查看棧頂元素 char peek(Stack S) { return isStackEmpty(S) == STACK_EMPTY ? STACK_EMPTY : S->next->data; } // 清空棧 void clearStack(Stack S) { while (isStackEmpty(S) == STACK_NOT_EMPTY) { pop(S); } free(S); } /********************************* 路徑 *********************************/ // 尋找路徑 int searchPath(BiTree T, Stack S) { if (isFindTargetNode(S) == FOUND) { return FOUND; } if (T == NULL) {// 空樹 return NOT_FOUND; } push(S, T->data); // 查找子樹 if (searchPath(T->lchild, S) == FOUND) { return FOUND; } if (searchPath(T->rchild, S) == FOUND) { return FOUND; } pop(S); return NOT_FOUND; } // 是否找到目標結點 int isFindTargetNode(Stack S) { if (isStackEmpty(S) == STACK_NOT_EMPTY && peek(S) == S->data) { return FOUND; } return NOT_FOUND; } // 輸出路徑,遞歸 void outputPath(Stack S) { if (isStackEmpty(S) == STACK_NOT_EMPTY) { outputPath(S->next); if (isStackEmpty(S->next) == STACK_NOT_EMPTY) { printf(" "); } printf("%c", S->next->data); } } // 顯示路徑 void showPath(Stack S) { if (isFindTargetNode(S) == FOUND) { printf("路徑:"); outputPath(S); printf("\n"); } else { printf("未找到結點'%c'\n", S->data); } } // 輸出提示 void outputTips() { printf("一、先序輸入二叉樹\n"); printf("二、空結點用'%c'表示\n", EMPTY_NODE); printf("三、Enter表示輸入結束\n"); printf("四、字符個數必須正確\n"); } /************************************************************************* 一、先序輸入二叉樹 二、空結點用'#'表示 三、Enter表示輸入結束 四、字符個數必須正確 示例1: 輸入二叉樹:ABD##EG###CF### 輸入指定結點:G 路徑:A B E G 示例2: 輸入二叉樹:124##56##7##3## 輸入指定結點:7 路徑:1 2 5 7 *************************************************************************/