樹的基本知識點
樹的定義
樹的ADT(抽象數據類型)
樹的儲存結構
二叉樹的定義
二叉樹的儲存結構
遍歷二叉樹
二叉樹的建立
二叉樹的ADT
typedef struct BiTNode { ElemType date; //結點的數據域 struct BiTNode *lchild , *rchild; //指向左孩子,右孩子 } BiTNode , *BiTree;
其中 BiTNode T 等價於 BiTNode *T
二叉樹的遍歷
有三種遍歷方式:(V是訪問visist , L是左邊left ,R是右邊right)(先訪問根節點就叫先序,中間訪問根節點就叫中序)
VLR(先序):先訪問根結點,再先序遍歷左子樹,再先序遍歷右子樹(后面有舉例)
LVR(中序):先中序遍歷左子樹,再訪問根節點,再中序遍歷右子樹
LRV(后序):先后序遍歷左子樹,再后序遍歷右子樹,再訪問根節點
遍歷實例舉例:
每進去一個新節點都要操作三個步驟:V或L或R
(1)先序遍歷
void PreOrdeTraverse(BiTree T) { if (T) {//遞歸結束條件,T*為空 visit(T->date); //訪問根節點 PreOrdeTraverse(T->lchild); //先序遍歷左子樹 PreOrdeTraverse(T->rchild); //先序遍歷右子樹 } }
(2)中序遍歷
中序遍歷的方法與先序遍歷一樣,只不過順序有改變,每當來到一個新節點,先看有沒有左子樹,有左子樹,就進去左子樹,沒有就訪問當前結點,之后再去找右子樹,沒有左右子樹或左右子樹結點都訪問了,就回到上一個結點
void InOrdeTraverse(BiTree T) { if (T) { InOrdeTraverse(T->lchild); visit(T->date); InOrdeTraverse(T->rchild); } }
(3)后序遍歷
void PosOrdeTraverse(BiTree T) { if (T) { PosOrdeTraverse(T->lchild); PosOrdeTraverse(T->rchild); visit(T->date); } }
二叉樹的建立
//先序序列創建一顆二叉樹 void CreatBiTree(BiTree *T) { char c; scanf("%c" , &c); if (c == '#') *T = NULL; else { *T = (BiTNode*)malloc(sizeof(BiTNode)); //給結點申請一個空間 (*T)->date = c; CreatBiTree(&((*T)->lchild)); //創建左子樹 CreatBiTree(&((*T)->rchild)); //創建右子樹 } }
這里說明一下,為什么要傳入樹的指針的指針
假如我們要用一個函數去改變一個整型變量 n 的值 ,我們知道必須傳入這個變量n的指針進去這個函數,要不然函數中n的變化影響不了函數外的n值
這里也是一樣,我們要改變左右子樹的地址,讓他們指向一個新的空間,所以要傳入左右子樹地址的地址,才能在函數里改變他們的地址
實例:
以先序序列輸入一棵樹,並用三種遍歷方式打印出這棵樹,並且找到某個字母所在的層數
我們下面這棵樹為例(沒有子樹記作#)(找到大寫字母D的所在層數)
#include<stdio.h> #include<stdlib.h> typedef struct BiTNode { char date; //結點的數據域 struct BiTNode *lchild , *rchild; //指向左孩子和右孩子 }BiTNode , *BiTree ; //先序序列創建一顆二叉樹 void CreatBiTree(BiTree *T) { char c; scanf("%c" , &c); if (c == '#') *T = NULL; else { *T = (BiTNode*)malloc(sizeof(BiTNode)); //給結點申請一個空間 (*T)->date = c; CreatBiTree(&((*T)->lchild)); //創建左子樹 CreatBiTree(&((*T)->rchild)); //創建右子樹 } } //訪問二叉樹結點操作 void visit(char c) { printf("%c",c); } //先序遍歷二叉樹 void PreOrdeTraverse(BiTree T) { if (T) { visit(T->date); PreOrdeTraverse(T->lchild); PreOrdeTraverse(T->rchild); } } //中序遍歷二叉樹 void InOrdeTraverse(BiTree T) { if (T) { InOrdeTraverse(T->lchild); visit(T->date); InOrdeTraverse(T->rchild); } } //后序遍歷二叉樹 void PosOrdeTraverse(BiTree T) { if (T) { PosOrdeTraverse(T->lchild); PosOrdeTraverse(T->rchild); visit(T->date); } } //查找字母D在第幾層 void serch(BiTree T , int leavel) { if (T){ if (T->date == 'D') { printf("D在第%d層!",leavel); } serch(T->lchild , leavel+1); serch(T->rchild , leavel+1); } } int main() { BiTree T; int leavel = 1; printf("請輸入先序創建的二叉樹,以#結束:"); CreatBiTree(&T); printf("正在先序打印二叉樹:"); PreOrdeTraverse(T); putchar('\n'); printf("正在中序打印二叉樹:"); InOrdeTraverse(T); putchar('\n'); printf("正在后序打印二叉樹:"); PosOrdeTraverse(T); putchar('\n'); serch(T , leavel); }
運行結果: