本文的寫做目的在於鞏固本身在數據結構和C語言方面的基礎知識,提高寫代碼的基本功。本文的代碼參考了浙大MOOC數據結構中的演示代碼以及《大話數據結構》中的演示代碼,由於運行沒有結果顯示加上發現本身對C語言指針的理解不到位,因而又參考了另外兩個博主的代碼。很是感謝浙大的何欽銘老師以及兩位博主。
其一參考簡書博主EarthChen
其二參考csdn博主men_wen數據結構
🦄編輯器:VSCode + MicroSoft原生插件;
🐱🐉運行環境: MinGW ;
🐱👤經常使用指令: gcc mian.c -o mian.exe編輯器
這裏咱們直接採用浙大數據結構課程中的代碼。由於這種寫法清晰明瞭,且便於後續擴展。函數
typedef char ElementType;
typedef struct TNode *Position; /* 結構體指針 */
typedef Position BinTree; /* 二叉樹類型 */
struct TNode{ /* 樹結點定義 */
ElementType Data; /* 結點數據 */
BinTree Left; /* 指向左子樹 */
BinTree Right; /* 指向右子樹 */
}TNode;
複製代碼
先看代碼再分析測試
void CreateBinaryTree ( BinTree *T ) {
ElementType ch;
scanf("%c",&ch);
if (ch == '#')
*T = NULL;
else {
*T = (BinTree)malloc(sizeof(TNode));
(*T)->Data = ch;
CreateBinaryTree(&((*T)->Left));
CreateBinaryTree(&((*T)->Right));
}
}
複製代碼
1.解決此函數的形參疑問
咱們知道,二叉樹的類型被咱們定義爲BinTree
,而它的原類型是指向二叉樹結點TNode
的指針。我一開始犯的錯誤是,我認爲直接傳入這裏的指針BinTree
給函數CreateBinaryTree()
就能夠獲得建立的二叉樹。事實上這裏須要傳入指針的指針,即這個結構體指針的地址*BinTree
。 也就是說,咱們事實上傳入的是** TNode
,即結點指針的指針。而採用上面的定義,就至關因而一個降維的過程,咱們能夠少寫一個*。
爲何要傳入結點指針的指針呢?個人理解是,咱們所使用的數據結構二叉樹在基本操做中就依賴於指針,這至關於咱們一開始就在操控指針(好比不修改二叉樹的一些操做——先序中序後序遍歷中,咱們用到了指針),但這些指針是包含在二叉樹這個類型中的,打個比方,就至關於一個沒有取得其地址的普通類型。因此咱們須要修改二叉樹的時候,咱們要考慮取所謂「普通類型」的地址,即咱們要取指針的地址,所以咱們會在CreateBinaryTree()
中傳入結點指針的指針,即** TNode
,又即*Bintree
。
2.對代碼的一些說明
這裏創建的二叉樹,其實是擴展二叉樹,這裏採用先序遍歷的順序依次輸入結點的值(char
類型),用'#'
表明空結點。
例如:建立二叉樹:第一層爲A,第二層爲B、C,第三層爲D、F,D爲B的左孩子,F爲C的右孩子;咱們須要輸入ABD###C#F##
;大數據
3種遞歸實現僅僅是輸出語句順序不一樣。
其實現原理爲
二叉樹的先中後序遍歷中通過的結點路徑是同樣的,可是訪問各結點的時機不一樣,每一個結點都會被通過三次,第一次通過就printf是先序,同理第二次printf是中序,第三次是後序。
1.先序遍歷ui
void PreOrderTraversal ( BinTree BT ) {
if ( BT ) {
printf("%c", BT->Data);
PreOrderTraversal( BT->Left );
PreOrderTraversal( BT->Right );
}
}
複製代碼
2.中序遍歷spa
void InOrderTraversal ( BinTree BT ) {
if ( BT ) {
PreOrderTraversal( BT->Left );
printf("%c", BT->Data);
PreOrderTraversal( BT->Right );
}
}
複製代碼
3.後序遍歷.net
void PostOrderTraversal ( BinTree BT ) {
if ( BT ) {
PostOrderTraversal( BT->Left );
PostOrderTraversal( BT->Right );
printf("%c", BT->Data);
}
}
複製代碼
1.先序遍歷輸出二叉樹葉子結點插件
void PreOrderPrintLeaves ( BinTree BT ) {
if ( BT ) {
if ( !BT->Left && !BT->Right )
printf("%c", BT->Data);
PreOrderPrintLeaves( BT->Left );
PreOrderPrintLeaves( BT->Right );
}
}
複製代碼
2.後序遍歷求二叉樹的高度3d
int PostOrderGetHeight ( BinTree BT) {
int HL, HR, MaxH;
if ( BT ) {
HL = PostOrderGetHeight( BT->Left );
HR = PostOrderGetHeight( BT->Right );
MaxH = ( HL > HR ) ? HL : HR;
return (MaxH + 1);
}
else
return 0;
}
複製代碼
程序結構:
頭文件爲BTree.h,裏面包含上述代碼。主要程序文件爲main.c,包含代碼以下:
#include<stdio.h>
#include<stdlib.h>
#include"BTree.h"
int main() {
BinTree myTree;
printf("Create your Binary Tree:\n");
CreateBinaryTree(&myTree);
printf("\n PreOrder:");
PreOrderTraversal(myTree);
printf("\n InOrder:");
InOrderTraversal(myTree);
printf("\n PostOrder:");
PostOrderTraversal(myTree);
printf("\n Leaves:");
PreOrderPrintLeaves(myTree);
printf("\n");
int high = PostOrderGetHeight(myTree);
printf("The height of the tree: %4d", high);
return 0;
}
複製代碼
測試結果以下:
本文解決了我關於二叉樹建立的疑惑,以前寫鏈表的時候應該也是這個問題,只是當時沒有深刻思考,趨之若鶩地使用了cpp的引用,今天稍微思考了一下,也可能有錯誤的地方,但由於還須要複習別的內容,因此暫時先寫到這裏。寫遞歸實現遍歷和結尾的測試程序只是爲了方便讀者快速運行代碼。後續可能會更新非遞歸實現二叉樹的遍歷。感謝閱讀!