1. 程式人生 > >二叉樹簡單總結

二叉樹簡單總結

一,二叉樹的定義

二叉樹是一種特殊形式的樹結構,二叉樹的特點是每個節點最多有兩棵子樹。

二叉樹(Binary tree )是這樣的數結構:它或者是空,或者是由一個根節點加上兩棵分別稱為左子樹和右子樹的互不相交的二叉樹組成。顯然這個定義是遞迴形式的。

二叉樹的一般儲存結構採用的是鏈式儲存結構。直觀地講就是將二叉樹的各個結點(根節點,葉子節點等)用連結串列的形式連線在一起。這樣通過特定的演算法就可以對二叉樹中的每個節點進行操作。鏈式儲存的二叉樹結點的記憶體結構如圖:

如圖,二叉樹有三個域,其中lchild 和 rchild 為指標域,用來指向該結點的左孩子和右孩子,data為資料域,用來存放該結點的資料。定義二叉樹的結點:

typedef struct BiTNode
{
    char data; /*結點的資料域*/
    struct BiTNode *lchild,*rchild;/*指向左孩子和右孩子*/
}BiTNode ,*BitTree;

上述程式碼定義了一個二叉樹的結點型別BiTNode ,也就是說二叉樹的每一個結點都屬於BiTNode 型別。另外定義了一個BitTree 型別,它就是指向BiTNode 型別資料(物件)的指標型別 變數宣告 BitTree t

二,二叉樹的遍歷

假設我們已經建立了一個二叉樹,在應用二叉樹結構解決實際問題時,往往要求在二叉樹中找到具有某些特徵的二叉樹結點。或者要求訪問二叉樹的每一個結點。這就需要設計一個演算法,針對二叉樹的結構特徵來訪問二叉樹的每一個結點。這個過程就稱作為 二叉樹的遍歷

二叉樹的定義是一種遞迴的形式,因此可以應用二叉樹的這種遞迴的邏輯結構特性,採用遞迴的方法遍歷這個二叉樹。

從二叉樹的定義來說,二叉樹巨集觀是由3個部分組成的,即根節點,左子樹,右子樹。只要完整地遍歷了這三各部分,就等於遍歷了整棵二叉樹。根節點好訪問,它就是一個節點。關鍵是如何遍歷左子樹和右子樹。可以把左子樹和右子樹看成看成兩棵獨立的二叉樹,因為它們也都是由根節點,左子樹,右子樹3部分組成的。

根據二叉樹遍歷的順序的不同,對二叉樹有3種方案:先序遍歷,中序遍歷,後序遍歷。

1,先序遍歷

(1)訪問根節點,(2)先序遍歷左子樹 (3)先序遍歷右子樹

preoderTraverse(Bitree t)
{
	if (t)
	{
		visit(t->data);/*訪問根節點*/
		preoderTraverse(t->lchild);/*先序遍歷t 的左子樹*/
		preoderTraverse(t->rchild);/*先序遍歷t 的右子樹*/
	}
}

visit()函式的作用是訪問指標 t 指向的結點

2,中序遍歷

(1)中序遍歷左子樹 (2)訪問根節點 (3)中序遍歷右子樹

InoderTraverse(Bitree t)
{
	if (t)
	{
		InoderTraverse(t->lchild);/*中序遍歷t 的左子樹*/
		visit(t->data);/*訪問根節點*/
		InoderTraverse(t->rchild);/*中序遍歷t 的右子樹*/
	}
}

3,後序遍歷

(1)後序遍歷左子樹 (2)後序遍歷右子樹 (3)訪問根節點

PosoderTraverse(Bitree t)
{
	if (t)
	{
		PosoderTraverse(t->lchild);/*中序遍歷t 的左子樹*/
		PosoderTraverse(t->rchild);/*中序遍歷t 的右子樹*/
		visit(t->data);/*訪問根節點*/
	}
}

例題

題目  用先序序列建立一顆如圖的二叉樹,並輸出字元位於二叉樹的層數

參考程式碼

#include<stdio.h>
#include<stdlib.h>
typedef struct BiTNode/*結構體定義*/
{
	char data;
	struct BiTNode *lchild, *rchild;
}BiTNode,*BitTree;
/*建立一個二叉樹*/
void CreateBitTree(BitTree *t)
{
	char c;
	scanf_s("%c", &c);
	if (c == ' ') *t = NULL;
	else
	{
		(*t) = (BiTNode *)malloc(sizeof(BiTNode));/*建立根節點*/
		(*t)->data = c;								/*向根節點輸入資料*/
		CreateBitTree(&(*t)->lchild);				/*遞迴建立一個左子樹*/
		CreateBitTree(&(*t)->rchild);				/*遞迴建立一個右子樹*/
	}
}
/*訪問二叉樹結點,輸出包含D字元結點位於二叉樹中的層數*/
void visit(char c, int level)
{
	if (c == 'D')
		printf("%c is at %dth level of BiTTree\n", c, level);
}
/*遍歷二叉樹*/
void PreOrderTraverse(BitTree t,int level)
{
	if (t)
	{
		visit(t->data, level);
		PreOrderTraverse(t->lchild, level + 1);
		PreOrderTraverse(t->rchild, level + 1);
	}
}
int main()
{
	int level = 1;
	BitTree t = NULL;			/*最開始t指向為空*/
	CreateBitTree(&t);			/*建立二叉樹*/
	PreOrderTraverse(t, level);	/*遍歷二叉樹,找到包含D字元的結點位於二叉樹的層數*/
        getche();
}

函式PreOrderTraverse() 包含兩個引數,一個引數是用來指向二叉樹根節點的指標,另一個引數是一個整數變數level ,它的作用是用來記錄當前遞迴操作的層數,也就是記錄當前遍歷到二叉樹的層數,level作為一個區域性變數每次作為引數傳遞時都要加1,因此遞迴深入自動增1。而一旦遞迴從下一層返回到上一層,上一層的level值任然保持原來的值不變,因為level傳遞僅僅是單向值傳遞,並不是指標傳遞,它在每一層中的區域性值都不會受到下一層任何操作的影響。所以變數就是標記著當前訪問的結點位於該二叉樹中的層數。