二叉樹(Binary Tree)的創建與遍歷——C語言實現

本文的寫做目的在於鞏固本身在數據結構和C語言方面的基礎知識,提高寫代碼的基本功。本文的代碼參考了浙大MOOC數據結構中的演示代碼以及《大話數據結構》中的演示代碼,由於運行沒有結果顯示加上發現本身對C語言指針的理解不到位,因而又參考了另外兩個博主的代碼。很是感謝浙大的何欽銘老師以及兩位博主。
其一參考簡書博主EarthChen
其二參考csdn博主men_wen數據結構

1、運行環境簡介

🦄編輯器:VSCode + MicroSoft原生插件;
🐱‍🐉運行環境: MinGW ;
🐱‍👤經常使用指令: gcc mian.c -o mian.exe編輯器

2、二叉樹的定義

這裏咱們直接採用浙大數據結構課程中的代碼。由於這種寫法清晰明瞭,且便於後續擴展。函數

typedef char ElementType;

typedef struct TNode *Position; /* 結構體指針 */
typedef Position BinTree; /* 二叉樹類型 */
struct TNode{ /* 樹結點定義 */
    ElementType Data; /* 結點數據 */
    BinTree Left;     /* 指向左子樹 */
    BinTree Right;    /* 指向右子樹 */
}TNode;
複製代碼

3、如何建立一個二叉樹?

先看代碼再分析測試

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##大數據

4、二叉樹的遍歷——遞歸實現

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);
    }
}
複製代碼

5、其餘操做

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;
}
複製代碼

6、測試

程序結構:
頭文件爲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;
}
複製代碼

測試結果以下:

測試

7、結語

本文解決了我關於二叉樹建立的疑惑,以前寫鏈表的時候應該也是這個問題,只是當時沒有深刻思考,趨之若鶩地使用了cpp的引用,今天稍微思考了一下,也可能有錯誤的地方,但由於還須要複習別的內容,因此暫時先寫到這裏。寫遞歸實現遍歷和結尾的測試程序只是爲了方便讀者快速運行代碼。後續可能會更新非遞歸實現二叉樹的遍歷。感謝閱讀!

相關文章
相關標籤/搜索