第五章 樹和二叉樹
樹和二叉樹的定義
1、樹的定義
一種非線性結構。樹是遞歸結構,在樹的定義中又用到了樹的概念。
基本術語:
樹結點:包含一個數據元素及若干指向子樹的分支;
孩子結點:結點的子樹的根稱為該結點的孩子;
雙親結點:B結點是A結點的孩子,則A結點是B結點的雙親;
兄弟結點:同一雙親的孩子結點;
堂兄結點:同一層上結點;
結點層次:根結點的層定義為1;根的孩子為第二層結點,依此類推;
樹的高(深)度:樹中最大的結點層
結點的度:結點子樹的個數
樹的度: 樹中最大的結點度。
葉子結點:也叫終端結點,是度為0的結點;
分枝結點:度不為0的結點(非終端結點);
森林:互不相交的樹集合;
有序樹:子樹有序的樹,如:家族樹;
無序樹:不考慮子樹的順序;
2、樹的基本定義
3、二叉樹的定義
二叉樹
二叉樹可以為空。二叉樹結點的子樹要區分左子樹和右子樹,即使只有一棵子樹也要進行區分,說明它是左子樹,還是右子樹。這是二叉樹與樹的最主要的差別。注意區分:二叉樹、二叉查找樹/二叉排序樹/二叉搜索樹、二叉平衡(查找)樹二叉平衡樹肯定是一顆二叉排序樹。堆不是一顆二叉平衡樹。二叉樹與樹是不同的,二叉樹不等價于分支樹最多為二的有序樹。當一個結點只包含一個子節點時,對于有序樹并無左右孩子之分,而對于二叉樹來說依然有左右孩子之分,所以二叉樹與樹是兩種不同的結構。
1、二叉樹的性質
性質:
在二叉樹的第 i 層上至多有2i-1個結點。
深度為 k 的二叉樹上至多含 2k-1 個結點(k≥1)
對任何一棵二叉樹,若它含有n0個葉子結點、n2個度為 2 的結點,則必存在關系式:n0= n2+1。
具有 n 個結點的完全二叉樹的深度為?log2 n?+1 。
n個結點的二叉樹中,完全二叉樹具有最小的路徑長度。
如果對一棵有n個結點的完全二叉樹的結點按層序編號,則對任一結點i(1<=i<=n),有:
如果i=1,則結點i無雙親,是二叉樹的根;如果i>1,則其雙親的編號是 i/2(整除)。
如果2i>n,無左孩子;否則,其左孩子是結點2i。
如果2i+1>n,則結點i無右孩子;否則,其右孩子是結點2i+1。
2、二叉樹的存儲結構
二叉樹的存儲結構
順序存儲結構:僅僅適用于滿或完全二叉樹,結點之間的層次關系由性質5確定。
二叉鏈表法:每個節點存儲左子樹和右子樹。三叉鏈表:左子樹、右子樹、父節點,總的指針是n+2
在有n個結點的二叉鏈表中,值為非空的鏈域的個數為n-1。在有N個結點的二叉鏈表中必定有2N個鏈域。除根結點外,其余N-1個結點都有一個父結點。所以,一共有N-1個非空鏈域,其余2N-(N-1)=N+1個為空鏈域。
二叉鏈存儲法也叫孩子兄弟法,左指針指向左孩子,右指針指向右兄弟。而中序遍歷的順序是左孩子,根,右孩子。這種遍歷順序與存儲結構不同,因此需要堆棧保存中間結果。而中序遍歷檢索二叉樹時,由于其存儲結構跟遍歷順序相符,因此不需要用堆棧。
遍歷二叉樹和線索二叉樹
1、遍歷二叉樹
遍歷二叉樹:使得每一個結點均被訪問一次,而且僅被訪問一次。非遞歸的遍歷實現要利用棧。
先序遍歷DLR:根節點->左子樹->右子樹
中序遍歷LDR:左子樹->根節點->右子樹。必須要有中序遍歷才能得到一棵二叉樹的正確順序
后續遍歷LRD:左子樹->右子樹->根節點。需要棧的支持。
層次遍歷:用一維數組存儲二叉樹時,總是以層次遍歷的順序存儲結點。層次遍歷應該借助隊列。
2、線索二叉樹
線索二叉樹:對二叉樹所有結點做某種處理可在遍歷過程中實現;檢索(查找)二叉樹某個結點,可通過遍歷實現;如果能將二叉樹線索化,就可以簡化遍歷算法,提高遍歷速度,目的是加快查找結點的前驅或后繼的速度。
如何線索化?以中序遍歷為例,若能將中序序列中每個結點前趨、后繼信息保存起來,以后再遍歷二叉樹時就可以根據所保存的結點前趨、后繼信息對二叉樹進行遍歷。對于二叉樹的線索化,實質上就是遍歷一次二叉樹,只是在遍歷的過程中,檢查當前結點左,右指針域是否為空,若為空,將它們改為指向前驅結點或后繼結點的線索。前驅就是在這一點之前走過的點,不是下一將要去往的點。
加上結點前趨后繼信息(結索)的二叉樹稱為線索二叉樹。n個結點的線索二叉樹上每個結點有2個指針域(指向左孩子和右孩子),總共有2n個指針域;一個n個結點的樹有n-1條邊,那么空指針域= 2n - (n-1) = n + 1,即線索數為n+1。指針域tag為0,存放孩子指針,為1,存放前驅/后繼節點指針。
線索樹下結點x的前驅與后繼查找:設結點x相應的左(右)標志是線索標志,則lchild(rchild)就是前驅(后繼),否則:
LDR–前驅:左子樹中最靠右邊的結點;后繼:右子樹中最靠左邊的結點
LRD–前驅:右子樹的根,若無右子樹,為左子樹跟。后繼:x是根,后繼是空;x是雙親的右孩子、x是雙親的左孩子,但雙親無右孩子,雙親是后繼;x是雙親的左孩子,雙親有右孩子,雙親右子樹中最左的葉子是后繼
DLR–對稱于LRD線索樹—將LRD中所有左右互換,前驅與后繼互換,得到DLR的方法。
為簡化線索鏈表的遍歷算法,仿照線性鏈表,為線索鏈表加上一頭結點,約定:
頭結點的lchild域:存放線索鏈表的根結點指針;
頭結點的rchild域: 中序序列最后一個結點的指針;
中序序列第一結點lchild域指向頭結點;
中序序列最后一個結點的rchild域指向頭結點;
中序遍歷的線索二叉樹以及線索二叉樹鏈表示意圖
一棵左右子樹均不空的二叉樹在前序線索化后,其中空的鏈域的個數是1。前序和后續線索化后空鏈域個數都是1,中序是2。二叉樹在線索化后,仍不能有效求解的問題是前序求前序先驅,后序求后序后繼。
中序遍歷的順序為:左、根、右,所以對于每一非空的線索,左子樹結點的后繼為根結點,右子樹結點的前驅為根結點,再遞歸的執行上面的過程,可得非空線索均指向其祖先結點。在中序線索二叉樹中,每一非空的線索均指向其祖先結點。
在二叉樹上加上結點前趨、后繼線索后,可利用線索對二叉樹進行遍歷,此時,不需棧,也不需遞歸。基本步驟:
p=T->lchild; p指向線索鏈表的根結點;
若線索鏈表非空,循環:
循環,順著p左孩子指針找到最左下結點;訪問之;
若p所指結點的右孩子域為線索,p的右孩子結點即為后繼結點循環: p=p->rchild; 并訪問p所指結點;(在此循環中,順著后繼線索訪問二叉樹中的結點)
一旦線索“中斷”,p所指結點的右孩子域為右孩子指針,p=p->rchild,使 p指向右孩子結點;
樹和二叉樹抽象數據類型定義
樹和森林
1、樹的存儲結構
樹的存儲結構:
雙親表示法
孩子表示法
利用圖表示樹
孩子兄弟表示法(二叉樹表示法):鏈表中每個結點的兩指針域分別指向其第一個孩子結點和下一個兄弟結點
將樹轉化成二叉樹:右子樹一定為空
加線:在兄弟之間加一連線
抹線:對每個結點,除了其左孩子外,去除其與其余孩子之間的關系
旋轉:以樹的根結點為軸心,將整樹順時針轉45°
2、森林與二叉樹的轉換
將各棵樹分別轉換成二叉樹
將每棵樹的根結點用線相連
以第一棵樹根結點為二叉樹的根
3、樹與森林的遍歷
樹與轉換后的二叉樹的關系:轉換后的二叉樹的先序對應樹的先序遍歷;轉換后的二叉樹的中序對應樹的后序遍歷
哈夫曼樹/霍夫曼樹及其應用
1、哈夫曼樹的基本概念
2、哈夫曼樹的構造算法
3、哈夫曼編碼
哈弗曼樹概念:
路徑:從一個祖先結點到子孫結點之間的分支構成這兩個結點間的路徑;
路徑長度:路徑上的分支數目稱為路徑長度;
樹的路徑長度:從根到每個結點的路徑長度之和。
結點的權:根據應用的需要可以給樹的結點賦權值;
結點的帶權路徑長度:從根到該結點的路徑長度與該結點權的乘積;
樹的帶權路徑長度=樹中所有葉子結點的帶權路徑之和;通常記作 WPL=∑wi×li
哈夫曼樹:假設有n個權值(w1, w2, … , wn),構造有n個葉子結點的二叉樹,每個葉子結點有一個 wi作為它的權值。則帶權路徑長度最小的二叉樹稱為哈夫曼樹。最優二叉樹。
前綴碼的定義:在一個字符集中,任何一個字符的編碼都不是另一個字符編碼的前綴。霍夫曼編碼就是前綴碼,可用于快速判斷霍夫曼編碼是否正確。霍夫曼樹是滿二叉樹,若有n個節點,則共有(n+1)/2個碼子
給定n個權值作為n的葉子結點,構造一棵二叉樹,若帶權路徑長度達到最小,稱這樣的二叉樹為最優二叉樹,也稱為霍夫曼樹(Huffman Tree)。霍夫曼樹是帶權路徑長度最短的樹,權值較大的結點離根較近。
假設哈夫曼樹是二叉的話,則度為0的結點個數為N,度為2的結點個數為N-1,則結點總數為2N-1。哈夫曼樹的結點個數必為奇數。
哈夫曼樹不一定是完全二叉樹,但一定是最優二叉樹。
若度為m的哈夫曼樹中,其葉結點個數為n,則非葉結點的個數為[(n-1)/(m-1)]。邊的數目等于度。
第六章 圖
圖的定義和基本術語
1、圖的定義——一種非線性結構。樹是遞歸結構,在樹的定義中又用到了樹的概念。
2、圖的基本術語
3、圖的類型定義
無向圖
回路或環:第一個頂點和最后一個頂點相同的路徑。
簡單回路或簡單環:除第一個頂點和最后一個頂點之外,其余頂點不重復出現的回路
連通:頂點v至v’ 之間有路徑存在
連通圖:無向圖圖 G 的任意兩點之間都是連通的,則稱G是連通圖。
連通分量:極大連通子圖,子圖中包含的頂點個數極大
所有頂點度的和必須為偶數
有向圖:
回路或環:第一個頂點和最后一個頂點相同的路徑。
簡單回路或簡單環:除第一個頂點和最后一個頂點之外,其余頂點不重復出現的回路。
連通:頂點v至v’之間有路徑存在
強連通圖:有向圖G的任意兩點之間都是連通的,則稱G是強連通圖。各個頂點間均可達。
強連通分量:極大連通子圖
有向圖頂點的度是頂點的入度與出度之和。鄰接矩陣中第V行中的1的個數是V的出度
生成樹:極小連通子圖。包含圖的所有n個結點,但只含圖的n-1條邊。在生成樹中添加一條邊之后,必定會形成回路或環。
完全圖:有 n(n-1)/2 條邊的無向圖。其中n是結點個數。必定是連通圖。
有向完全圖:有n(n-1)條邊的有向圖。其中n是結點個數。每兩個頂點之間都有兩條方向相反的邊連接的圖。
一個無向圖 G=(V,E) 是連通的,那么邊的數目大于等于頂點的數目減一:|E|>=|V|-1,而反之不成立。如果 G=(V,E) 是有向圖,那么它是強連通圖的必要條件是邊的數目大于等于頂點的數目:|E|>=|V|,而反之不成立。沒有回路的無向圖是連通的當且僅當它是樹,即等價于:|E|=|V|-1。
圖的存儲結構
圖的存儲形式
鄰接矩陣和加權鄰接矩陣
無權有向圖:出度: i行之和;入度: j列之和。
無權無向圖:i結點的度: i行或i列之和。
加權鄰接矩陣:相連為w,不相連為∞
鄰接表
用頂點數組表、邊(弧)表表示該有向圖或無向圖
頂點數組表:用數組存放所有的頂點。數組大小為圖頂點數n
邊表(邊結點表):每條邊用一個結點進行表示。同一個結點的所有的邊形成它的邊結點單鏈表。
n個頂點的無向圖的鄰接表最多有n(n-1)個邊表結點。有n個頂點的無向圖最多有n*(n-1)/2條邊,此時為完全無向圖,而在鄰接表中每條邊存儲兩次,所以有n*(n-1)個結點
1、鄰接矩陣
2、鄰接表
3、十字鏈表
4、鄰接多重表
圖的遍歷
深度優先搜索利用棧,廣度優先搜索利用隊列
求一條從頂點i到頂點s的簡單路徑–深搜。求兩個頂點之間的一條長度最短的路徑–廣搜。當各邊上的權值均相等時,BFS算法可用來解決單源最短路徑問題。
圖遍歷與回溯
圖搜索->形成搜索樹
窮舉法。
貪心法。多步決策,每步選擇使得構成一個問題的可能解,同時滿足目標函數。
回溯法。根據題意,選取度量標準,然后將可能的選擇方法按度量標準所要求順序排好,每次處理一個量,得到該意義下的最優解的分解處理。
圖
1、深度優先搜索
2、廣度優先搜索
圖的應用
1、生成樹和最小生成樹
每次遍歷一個連通圖將圖的邊分成遍歷所經過的邊和沒有經過的邊兩部分,將遍歷經過的邊同圖的頂點構成一個子圖,該子圖稱為生成樹。因此有DFS生成樹和BFS生成樹。
生成樹是連通圖的極小子圖,有n個頂點的連通圖的生成樹必定有n-1條邊,在生成樹中任意增加一條邊,必定產生回路。若砍去它的一條邊,就會把生成樹變成非連通子圖
最小生成樹:生成樹中邊的權值(代價)之和最小的樹。最小生成樹問題是構造連通網的最小代價生成樹。
Kruskal算法:令最小生成樹集合T初始狀態為空,在有n個頂點的圖中選取代價最小的邊并從圖中刪去。若該邊加到T中有回路則丟棄,否則留在T中;依此類推,直至T中有n-1條邊為止。
Prim算法、Kruskal算法和Dijkstra算法均屬于貪心算法。
Dijkstra算法解決的是帶權重的有向圖上單源最短路徑問題,該算法要求所有邊的權重都為非負值。
Dijkstra算法解決了從某個原點到其余各頂點的最短路徑問題,由循環嵌套可知該算法的時間復雜度為O(N*N)。若要求任一頂點到其余所有頂點的最短路徑,一個比較簡單的方法是對每個頂點當做源點運行一次該算法,等于在原有算法的基礎上,再來一次循環,此時整個算法的復雜度就變成了O(N*N*N)。
Bellman-Ford算法解決的是一般情況下的單源最短路徑問題,在這里,邊的權重可以為負值。該算法返回一個布爾值,以表明是否存在一個從源節點可以到達的權重為負值的環路。如果存在這樣一個環路,算法將告訴我們不存在解決方案。如果沒有這種環路存在,算法將給出最短路徑和它們的權重。
2、最短的路徑
3、拓撲排序
雙連通圖和關節點
若從一個連通圖中刪去任何一個頂點及其相關聯的邊,它仍為一個連通圖的話,則該連通圖被稱為重(雙)連通圖。
若連通圖中的某個頂點和其相關聯的邊被刪去之后,該連通圖被分割成兩個或兩個以上的連通分量,則稱此頂點為關節點。
沒有關節點的連通圖為雙連通圖若生成樹的根結點,有兩個或兩個以上的分支,則此頂點(生成樹的根)必為關節點;
對生成樹上的任意一個非葉“頂點”,若其某棵子樹中的所有“頂點”沒有和其祖先相通的回邊,則該“頂點”必為關節點。
一些定義:
事件的最早發生時間(ve(j)):從源點到j結點的最長的路徑。意味著事件最早能夠發生的時間。
事件的最遲發生時間(vl(j)):不影響工程的如期完工,事件j必須發生的時間。
活動ai由弧
有向無環圖及其應用
拓撲排序。在用鄰接表表示圖時,對有n個頂點和e條弧的有向圖而言時間復雜度為O(n+e)。一個有向圖能被拓撲排序的充要條件就是它是一個有向無環圖。拓撲序列唯一不能唯一確定有向圖。
AOV網(Activity On Vertex):用頂點表示活動,邊表示活動的優先關系的有向圖稱為AOV網。AOV網中不允許有回路,這意味著某項活動以自己為先決條件。
拓撲有序序列:把AOV網絡中各頂點按照它們相互之間的優先關系排列一個線性序列的過程。若vi是vj前驅,則vi一定在vj之前;對于沒有優先關系的點,順序任意。
拓撲排序:對AOV網絡中頂點構造拓撲有序序列的過程。方法:
在有向圖中選一個沒有前驅的頂點且輸出之
從圖中刪除該頂點和所有以它為尾的弧
重復上述兩步,直至全部頂點均已輸出;或者當圖中不存在無前驅的頂點為止(此時說明圖中有環)
采用深度優先搜索或拓撲排序算法可以判斷出一個有向圖中是否有環(回路).深度優先搜索只要在其中記錄下搜索的節點數n,當n大于圖中節點數時退出,并可以得出有回路。若有回路,則拓撲排序訪問不到圖中所有的節點,所以也可以得出回路。廣度優先搜索過程中如果訪問到一個已經訪問過的節點,可能是多個節點指向這個節點,不一定是存在環。
算法描述:
把鄰接表中入度為0的頂點依此進棧
若棧不空,則
棧頂元素vj退棧并輸出;
在鄰接表中查找vj的直接后繼vk,把vk的入度減1;若vk的入度為0則進棧
若棧空時輸出的頂點個數不是n,則有向圖有環;否則,拓撲排序完畢。
AOE網:帶權的有向無環圖,其中頂點表示事件,弧表示活動,權表示活動持續時間。在工程上常用來表示工程進度計劃。
4、關鍵路徑
Java。大家都知道,我們是學Java全棧的,大家就肯定以為我有全套的Java系統教程。沒錯,我是有Java全套系統教程,進扣裙【47】974【9726】所示,今天小編就免費送!~
“我們相信人人都可以成為一個程序員,現在開始,找個師兄,帶你入門,學習的路上不再迷茫。這里是ja+va修真院,初學者轉行到互聯網行業的聚集地