1. 程式人生 > >資料結構學習筆記-樹

資料結構學習筆記-樹

基本概念:樹是n(n>=0)n(n>=0)結點的有限集

  1. 有且僅有一個特定的稱為根的結點
  2. n>1n>1時,其餘結點可分為m個互不相交的有限集,每個集合都是一棵樹,是根的子樹。

其他概念:

  1. 結點的度:子樹的個數;
  2. 樹的度:樹的節點中最大度
  3. 葉節點(終端結點):度為0的節點;而分支結點是度不為0的結點。
  4. 樹的深度:樹所有結點中最大層次(根節點的層次為1)
  5. 路徑長度:結點個數-1,或者說是分支條數
  6. 兄弟結點是父結點相同的結點
  7. 森林是m(m>=0)m(m>=0)棵互不相交的樹的集合

二叉樹

二叉樹是另一種樹形結構,每個結點至多隻有兩棵子樹,且有左右之分,需要注意的是,從樹的概念衍生來的二叉樹是可以為空樹的。

性質

  1. 在二叉樹的第ii層上至多有2i12^{i-1}個結點(i>=1)
  2. 深度為kk的二叉樹至多有2k12^k-1個結點(k>=1),由此,深度為kk且有2k12^k-1個結點的二叉樹是滿二叉樹;而完全二叉樹是其nn個結點與滿二叉樹的n(n<=k)n(n<=k)個結點編號一致。
  3. 對任何一棵二叉樹T,若葉結點數為n0n_0,度為2的結點數為n2n_2,則n0=n2+
    1n_0=n_2+1
  4. 對於完全二叉樹T,具有n個結點,其深度為log2n+1log_2n+1
  5. 對於有nn個結點的完全二叉樹,i為結點編號,如果i=1i=1ii是二叉樹的根,若i>1i>1則其雙親是i/2i/2(向下取整);另外,如果2i>n2i>nii無左孩子,2i+1>n2i+1>nii無右孩子

儲存結構

  1. 順序儲存,以陣列下標表示結點編號,明顯可以看出,如果樹不為完全二叉樹,則浪費了很多儲存空間
  2. 鏈式儲存 分為資料域和左右指標域,鏈的頭指標指向根節點,還有一種三叉連結串列,多加了一個指向雙親結點的指標。

二叉樹的遍歷和線索二叉樹

遍歷

  1. 前序遍歷 根結點-左子結點-右子結點
  2. 中序遍歷 左子結點-根結點-右子結點
  3. 後序遍歷 左子結點-右子結點-根結點 三種遍歷方式正好對應波蘭式,中綴表示式和逆波蘭式
bool PreOrderTraverse(BinTree T)
{
	if (!T)
		return 1;
	else
	{
		Visit(T->data);
		PreOrderTraverse(T->left);
		PreOrderTraverse(T->right);
	}
	return 1;
}

遍歷演算法的不同之處僅僅為訪問結點的先後關係,其實遞迴執行過程是完全一樣的,仿照遞迴執行狀態中遞迴棧的變化可寫出相應的非遞迴演算法,若棧頂記錄的指標非空,則遍歷左子樹將左指標入棧;若棧頂記錄的指標為空,說明應當返回上一層,若從右子樹返回,不必儲存當前的根指標,直接修改指標即可。

bool InOrderTraverse(BinTree T)
{
	InitStack(s);
	BinTree p=T;
	while(p||!isempty(s))
	{
		if(p)
		{
			Push(s,p);
			p=p->left;
		}
		else
		{
			Pop(s,p);
			if(!Visit(p->data))
				return 0;
			p=p->r;
		}
	}
	return 1;
}

線索二叉樹

二叉連結串列作為儲存結構時,不能找到結點的前驅和後繼資訊,所以,將樹的空鏈域用來存放結點的前驅和後繼資訊。規定:如果結點有左子樹,則lchild域指示其左孩子,否則指示前驅,rchild域指示右孩子,否則指示後繼。為避免混淆,再增加兩個標誌域 這種結點結構組成的二叉連結串列作為二叉樹的儲存結構,叫做線索連結串列,指向前驅和後繼的指標稱為線索,樹也為線索二叉樹

  1. 中序線索二叉樹:樹中所有葉子結點的後繼由右鏈域指出。非葉子結點右鏈指向孩子,但是由中序遍歷可知,其後繼為遍歷該結點右子樹時的最左下端結點;同樣,找前驅時葉子結點左鏈域指向前驅,否則是該結點左子樹的最右下端結點
  2. 後序線索二叉樹:因為根節點在遍歷順序之後,所以根的後繼為空;若為右孩子或者左孩子(但沒有兄弟),則後繼結點就為根結點,若為左孩子且有右子樹,就是遍歷右子樹的第一個結點。