日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

排序算法三:堆排序基本原理以及Python实现

發(fā)布時間:2023/12/2 python 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 排序算法三:堆排序基本原理以及Python实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. 基本原理

堆排序就是利用堆的特性進行一個無序序列的排序工作。

堆的特點

堆分為最大堆和最小堆,其實就是完全二叉樹

  • 最大堆要求節(jié)點的元素都要不小于其孩子

  • 最小堆要求節(jié)點元素都不大于其左右孩子

  • 兩者對左右孩子的大小關(guān)系不做任何要求,其實很好理解。

    有了上面的定義,我們可以得知,處于最大堆的根節(jié)點的元素一定是這個堆中的最大值。

    其實我們的堆排序算法就是抓住了堆的這一特點,每次都取堆頂?shù)脑?#xff0c;將其放在序列最后面,然后將剩

    余的元素重新調(diào)整為最大堆,依次類推,最終得到排序的序列。

    基本思想

  • 將初始待排序關(guān)鍵字序列(a1,a2,?,an)構(gòu)建成大頂堆,此堆為初始的無序區(qū)

  • 將堆頂元素a[1]與最后一個元素a[n]交換,此時得到新的無序區(qū)(a1,a2,?,an?1)和新的有序區(qū)(an)

  • 由于交換后新的堆頂a[1]可能違反堆的性質(zhì),因此需要對當(dāng)前無序區(qū)(a1,a2,?,an?1)調(diào)整為新堆,然后再次將a[1]與無序區(qū)最后一個元素交換,得到新的無序區(qū)(a1,a2,?,an?2)新的有序區(qū)(an?1,an?2)。不斷重復(fù)此過程直到有序區(qū)的元素個數(shù)為n-1,則整個排序過程完成。

  • 一個例子

    這里有一個無序的序列,[16,7,3,20,17,8]

    首先構(gòu)造一個二叉樹:

    然后依據(jù)構(gòu)造的二叉樹,從下至上調(diào)整,得到一個初始化的最大堆。

    再講堆頂?shù)臄?shù)和堆底的數(shù)互換。

    但是,此時的堆可能不符合要求,需要再從新調(diào)整:

    再重復(fù),將堆頂和堆底互換(當(dāng)然了,在之前,堆的大小要減1)

    又一次進行調(diào)整:

    重復(fù),將堆頂和堆底互換(當(dāng)然了,在之前,堆的大小又要減1)

    再調(diào)整:

    再換:

    再調(diào)整:

    再換:

    到這,一個堆排序就完成了,最終得到一個最小堆。

    2. Python 實現(xiàn)

    程序

    #定義一個對單一節(jié)點的父節(jié)點以及其孩子大小交換的函數(shù) def initialMaxHeap(a,startIndex,endIndex):leftChildIndex=2*startIndex+1 #父節(jié)點為i,左邊孩子的位置為2*i+1#判斷左邊孩子是否有右邊的孩子if leftChildIndex+1<=endIndex and a[leftChildIndex+1]>a[leftChildIndex]:leftChildIndex+=1 if a[leftChildIndex]>a[startIndex]:#左右孩子值大于父節(jié)點的值的時候,交換,使得這個二叉樹的最大值位于父節(jié)點上temp=a[startIndex]a[startIndex]=a[leftChildIndex]def myHeapSort(a):#a是要排序的序列listLength=a.__len__()while True:if listLength==1:break;finalNodeHavingChild=(listLength)//2-1 #尋找最下一層的父節(jié)點#從下到上調(diào)整堆for i in range(finalNodeHavingChild,-1,-1):#print(a[i])initialMaxHeap(a,i,listLength-1)#將堆頂?shù)臄?shù)換到堆底temp=a[0]a[0]=a[listLength-1]a[listLength-1]=temp#這個調(diào)整之后,可能不滿足最大堆的定義,需要再從上到下再調(diào)整一次#從上到下調(diào)整堆for j in range(0,finalNodeHavingChild+1):#print(a[j])initialMaxHeap(a,j,listLength-1)#將堆的數(shù)量減少listLength-=1return a def generatingRandomNumber(sampleNumber,lower,upper):#sampleNumber :是生成的隨機序列的長度#lower和upper分別是生成隨機序列的下限與上限#最后,函數(shù)會返回一個隨機的無序的序列a。import randoma=[]aSize=a.__len__()while 1:aSize=a.__len__()if aSize>=sampleNumber:breakelse:temp=int(random.randint(lower,upper))a.append(temp)return aif __name__=="__main__":a=generatingRandomNumber(20,1,100)print()print('the sequence before sorting is:\n')print(a)print()print('the sequence after sorting is:\n')print(myHeapSort(a))

    結(jié)果為:

    結(jié)果正確!!!

    排序動態(tài)圖

    3. 時間復(fù)雜度分析

    在構(gòu)建堆(初始化大頂堆)的過程中,完全二叉樹從最下層最右邊的非終端結(jié)點開始構(gòu)建,將它與其孩子進行比較和必要的互換,對于每個非終端結(jié)點來說,其實最多進行兩次比較和一次互換操作,因此整個構(gòu)建堆的時間復(fù)雜度為: O(n)。大概需進行 n2?2=n 次比較和 n2 次交換。

    在正式排序時,n 個結(jié)點的完全二叉樹的深度為?log2n?+1并且有 n個數(shù)據(jù)則需要取 n?1 次調(diào)整成大頂堆的操作,每次調(diào)整成大頂堆的時間復(fù)雜度為O(log2n)。因此,重建堆的時間復(fù)雜度可近似看做: O(nlog2n)

    總結(jié)

    以上是生活随笔為你收集整理的排序算法三:堆排序基本原理以及Python实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。