1.樹與二叉樹
結點的度:一個結點的有幾個孩子(孫子不算)
樹的度:所有結點中,其中一個結點最大的度
葉子結點:沒有孩子的結點
分支結點:左右分支的結點
內部結點:夾在中間的結點,既不是葉子和根結點
父結點:作爲父親的結點
子結點:作爲孩子的結點
兄弟結點:同一個父親的結點
層次:樹的層次
2.二叉樹的性質
2.1 分類
滿二叉樹:結點都是滿的的二叉樹
完全二叉樹:結點按順序分佈的,但是沒有滿的二叉樹
非完全二叉樹:結點沒有按順序分佈的二叉樹
3.二叉樹的遍歷
前序遍歷:根節點最先訪問,即根-左-右
中序遍歷:根結點中間訪問,即左-根-右
後序遍歷:根結點最後訪問,即左-右-根
層次遍歷:一層一層訪問
圖上結果:
前:1 ,2 ,4 ,5,7 ,8 ,3, 6
中:4 ,2 ,7 ,8, 5,1 , 3, 6
後:4 ,8, 7, 5 ,2, 6 ,3 ,1
層次:1, 2, 3 ,4 ,5 ,6 ,7 ,8
3.2二叉樹的反向構造
反向構造:就是知道其中兩種遍歷,來構建二叉樹(必須有中序遍歷,否則不能推出)
下圖:先看前序遍歷的A爲根結點,所以中序遍歷中,A的左邊爲左子樹,右邊爲右子樹,依次推下面的
結果:
4.普通樹轉成二叉樹
樹轉二叉樹的兩個個原則:
1.普通樹的孩子結點變成新二叉樹的左子樹結點
2.普通樹的兄弟結點變成新二叉樹的右子樹結點
看起來很抽象,下面用例子分析
如下圖:
普通樹的根結點是1,孩子結點有2, 3 , 4
那麼(根據原則1)先把2拿出來,作爲新二叉樹左子樹結點,而在普通樹中3作爲2的兄弟,所以在新二叉樹中3(根據原則2)只能做2的右子樹,
接下來3有5, 6 ,7三個孩子結點,同理,5作爲新二叉樹的左子樹,而在普通樹中6作爲5的兄弟,所以在新二叉樹中6(根據原則2)只能做5的右子樹,依次類推,得出新的二叉樹的結構
5.查找二叉樹(又稱排序二叉樹)
查找二叉樹:根結點要大於左子樹,小於右子樹
6.最優二叉樹(哈夫曼樹)
樹的路徑長度:結點與結點的路徑距離
權:結點的值
帶權路徑長度:樹的路徑長度*結點的值
樹的帶權路徑長度:葉子結點的帶權路徑長度累加
如下圖(假設結點與結點的路徑距離爲1):
左邊第一棵樹的帶權路徑長度:2*2+4*3+8*3+1*1=41
左邊第二棵樹的帶權路徑長度:4*2+1*3+2*3+8*1=25
怎麼構造哈夫曼樹?
如下圖右邊:
在5,29,7,8,14,23,3,11中找出兩個最小的值即5,3
5,3組成小樹,和爲8,所以8放到原先的數列中,但是8重複了,只能取一個
29,7,8,14,23,11中找出兩個最小的值即7,8,依次類推,得出哈夫曼樹
7.線索二叉樹
線索二叉樹:由於二叉樹的葉子結點或分支結點,有時左右子樹的指針地址是空的,爲了利用資源和快速資源尋找,產生了線索二叉樹
分類:
前序線索二叉樹:先讓二叉樹進行前序遍歷,其中有空指針地址的結點(即結點沒有2個孩子),然後讓該結點的左指針地址指向前一個結點,右指針地址指向後一個結點
中序線索二叉樹:先讓二叉樹進行中序遍歷,其中有空指針地址的結點(即結點沒有2個孩子),然後讓該結點的左指針地址指向前一個結點,右指針地址指向後一個結點
後序線索二叉樹:先讓二叉樹進行後序遍歷,其中有空指針地址的結點(即結點沒有2個孩子),然後讓該結點的左指針地址指向前一個結點,右指針地址指向後一個結點
這麼說,太抽象了,用一個例子分析
如下圖:
左下角的樹(構造前序線索二叉樹)的前序遍歷:A B D E H C F G I,
那麼有空地址的結點有:D E H F G I
依照定義,D的左指針地址指向B,D的右邊指針地址指向E,然後依次類推,得出前序線索二叉樹
8.平衡二叉樹
之前有排序二叉樹,但是不夠平衡,爲了達到更加優化,提出了平衡二叉樹
9.圖
分類:無向圖(沒有方向),有向圖(有方向)
圖與樹的本質區別:圖是有環的,而樹沒有環
9.1圖的存儲
兩種形式:鄰階矩陣,鄰階表
(1)鄰階矩陣:採用一個二維數組存儲,用0和1代表該結點有沒有連線
太抽象了,例子分析
如下圖:
左邊的圖共有5個結點,所以矩陣需要5*5個
看圖的右邊的矩陣分析,
第一行第一列是0,因爲左邊的“圖”中,“1”這個結點沒有與自己連線,
第一行第二列是1,因爲左邊的“圖”中,“1”這個結點沒有與“2”結點連線,
第一行第三列是1,因爲左邊的“圖”中,“1”這個結點沒有與“3”結點連線,
依次類推,得出鄰階矩陣
(2)鄰階表:先用一個數組存儲每個結點,然後其中的每個結點的相鄰結點用鏈表連接起來
太抽象了,例子分析
如下圖:
v1 到 v8 總共8個結點,先用數組存儲起來,圖中紅色方框表示
看左邊的圖,
v1一共有3個相鄰的結點,v2 ,v4, v6,用鏈表連接起來(連接順序無要求)在v1的後面
v2一共有3個相鄰的結點,v3,v5, v4,用鏈表連接起來(連接順序無要求)在v2的後面
依次類推,得出鄰階表
9.2圖的遍歷
廣度優先:一層一層遍歷(類似層次遍歷)
深度優先:一個結點接一個結點訪問,直到不能訪問(類似前序遍歷)
廣度優先(鄰接表存儲)如下圖分析:
首先v0有三個相鄰的結點v4 ,v3 ,v1,所以先訪問v4 ,v3, v1
繼續走,看v4,有三個相鄰的結點v6,v1 ,v0,所以先訪問v6 ,v1(已經訪問過了,不用管), v0(已經訪問過了,不用管)
繼續走,看v3,有兩個相鄰的結點v6,v0,所以先訪問v6 (已經訪問過了,不用管), v0(已經訪問過了,不用管)
繼續走,看v1,有三個相鄰的結點v4,v2 ,v0,所以先訪問v4 (已經訪問過了,不用管),v2, v0(已經訪問過了,不用管)
第一層遍歷完了,繼續第二層
繼續走,看v6,有三個相鄰的結點v3,v4,v7,所以以先訪問v3 (已經訪問過了,不用管), v4(已經訪問過了,不用管),v7
繼續走,看v2,有兩個相鄰的結點v1,v5,所以以先訪問v1 (已經訪問過了,不用管), v5
最後結果:v0, v4 ,v3, v1,v2,v0,v7,v5(其中一種結果)
遍歷完成
深度優先(鄰接表存儲)如下圖分析:
先訪問v0,v4,v6,v7,發現v7後面沒有了,回退一步,
看v6的其他相鄰的結點,所以以先訪問v3,v4(已經訪問過了,不用管),v3後面也沒有了,回退一步,
看v6的其他相鄰的結點,發現全部訪問完了,繼續回退一步,
看v4的其他相鄰的結點,所以以先訪問v0(已經訪問過了,不用管),v1,v6(已經訪問過了,不用管)
v1後面還有,繼續訪問 v2 ,v5,後面沒有了,回退一步,v2其他相鄰的結點已經訪問,繼續回退,v1其他相鄰的結點已經訪問,
繼續回退 ,v4其他相鄰的結點已經訪問,繼續回退 ,v0其他相鄰的結點已經訪問
最後結果:v0, v4 ,v6, v7,v3,v1,v2,v5(其中一種結果)
到此遍歷完成
圖的拓撲排序:
拓撲排序:執行的先後順序,比如,完成某件事,必須要完成前面的事才行
太抽象了,實例分析
如下圖:
0可以開始執行,把兩條線劃掉
接下來,2和3都可以執行,把線劃掉,
接下來執行4(但是4必須等2和3執行完),把線劃掉,
接下來執行3或6,把線劃掉,
接下來執行5或者6
最後執行7
10.圖的最小生成樹
最小生成樹:各個結點的連線,總長度最小,但是不能成環了
10.1 普里姆算法(prime)
核心思想:找出結點,並作爲一個集合(有的稱藍點集或紅點集,意思一樣的)去處理
如下圖分析:
首先在樹中去任意一個結點A(也可以其他結點),然後找出其他結點與A最近的連線,發現A 到B是最近的,距離100
繼續,把A與B看成一個“整體”,看看這個“整體”與那個結點最近,發現A 到E是最近的,距離200
繼續,把A與B,E看成一個“整體”,看看這個“整體”與那個結點最近,發現A 到F是最近的,距離250
依次類推,得出圖的最小生成樹
10.1 克魯斯卡爾算法
核心思想:找出最短的邊(比較簡單)
下圖分析:
首先找出最短的邊:100,所以連接A B
繼續找出最短的邊:200,所以連接A E,所以連接F D
繼續找出最短的邊:250,所以連接A F
繼續找出最短的邊:300,所以連接C D,不能連接B F導致成環,
依次類推,得出圖的最小生成樹
,
11.算法的複雜度
11.1排序
分類:
交換類:冒泡排序,快速排序
插入類:直接插入排序,希爾排序
選擇類:簡單選擇排序,堆排序
歸併排序
基數排序
(1)直接插入排序
核心:在一個已知的序列中,進行比較插入
例子分析:57 ,68 ,59 , 52(要求從小到大排序)
先取第一個57,
然後第二個68,68>57,不處理
然後第三個59,59<68,再繼續比較57,發現59>57,這時可以插入
(2)希爾排序
核心思想:取一個間隔增量進行分組,然後組內用直接插入排序,然後縮小間隔增量,直到爲1,最後用直接插入排序完成
好處:經過組內分組排序之後,整個序列變得有序,大大提高了排序的速度
例子分析:
如下圖:
先取增量(這個增量任意的,只要不大於n就行)爲5,每隔5個爲一組,57和28,68和96,59和33,52和24,72和19,然後每個組進行單獨的直接插入排序,變成
28 ,68,33,24,19,57,96,59,52,72
再取增量爲3,每隔3個爲一組,28,24,96爲一組,68,19,59爲一組,33,57,52爲一組然後每個組進行單獨的直接插入排序,依次類推
最後增量爲1,然後再進行直接插入排序,完成。
(3)簡單選擇排序
核心思想:首先選出最小與第一個交換位置,然後剩餘選出最小與第二個交換位置。。。
(4)堆排序
堆:要滿足完全二叉樹
分類:
小頂堆:父結點比左右子結點小
大頂堆:父結點比左右子結點大
核心思想:從堆頂取出的結點最大(或最小),然後調整堆,再從堆頂取出的結點最大(或最小),從而排序。
非常適合海量數據排名前幾的排序
怎麼構建大頂堆?如下圖分析
比如構建大頂堆
先數列排成完全二叉樹形式
然後非葉子結點(5,3,1,4,這裏有4個非葉子結點)進行比較,
首先5與8調換,然後8與3調換,然後發現下面的3也要與5調換
按照這種方式,依次類推,得出大頂堆
接下來,例子分析
如下圖分析:
假設已經構建好大頂堆,從大頂堆取出80後,需要調整
從最後一個結點取出來放到根結點,然後進行調整,比較左右子樹,直到合適
(5)冒泡排序
核心思想:從最後兩兩交換,得到最小(或最大)的元素放到前面
(6)快速排序
首先選一個基準,任意的,
比如選第一個57爲基準,然後指針最後一個19與基準比較,如果小於基準,交換位置
然後指針跑到第二位68,與基準比較,如果大於基準,交換位置
依次類推,最後基準會跑到中間,然後基準的左邊都是小於基準,右邊都是大於基準的
然後基準的左邊繼續剛剛的排序,直到完成
然後基準的右邊繼續剛剛的排序,直到完成
(7)歸併排序
分析兩個小組合並(其他也一樣):
57和52比較,52小,52複製到新的數組去,然後右邊的指針加1,
然後57和59比較,57小,57複製到新的數組去,然後左邊的指針加1,
然後68和59比較,59小,59複製到新的數組去,然後右邊的指針加1,後面沒有,排序完成
最後:52,57,59,68