樹和二叉樹

樹和二叉樹

樹定義:

    專業定義【遞歸定義】

如果是一個非空樹,則必須滿足以下兩點:

1、有且僅有一個稱爲根的結點

2、有若干個互不相交的子樹,這些子樹本身也是一棵樹


通俗的定義【非遞歸定義】

1、樹由結點和邊組成

2、沒有父結點的結點稱爲根節點

3、每個結點有且僅有一個父結點但可以有多個子結點

一些專業術語

結點

父結點

子結點

子孫

堂兄弟

深度:

從根節點到葉子節點的層數稱爲深度

葉子結點(終端結點):

沒有子結點的結點

度:

某結點的子樹個數稱爲該結點的度

分類

一般樹

可以有任意棵子樹的樹

二叉樹

每個非葉子節點(非終端結點)的子樹個數最多爲兩個,且子樹位置不可改變的樹

分類:

一般二叉樹

滿二叉樹

每個非葉子節點都有且僅有兩個子樹(左子樹和右子樹)

完全二叉樹

如果只刪除了滿二叉樹最底層最右邊的連續的若干個結點,這樣的二叉樹叫完全二叉樹

森林

N個互不相交的樹的集合

存儲

二叉樹的存儲

連續二叉樹【完全二叉樹】

優點:

查找某個父結點和子結點(也包括判斷有沒有)

缺點:

耗用內存空間過大

鏈式存儲


一般樹的存儲

雙親表示法

即使用數組(這不是傳統意義上的數組,而是利用結構體造出的數組)來實現一般樹的存儲

舉個例子,如下圖所示的二叉樹

雙親表示法的存儲如下圖所示

    最左邊的數字是各個結點元素的下標,左邊這一列是結點數據(其順序不固定),右邊這一列是結點元素的父結點的下標(其中,根結點處爲-1)

    這種方法,求父結點方便,求子結點困難


孩子表示法

還是舉例說明,如下圖所示

同樣是用數組(非傳統)來實現一般樹的存儲,具體格式如下所示

    每個結點的右邊是它的子結點,沒有子結點的爲空

    這種方法,求子結點方便,求父結點困難


雙親孩子表示法

如下圖所示


    前面已經說過,數組元素的位置不固定,最左邊是元素下標,接着是元素,中間是結點元素的父結點下標,最右邊是子結點,相當於把上面兩個合併了

    這種方法,求父結點和子結點都很方便

二叉樹表示法

把一個普通樹轉化成二叉樹來存儲

具體轉化方法

設法保證任意一個結點的

左指針域指向它的第一個孩子

右指針域指向它的下一個兄弟

只要能滿足此條件,就可以把一個普通樹轉化爲二叉樹來存儲

森林的存儲

先把森林轉化爲二叉樹,再存儲二叉樹

二叉樹操作

遍歷(訪問)

所謂先序、中序、後序,是指對根結點的訪問

先序遍歷

先訪問根結點

再先序遍歷左子樹

再先序遍歷右子樹

中序遍歷

先中序遍歷左子樹

再訪問根結點

再中序遍歷右子樹

後序遍歷

先中序遍歷左子樹

再中序遍歷右子樹

再訪問根結點

已知兩種遍歷序列求原始二叉樹

通過先序和中序 或者 中序和後序我們可以

還原出原始的二叉樹

但是通過先序和後序是無法還原出原始的二叉樹的

下面舉例說明(已知先序中序求後序),

先序遍歷爲ABCDEFGH

中序遍歷爲BDCEAFGH

求後序遍歷次序


    由先序次序可知,A爲根節點,則由中序次序可知,A的左邊是它的左子樹,A的右邊是它的右子樹,再由先序次序,可知此二叉樹的左子樹(須清楚左子樹或右子樹也是樹)的根節點爲B,因爲B的左邊沒有結點,所以B沒有左子樹,B的右子樹結點分別爲D、C、E,由由先序次序可知,在B的右子樹中,C爲根節點,再看中序次序,C的左邊是D,右邊是E,所以,D是C的左子樹,E是C的右子樹,最終得到該二叉樹的左子樹如下圖所示

    接下來看A的右子樹,共有3個結點,分別是F、G、H,由先序次序可知,F爲A的右子樹的根結點,由中序次序知,F沒有左子樹,但有一個結點爲G的右子樹,再看先序次序,G有一個結點爲H的右子樹,最後根據中序次序,G沒有左子樹,只是有一個根結點爲H的右子樹,因爲H往後沒有結點,所以G的右子樹即爲一個結點H


