'''
堆排序:
堆是乙個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。
1)最大堆(最小堆)調整:將堆的末端子節點作調整,使得子節點永遠小於(大於)父節點
2)建立最大堆(小堆):將堆中的所有資料重新排序
3)堆排序:移除位在第乙個資料的根節點,並做最大堆(小堆)調整的遞迴運算
問題1:當堆頂元素改變時,如何重建堆?
首先將完全二叉樹根結點中的記錄移出,該記錄稱為待調整記錄。此時根結點相當於空結點。從空結點的左、右子中選出乙個關鍵字較小的記錄,如果該記錄的關鍵字小於待調整記錄的關鍵字,則將該記錄上移至空結點中。此時,原來那個關鍵字較小的子結點相當於空結點。重複上述移動過程,直到空結點左、右子的關鍵字均不小於待調整記錄的關鍵字。此時,將待調整記錄放入空結點即可。上述調整方法相當於把待調整記錄逐步向下「篩」的過程,所以一般稱為「篩選」法。
問題2:如何由乙個任意序列建初堆?
乙個任意序列看成是對應的完全二叉樹,由於葉結點可以視為單元素的堆,因而可以反覆利用「篩選」法,自底向上逐層把所有子樹調整為堆,直到將整個完全二叉樹調整為堆。
問題3:如何利用堆進行排序(進行堆排序的步驟)?
1)將待排序記錄按照堆的定義建初堆(演算法9.10),並輸出堆頂元素;
2)調整剩餘的記錄序列,利用篩選法將前n-i個元素重新篩選建成為乙個新堆,再輸出堆頂元素;
3)重複執行步驟②n-1次進行篩選, 新篩選成的堆會越來越小,而新堆後面的有序關鍵字會越來越多,最後使待排序記錄序列成為乙個有序的序列,這個過程稱之為堆排序。
時間複雜度:o(nlog2n)
穩定性:不穩定排序演算法
'''# 構造大根堆
defcreate_heap
(my_list, index, heap_size)
:"""
構造大根堆
:param my_list:構造大根堆的元素列表
:param index: 大根堆的起始索引
:param heap_size: 索引的最大值
:return:
"""# 建立堆的起始索引
largest = index
# 左右孩子下標
left_child =
2* index +
1 right_child =
2* index +
2# 判斷左右孩子索引是否超出,並且比較值得大小
if left_child < heap_size and my_list[left_child]
> my_list[largest]
:# 姜兩個值中較大的值得索引賦值給largest,有孩子同理
largest = left_child
if right_child < heap_size and my_list[right_child]
> my_list[largest]
: largest = right_child
# 判斷堆的初始索引位置和當前位置是否相同,如果不相同則交換位置
if index != largest:
my_list[index]
, my_list[largest]
= my_list[largest]
, my_list[index]
# 繼續遞迴構建堆
create_heap(my_list, largest, heap_size)
# print("create_heap", my_list)
defheap_sort
(my_list)
:"""
進行排序
:param my_list:排序的列表
:return:
"""# 自底向上建立堆
for i in
range
(len
(my_list)//2
-1,-
1,-1
):create_heap(my_list, i,
len(my_list)
)"""
此處的my_list為構建完成的大根堆:[89, 36, 27, 11, 7, 2, 12, 5]
"""# 交換元素
for j in
range
(len
(my_list)-1
,0,-
1):# 對以上構建的大根堆元素交換,交換之後繼續構建大根堆
my_list[0]
, my_list[j]
= my_list[j]
, my_list[0]
# 自堆頂構建堆
create_heap(my_list,
0, j)
return my_list
if __name__ ==
'__main__'
: mylist =[5
,7,2
,36,89
,27,12
,11]print
(heap_sort(mylist)
)
'''
歸併排序(速度僅次於快排):
建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法的乙個非常典型的應用。將已有序的子串行合併,得到完全有序的序列;即先使每個子串行有序,再使子串行段間有序。若將兩個有序表合併成乙個有序表,稱為二路歸併。
1)將一組無序的陣列使用二分思想進行分割,直至分到每乙個子串行只剩乙個元素,或者子串行有序時,然後開始合併,分為子串行時可以使用遞迴。
2)通過不斷的分割之後,所有的子串行都已經內部有序,之後進行合併,也就是二路歸併,通過比較,將兩個有序的序列合併為乙個有序的序列,之後重複合併,直至所有的序列都合併完成,需要排序的陣列就排序完成了。
時間複雜度:o(nlog2n)
穩定性:穩定排序演算法
'''def
mergesort
(newlist1,newlist2)
:#定義乙個空列表,方便合併兩個有序陣列
nums =
#定義乙個計數
x, y =0,
0#長度小於兩個分組的長度
while x <
len(newlist1)
and y <
len(newlist2)
:#找出兩個陣列中較小的,新增到空列表中,小的陣列的下標+1
if newlist1[x]
< newlist2[y]:)
x +=
1else
:#反之另外乙個加入空列表中,下標+1
) y +=
1#當其中乙個遍歷完成之後,另外的乙個陣列中的元素全部新增到陣列中
if x ==
len(newlist1)
:for i in newlist2[y:]:
else
:for i in newlist1[x:]:
return nums
defmerge
(mylist):if
len(mylist)
<2:
return mylist
else
:# 歸併排序使用的是二分思想,不斷將其二分
_index =
len(mylist)//2
# 遞迴呼叫繼續二分
left_index = merge(mylist[
:_index]
) right_index = merge(mylist[_index:])
# 多次二分之後,當只剩乙個元素時,一定有序,呼叫函式進行合併
return mergesort(left_index,right_index)
if __name__ ==
'__main__'
: mylist =[2
,3,4
,2,1
,7,8
,5,99
,0,1
,-1,
-6,45
(merge(mylist)
)
堆排序,歸併排序
1.介紹 對簡單的選擇排序的一種改進,改進效果非常明顯,每次在選擇最小記錄的同時,並根據比較結果對其他記錄做出相應的調整,那麼排序效率就會提高很多。定義 將待排序的序列構造成乙個大頂堆,此時,整個序列的最大值就是堆頂的根節點。將它移走 其實就是將其與堆陣列的末尾元素進行交換,此時末尾元素就是最大值 ...
歸併排序和堆排序
歸併排序的演算法我們通常用遞迴實現,先把待排序區間 s,t 以中點二分,接著把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操作合併成有序的區間 s,t 桶排序法,非常耗空間。規定陣列中元素的最大值不超過陣列的長度,否則要先求出陣列元素的最大值後,才能指定空桶的個數,要求待排序陣...
堆排序和歸併排序
極少涉及,在此就不再研究 了!堆排序 原理 把待排序的元素按照大小在二叉樹位置上排列,排序好的元素要滿足 父節點的元素要大於等於子節點 這個過程叫做堆化過程,如果根節點存放的是最大的數,則叫做大根堆,如果是最小的數,則叫做小根堆,可以把根節點拿出來,然後再堆化,迴圈到最後乙個節點。時間複雜度 平均 ...