一、堆-完全二叉樹
堆排序是利用堆這種資料結構而設計的一種排序演算法,堆排序是一種選擇排序,它的最壞,最好,平均時間複雜度均為o(nlogn),是不穩定排序
堆排序中的堆有大頂堆、小頂堆兩種。他們都是完全二叉樹
將該堆按照排序放入列表
1. 大頂堆:
所有的父節點的值都比孩子節點大,葉子節點值最小。root 根節點是第乙個節點值最大
2. 小頂堆:
和大頂堆相反,所有父節點值,都小於子節點值,root 根節點是 第乙個節點值最小
二、堆排序
基本思路:將待排序序列構造成乙個大頂堆,此時,整個序列的最大值就是堆頂的根節點。將其與末尾元素進行交換,此時末尾就為最大值。可稱為有序區,然後將剩餘n-1個元素重新構造成乙個堆,估且稱為堆區(未排序)。這樣會得到n個元素的次小值。重複執行,有序區從:1--->n,堆區:n-->0,便能得到乙個有序序列了
2.1 構造大頂堆
在構造有序堆時,開始時只需要掃瞄一半的元素(所有父節點)(length/2-1 --> 0)
因為只有他們才有子節點:3-->2 -->1 -->0
1. 從最後乙個父節點開始,將父節點、他所有的子節點中的最大值交換到父節點。父節點:3
2. 將倒數第二個父節點同理交換,父節點:2
3. 父節點:1
4. 根節點:0
5. 注意很重要:務必注意-承接第3步。
假設根節點值為:10, 當他和兩個子節點70, 80,
父節點和兩子節點中的大的(80)交換後位於父節點2:原來80的位置。
可是他還有子節點,且子節點中的值比根節點大,那就還需要以他為父節點構造一次,與子節點6 值為20交換一次
同理在其他所有父節點的構造中都需要判斷調整
忽略第五步。構造好的的大頂堆如下:
2.2 開始排序
基本思路:將待排序序列構造成乙個大頂堆,此時,整個序列的最大值就是堆頂的根節點。將其與末尾元素進行交換,此時末尾就為最大值。可稱為有序區,然後將剩餘n-1個元素重新構造成乙個堆,估且稱為堆區(未排序)。這樣會得到n個元素的次小值。重複執行,有序區從:1--->n,堆區:n-->0,便能得到乙個有序序列了
每次將堆頂(根節點)最的的元素和堆尾列表最後乙個元素交換,80 和40交換
即上面說的堆區(未排序):n-->0最大元素(根節點),和有序區從:1--->n,最後乙個元素交換
按照上面原理繼續排序,70, 30 交換。然後調整堆
堆頂元素60尾元素20交換後-->調整堆
最後結果
三、python**實現
現在排序這麼乙個序列:list_ = [4, 7, 0, 9, 1, 5, 3, 3, 2, 6]
堆排序 heap_sort
7 09 1 5 3
3 2 6
list_ = [4, 7, 0, 9, 1, 5, 3, 3, 2, 6]
3.2 **實現
def swap(data, root, last):
data[root], data[last] = data[last], data[root]
#調整父節點 與孩子大小, 製作大頂堆
def adjust_heap(data, par_node, high):
new_par_node = par_node
j = 2*par_node +1 #取根節點的左孩子, 如果只有乙個孩子 high就是左孩子,如果有兩個孩子 high 就是右孩子
while j <= high: #如果 j = high 說明沒有右孩子,high就是左孩子
if j < high and data[j] < data[j+1]: #如果這兒不判斷 j < high 可能超出索引
# 乙個根節點下,如果有兩個孩子,將 j 指向值大的那個孩子
j += 1
if data[j] > data[new_par_node]: #如果子節點值大於父節點,就互相交換
data[new_par_node], data[j] = data[j], data[new_par_node]
new_par_node = j #將當前節點,作為父節點,查詢他的子樹
j = j * 2 + 1
else:
# 因為調整是從上到下,所以下面的所有子樹肯定是排序好了的,
#如果調整的父節點依然比下面最大的子節點大,就直接打斷迴圈,堆已經調整好了的
break
# 索引計算: 0 -->1 --->....
# 父節點 i 左子節點:2i +1 右子節點:2i +2 注意:當用長度表示最後乙個葉子節點時 記得 -1
# 即 2i + 1 = length - 1 或者 2i + 2 = length - 1
# 2i+1 + 1 = length 或 2i+2 + 1 = length
# 2(i+1)=length 或 2(i+1)+1 = length
# 設j = i+1 則左子節點(偶數):2j = length 和 右子節點(基數):2j+1 = length
# 2j//2 = j == (2j+1)//2 這兩個的整除是一樣的,所以使用length//2 = j 然後 i + 1 = j
# i = j-1 = length//2 -1 #注意左子節點:2i+1 //2 =i 而右子節點:(2i+2)//2 = i+1
# 從第乙個非葉子節點(即最後乙個父節點)開始,即 list_.length//2 -1(len(list_)//2 - 1)
# 開始迴圈到 root 索引為:0 的第乙個根節點, 將所有的根-葉子 調整好,成為乙個 大頂堆
def heap_sort(lst):
根據列表長度,找到最後乙個非葉子節點,開始循化到 root 根節點,製作 大頂堆
:param lst: 將列表傳入
:return:
length = len(lst)
last = length -1 #最後乙個元素的 索引
last_par_node = length//2 -1
while last_par_node >= 0:
adjust_heap(lst, last_par_node, length-1)
last_par_node -= 1 #每調整好乙個節點,從後往前移動乙個節點
# return lst
while last > 0:
#swap(lst, 0, last)
lst[0], lst[last] = lst[last],lst[0]
# 調整堆讓 adjust 處理,最後已經排好序的數,就不處理了
adjust_heap(lst, 0, last-1)
last -= 1
return lst #將列表返回
if __name__ == '__main__':
list_ = [4, 7, 0, 9, 1, 5, 3, 3, 2, 6]
heap_sort(list_)
print(list_)
#最後結果為:
[0, 1, 2, 3, 3, 4, 5, 6, 7, 9]
堆儲存 堆排序 python實現
使用堆實現優先佇列 對於總共n個請求 使用普通陣列或者順序陣列 最差情況o n 2 使用堆 o n log n 堆的基本實現 二叉堆 任何乙個子節點都不大於他的父節點 必須是一棵完全二叉樹 用陣列儲存二叉堆 shift up shift down 基礎堆排序 heapsort1 heapify 堆排...
5排序 5堆排序
include using namespace std int n 10 元素個數 int b 11 定義全域性陣列 void shift down int i else flag 1 下乙個移動的結點是i,即沒有被更改 函式原理 對傳入的i進行下移,i移動到比它的兒子都小為止 最壞情況是移動到葉 ...
python3堆排序 python 堆排序
堆排序 堆排序 heapsort 是指利用堆這種資料結構所設計的一種排序演算法。堆積是乙個近似完全二叉樹的結構,並同時滿足堆積的性質 即子結點的鍵值或索引總是小於 或者大於 它的父節點 但是不保證所有左子樹比右子樹小反之亦然 堆排序可以說是一種利用堆的概念來排序的選擇排序。分為兩種方法 大頂堆 每個...