堆是完全二叉樹
子樹是不相交的
度 節點擁有子樹的個數
滿二叉樹:
每個節點上都有子節點(除了葉子節點)
完全二叉樹:
葉子結點在倒數第一層和第二層,最下層的葉子結點集中在樹的左部
,在右邊的話,左子樹不能為空
二叉搜索樹:
左邊子節點小於父節點,右邊子節點大於父節點
堆:
也叫隊列,在堆尾插入,在堆頭取出
最大堆:
最上邊比下邊的兩個數都大,所有的節點都滿足這個規則

最小堆:
父節點一定比兩個子節點要小
特征:
堆起始坐標從1開始
如果用列表表示一個堆:
堆的坐標從1開始算
當前坐標是i
左節點坐標是2i
右節點坐標是2i+1
父節點坐標是i//2 取整
如果想找到最后一個帶有子節點的節點坐標:
堆的長度//2
[0,1,2,3,4,5]
[0,1,2,3,4,5,6,7]
1
2 2*1+1=3
2*2 2*2+1=5
0
1 2
3 4 5 6
堆的坐標從0開始算
當前坐標是i
左節點坐標是2i+1
右節點坐標是2i+2
父節點坐標是(i-1)//2 取整
如果想找到最后一個帶有子節點的節點:
(堆的長度-1)//2
父節點的位置是K//2,它的左節點是2k,右節點是2k+1
在堆里插入一個元素:上濾
最大堆:
所有的父節點必須大於它的兩個子節點
如果將新元素增加到堆的末尾:加一個88
要保證最大堆的規則,新元素和父節點調整交換的操作叫做上濾

只要插入的節點比父節點小,就不做交換了,不交換那么排序就停止了
當發生了新插入節點和父節點沒有交換的情況,那么上濾過程及結束了
刪除根元素:下濾
刪除堆頂元素,兩個子元素比較,大的上去,空出的元素的兩個子元素繼續比較,大的再上去。。。

