python堆排序 歸併排序

2021-10-02 06:53:20 字數 4054 閱讀 5748

'''

堆排序:

堆是乙個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。

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

]print

(merge(mylist)

)

堆排序,歸併排序

1.介紹 對簡單的選擇排序的一種改進,改進效果非常明顯,每次在選擇最小記錄的同時,並根據比較結果對其他記錄做出相應的調整,那麼排序效率就會提高很多。定義 將待排序的序列構造成乙個大頂堆,此時,整個序列的最大值就是堆頂的根節點。將它移走 其實就是將其與堆陣列的末尾元素進行交換,此時末尾元素就是最大值 ...

歸併排序和堆排序

歸併排序的演算法我們通常用遞迴實現,先把待排序區間 s,t 以中點二分,接著把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操作合併成有序的區間 s,t 桶排序法,非常耗空間。規定陣列中元素的最大值不超過陣列的長度,否則要先求出陣列元素的最大值後,才能指定空桶的個數,要求待排序陣...

堆排序和歸併排序

極少涉及,在此就不再研究 了!堆排序 原理 把待排序的元素按照大小在二叉樹位置上排列,排序好的元素要滿足 父節點的元素要大於等於子節點 這個過程叫做堆化過程,如果根節點存放的是最大的數,則叫做大根堆,如果是最小的數,則叫做小根堆,可以把根節點拿出來,然後再堆化,迴圈到最後乙個節點。時間複雜度 平均 ...