有一棵二叉樹,如下圖所示:
其中 #
表示空結點。
先序遍歷:A B D E G C F
問題:怎么得到從根結點到任意結點的路徑呢?
示例:輸入 G
,怎么得到從結點 A
到結點 G
的路徑呢?
很明顯,我們一眼就能看出來路徑是 A B E G。如何通過程序得到這條路徑就是我們接下來需要做的。
定義二叉樹的 鏈式存儲結構 如下:
typedef struct BiTNode {
char data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;// 二叉樹結點的存儲結構
二叉樹的遍歷有三種方式:即先序遍歷,中序遍歷,后序遍歷。
先序遍歷是先訪問結點再遞歸子樹。我們只需要訪問到目標結點的時候就知道了路徑就可以結束遞歸,因此正好符合要求。另外兩個也可以得到路徑,但是還要先訪問子樹,顯然是沒必要的。
先序遍歷可以通過遞歸實現,我們只需要加個容器來保存路徑即可。棧 正好滿足要求。由於不知道路徑的長度,因此采用 鏈棧 來實現。
鏈棧 結構如下:
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("1、先序輸入二叉樹\n");
printf("2、空結點用'%c'表示\n", EMPTY_NODE);
printf("3、Enter表示輸入結束\n");
printf("4、字符個數必須正確\n");
}
/************************************************************************* 1、先序輸入二叉樹 2、空結點用'#'表示 3、Enter表示輸入結束 4、字符個數必須正確 示例1: 輸入二叉樹:ABD##EG###CF### 輸入指定結點:G 路徑:A B E G 示例2: 輸入二叉樹:124##56##7##3## 輸入指定結點:7 路徑:1 2 5 7 *************************************************************************/