最小堆:
所有的父節點必須小於它的兩個子節點
堆排序:
算法:一個列表是待排序的
構造最大(小)堆:
最大堆的規則:堆中所有的父節點必須都大於它的子節點
最大堆中的最大值是:根
最小堆的規則:堆中所有的父節點必須都小於它的子節點
最小堆中最小值是:根
排序:
假設使用最大堆
1生成一個空列表存儲排序后的結果
2將待排序的list構造成最大堆
3將最大堆的根元素放到空列表中,將剩余的元素通過下濾重新構造最大堆
4然后重復3的步驟,知道所有的元素都當過一次最大堆
拆解過程:
列表中的元素是排好序的,並且是降序的
result =[]
5
3 4
1 2
第一次:result:[5]
3 4
1 2
剩下的元素要構造新的最大堆
4
3
1 2
第二次:result:[5,4]
3
1 2
再次構造最大堆
第三次:result:[5,4,3]
1 2
再次構造最大堆
2
1
第三次:result:[5,4,3 ,2]
1
再次構造最大堆
第四次:result:[5,4,3,2,1]
完成了所有元素當過一次堆的根元素條件,結束堆排序
構造最大堆的時候,如何構造:
從堆的最下層開始構造,每構造一次進行一次上濾
將最大值向上傳遞。
下濾是從堆頂取值
代碼:
# encoding=utf-8
#左葉子、右葉子和父節點,三個元素,找到最大的一個
def maxHeap(heap,heapSize,i):#構造最大堆
#參數heap為一個list,heapsize是指定這個list要操作的長度
#i為某個節點,假設我們傳遞的是列表的倒數第三個元素
#它的左節點坐標:2i
#那么它的右節點坐標:2i + 1
#它的父節點:i/2
left = 2*i +1
right = 2*i +2
larger = i#當前節點的值
#通過2次if的比較,將left、right和larger三者的最大值找到
#然后將最大值所在的坐標賦值給larger
if left < heapSize and heap[larger] < heap[left]:
larger = left
if right < heapSize and heap[larger] < heap[right]:
larger = right
#以上兩步是把三個節點中,最大的值的坐標給了larger
#如果lager的值不是i,說明i的值需要和最大值進行交換
#因為i的坐標是最大堆的堆頂,所以必須是最大值
#如果不是i最大,則說明左結點,或者右節點最大,交換值
#后,說明下面的堆有可能需要進行調整,所以通過遞歸來
#建立左(右)結點下的最大堆。
#如果最大值就是i,沒有進行交換值,所以不需要進行建立
#左(右)結點下的最大堆,這是因為
#做交換,如果最大值的坐標不是當前節點的坐標,說明更大的是左右節點之一
#就把最大那個和當前節點做一個交換,這樣最大的就跑到上邊去了
if larger != i:
heap[i],heap[larger] = heap[larger],heap[i]
maxHeap(heap,heapSize,larger)#遞歸調用larger是左節點坐標或者右節點坐標,繼續去找下邊的最大值,做交換
#如果發生了larger =i 的情況,則次函數調用結束
#以上步驟完成,堆頂坐標為i坐標的最大子堆建立好了
def buildMaxHeap(heap):
#heap參數是未排序、未建堆的list
heapSize = len(heap)
#堆的長度//2可以找到堆里面的
#最后一個帶有子節點的節點
#循環可以實現從堆的最下層節點開始建堆
#每次建立的堆都是一個最大堆
#簡單來說把所有字段都建成最大堆
#然后組成了最終的最大堆
for i in range((heapSize-1)//2 -1,-1,-1):
maxHeap(heap,heapSize,i)
#(heapSize-1)//2是算出來當前堆中最后一個含有子節點的坐標
'''
5
3 4
2 1 -1
'''
def heapSort(heap):
#先把所有元素先建立一個最大堆
buildMaxHeap(heap)
#將堆中所有的元素都遍歷一遍
#讓每個元素都做一次堆頂
#然后將堆頂的每個元素都換到堆的最后一個節點
for i in range(len(heap)-1,-1,-1):
heap[0],heap[i] = heap[i],heap[0]
#maxheap中的i是列表的長度,這樣可以防止追加到
#堆后面的元素重新被當做最大堆元素進行建隊
maxHeap(heap,i,0)
return heap
#第一次循環的時候,把最大值放到了列表最后面
#把最后一個值(肯定不是最大值)放到了堆頂,然后把不包含最后一個元素的
#剩余元素,重新進行最大堆排序
#第二次循環的時候,把堆頂(次大值)放到列表倒數的第二個位置,然后把不包含最后
#兩個元素的剩余元素,重新進行建立最大堆
#。。。。
#循環結束,那么列表的數據就排好了
if __name__ == '__main__':
heap1 = [3,4,5,6,23,4,1,1,23,45,6678]
print (heap1)
heapSort(heap1)
print (heap1)
算法:
將一個未排序的list,做成最大堆
buildMaxHeap函數通過maxHeap函數構造了最大堆
第一次從最大堆取出的元素和列表的最后一個的元素交換
位置,我們就找到了最大值
剩余的元素,進行新的最大堆建立
第二次從新建的最大堆堆頂取出來最大值,這個值和
列表中的倒數第二個數進行交換,那么第二大的值就找到了,
此時,最大值在列表的最后,第二大值在列表的倒數
第二個元素
第三次。。。。。重復上面的過程
直到所有的元素都被交換過一次位置
剛才有一個地方講解有偏差
maxHeap 這個函數的交換邏輯,應該是既不算上濾,也不算下濾
上濾:新插入元素和父節點比對,發生交換。下濾:左右節點比對后發生交換
maxHeap 這個函數的交換邏輯是三個數找到最大的,和上濾下濾還是有一些區別。
for i in range((heapSize-1)//2,-1,-1):
maxHeap(heap,heapSize,i)
這個循環要理解一下:
這個循環調用,表示從最下層的子樹,開始實現最大堆,這個就是我剛才說的從最下層開始建立最大堆的過程