綜上,得出原始的二叉樹如下圖所示

最終根據二叉樹結構得該二叉樹的後序遍歷次序爲DECBHGFA


再舉一個例子(已知中序後序求先序)

中序遍歷爲BDCEAFGH

後序遍歷爲DECBHGFA

求先序遍歷


    由後序次序可知,A爲根結點,再由中序次序知BDCE爲A的左子樹,FGH爲A的右子樹,在A的左子樹的各個結點B、D、C、E中,由後序次序知B爲A的左子樹的根結點,再由中序次序知B沒有左子樹,B的右子樹爲DCE,再根據後序次序知C爲B的右子樹的根結點,再根據中序次序,知D和E分別爲C的左子樹和右子樹,此時該二叉樹的左子樹已經得到,如下圖所示


同理在後序中,由HGF次序知F爲A的右子樹的根結點,再由中序次序,知,G爲F的右子樹根結點,H爲G的右子樹根結點,最終得出二叉樹如下圖所示

應用

樹是數據庫中數據組織的一種重要形式

操作系統子父進程的關係本身就是一棵樹

面嚮對象語言中類的繼承關係本身也是一棵樹

哈夫曼樹

下面舉個例子,構造一個鏈式二叉樹,並輸出它的先序、中序和後序的順序輸出,二叉樹如下圖所示:

其先序、中序及後序遍歷的次序爲

先序 ABCDE

中序 BADEC

後序 BEDCA

程序如下:

# include <stdio.h>
# include <malloc.h>

typedef struct BTNode
{
	char data;
	struct BTNode * pLchild; //p是指針 L是左  child是孩子
	struct BTNode * pRchild;
}BT, * PBT;

PBT CreateBTree(void);           //構造一個二叉樹 
void PreTraverseBTree(PBT pT);   //先序 
void InTraverseBTree(PBT pT);    //中序 
void PostTraverseBTree(PBT pT);  //後序 

int main(void)
{
	PBT pT = CreateBTree();
	
	printf("先序遍歷二叉樹:\n");
	PreTraverseBTree(pT);
	printf("\n\n"); 
	printf("中序遍歷二叉樹:\n");
	InTraverseBTree(pT);
	printf("\n\n"); 
	printf("後序序遍歷二叉樹:\n");
	PostTraverseBTree(pT);
	printf("\n\n"); 
	
	return 0;
}

void PreTraverseBTree(PBT pT)
{
	if (NULL != pT)
	{
		printf("%c ", pT->data);
	
		if (NULL != pT->pLchild)
		{
			PreTraverseBTree(pT->pLchild);
		}
		
		if (NULL != pT->pRchild)
		{
				PreTraverseBTree(pT->pRchild);
			//pT->pLchild可以代表整個左子樹
		}	
	}	
}

void InTraverseBTree(PBT pT)
{
	if (NULL != pT)
	{
		if (NULL != pT->pLchild)
		{
			InTraverseBTree(pT->pLchild);
		}
		
		printf("%c ", pT->data);
	
		if (NULL != pT->pRchild)
		{
				InTraverseBTree(pT->pRchild);
			//pT->pLchild可以代表整個左子樹
		}	
	}
}

void PostTraverseBTree(PBT pT)
{
	if (NULL != pT)
	{
		if (NULL != pT->pLchild)
		{
			PostTraverseBTree(pT->pLchild);
		}	
		if (NULL != pT->pRchild)
		{
				PostTraverseBTree(pT->pRchild);
			//pT->pLchild可以代表整個左子樹
		}
		printf("%c ", pT->data);
	}
}

PBT CreateBTree(void)
{
	PBT pA = (PBT)malloc(sizeof(struct BTNode));
	PBT pB = (PBT)malloc(sizeof(struct BTNode));
	PBT pC = (PBT)malloc(sizeof(struct BTNode));
	PBT pD = (PBT)malloc(sizeof(struct BTNode));
	PBT pE = (PBT)malloc(sizeof(struct BTNode));

	pA->data = 'A';
	pB->data = 'B';
	pC->data = 'C';
	pD->data = 'D';
	pE->data = 'E';

	pA->pLchild = pB;
	pA->pRchild = pC;
	pB->pLchild = pB->pRchild = NULL;
	pC->pLchild = pD;
	pC->pRchild = NULL;
	pD->pLchild = NULL;
	pD->pRchild = pE;
	pE->pLchild = pE->pRchild = NULL;

	return pA;
}

輸出結果爲:

【所有代碼均在windows系統下C-Free5.0下運行通過】

(如有錯誤,敬請指正)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章