資料結構:三、樹結構概述
在此文,我們將總結下資料結構中樹結構的主要知識點。
1、樹的定義
樹(Tree)時n(n>=0)個結點的有限集,當n==0時稱為空樹,對於非空樹:
(1)、有且僅有一個根結點;
(2)、除去根結點,其餘結點可分為m(m>0)個互不相交的有限集,其中每個集合本身也是一棵樹,稱為根結點的子樹(SubTree)。(個人認為有一個特例:只有一個根結點的樹,它並沒有子樹,不具備非空樹的第二個定義,但課本里並沒有特別寫出這點)
結點分類
按照所處層次的不同,分為根結點、分支結點、葉結點
結點間的關係
按照所在的相對位置,有“子結點”、“父結點”、“兄弟結點”。
上圖樹結構中,A是他們仨的父結點或雙親結點,反過來說,B、C、D三個結點便是A結點的子結點,BCD處於同一層,互稱為兄弟結點。
結點的度
結點的度是指該結點的子結點個數。上圖中根結點A的度為3,B結點的度為2,所有葉結點的度為0。
樹的度
樹的度是指樹的各個結點的度的最大值。圖中樹的度為3。
樹的深度
從根結點開始為第一層,最大的層次數稱為數的深度
上圖中樹的深度為4。
有序樹和無序樹
普通樹中的結點的左右子樹是可以互換的,稱為無序樹,而若將樹中結點的各子樹看成從左往右是有次序的,不能互換,則稱該樹為有序樹,如二叉樹便是一種有序樹。有序樹中最左邊的子樹的根稱為第一個孩子,最右邊的子樹的根稱為最後一個孩子。樹和森林
森林是m(m>=0)棵互不相交的樹的集合。
ADT Tree{ InitTree(&T);//構造空樹 DestroyTree(&T);//銷燬樹T CreateTree(&T, definition);//根據definition中給出的樹的定義來構造樹 ClearTree(&T);//若樹存在,則將樹T清空為空樹 TreeEmpty(T);//若樹為空樹,返回treu,否則返回false Root(T);//返回T的根結點 Value(T, cur_e);//cur_e是樹T中的一個結點,返回此值 Assign(T, cur_e, value);//給樹T的根結點cur_e賦值為value Parent(T, cur_e);//若cur_e是樹T的非根結點,則返回它的父結點 LeftChild(T, cur_e);//若cur_e是樹的非葉結點,則返回它的最左孩子 RightSibling(T, cur_e);//若cur_e有右兄弟,則返回它的右兄弟否則返回空 InsettChild(&T,p, i, c); //其中p指向樹T的某個結點,i為所指結點p的度數加1,非空樹c與T不相交,操作結果為插入c為樹T中p指向結點的第i棵子樹 DeleteChild(&T, p, i);//其中p指向樹T的某個結點,i為所指結點p的度,操作結果為刪除T中p所指向結點的第i棵子樹 TraverseTree(T);//按某種次序對T的每個結點訪問一次 }
2、二叉樹
二叉樹與樹的主要區別:
(1)、二叉樹每個結點至多隻有兩棵子樹,即不存在度大於2的結點;
(2)、二叉樹的子樹有左右之分,其次序不能任意顛倒。
二叉樹的性質
1)、二叉樹的第i層上至多有2^(i-1)個結點;
2)、深度為k的二叉樹至多有2^k-1個結點;
下面介紹兩種比較特殊的二叉樹:滿二叉樹和完全二叉樹
滿二叉樹:深度為k且含有(2^k)-1個結點的二叉樹。下圖為一棵深度為4的二叉樹。
特點:每一層上的結點數都為最大結點數;可對滿二叉樹進行編號,自上而下,自左至右。
滿二叉樹
完全二叉樹:(課本官方定義)深度為k的,有n個結點的二叉樹,當且僅當其每一個結點都與深度為k的滿二叉樹中編號從1至n的結點一一對應時,稱該樹為完全二叉樹。個人比較庸俗不過比較容易理解的想法:深度為k的二叉樹,除了第k層的結點依次從左往右排列,前面k-1層結點組成滿二叉樹,則稱該二叉樹為完全二叉樹。如下圖為深度為4的完全二叉樹。
特點:1)、葉結點只可能在層次最大的兩層上出現;
2)、具有n個結點的完全二叉樹的深度為:log2n(向下取整)+1
完全二叉樹
在二叉樹的一些應用中,常會用到特殊的二叉樹——哈夫曼樹(即最優二叉樹)、線索二叉樹、平衡二叉樹等等,在之後會有篇專講這些二叉樹的,今天的課到這先告一段落啦。
最後再附上二叉樹的基本操作
ADT BinaryTree{ InitBiTree(&T); //構造空二叉樹T DestroyBiTree(&T);//銷燬二叉樹T CreatBiTree(&T,definition);//按definition構造二叉樹T ClearBiTree(&T);//將二叉樹清為空樹 BiTreeEmpty(T);//判斷T是否為空二叉樹,若是則返回true,不是返回false BiTreeDepth(T);//返回T的深度 Root(T);//返回T的根 Value(T,e);//返回e的值 Assign(T,&e,value);//結點e賦值 Parent(T,e);//若e是T的非根結點,則返回它的雙親,否則返回“空” LeftChild(T,e);//返回e的左孩子,若e無左孩子,則返回“空” RightChild(T,e);//返回e的右孩子,若e無右孩子,則返回“空” LeftSibling(T,e);//返回e的左兄弟,若e無左兄弟,則返回“空” RightSibling(T,e);//返回e的右兄弟,若e無右兄弟,則返回“空” InsertChild(&T,p,LR,c);//插入子樹,根據LR為0或1,插入c為T中p所指結點的左或右子樹。p所指結點的原有左或右子樹則成為c的右子樹 DeleteChild(&T,p,LR);//刪除子樹,根據LR為0或1,刪除T中p所指結點的左或右子樹 PreOrderTraverse(T);//先序遍歷T,對每個結點訪問一次 InOrderTraverse(T);//中序遍歷T,對每個結點訪問一次 PostOrderTraverse(T);//後序遍歷T,對每個結點訪問一次 LevelOrderTraverse(T);//層序遍歷T,對每個結點訪問一次 }