無序數(shù)組中的第k大元素:快速排序和堆排序

找到無序數(shù)組中的第k大元素, kth_Largest_element_in_an_array。
常見的解決方案有兩種,快速排序思想和堆排序思想,簡單記錄一下過程,順便復(fù)習(xí)快速排序和堆排序過程。

快速排序思想

快速排序的理論基礎(chǔ)是隨機取一個數(shù),大的放左邊,小的放右邊,完成一趟排序。
分別對左右兩邊遞歸做相同的分割,最后還剩一個數(shù),自然有序,完成快速排序。
那么找第k大的元素,即完成一次排序后,隨機找出的這個數(shù)的前面有 k -1個數(shù),那么就是第k大個元素。
下標(biāo): k - 1 = index.
否則再根據(jù)下標(biāo)關(guān)系判斷在k在左邊還是右邊,繼續(xù)如上操作。
快速排序完成一次排序的函數(shù)如下:

# 最后一個數(shù)為支點,從小到大排序
def partition_two(array, lo, hi):
    i = lo
    j = hi
    while i < j:
        while i < j and array[i] <= array[hi]:
            i += 1
        while i < j and array[j] >= array[hi]: # =保證支點不變,可以后續(xù)比較。
            j -= 1
        array[i], array[j] = array[j], array[i]
    array[i], array[hi] = array[hi], array[i]
    return i

下面得到分界點的下標(biāo),對左右兩邊遞歸分割,完成排序:

# 快速排序
def quick_sort(array, lo, hi):
    #參數(shù)合法性
    if array is None or lo >= hi:
        return
    mid = partition_two(array, lo, hi)
    quick_sort(array, lo, mid - 1)
    quick_sort(array, mid + 1, hi)

找第k大元素的代碼類似。

堆排序思想

首先堆不作介紹,分為大根堆和小根堆。堆的操作有插入和刪除最大(小)元素,插入的節(jié)點放在最后,然后進(jìn)行堆化操作。
堆的一個經(jīng)典實現(xiàn)是完全二叉樹,這樣實現(xiàn)的堆為二叉堆。
下面是數(shù)組進(jìn)行從小到大的堆排序過程。

堆化數(shù)組

一個隨機數(shù)組,對根節(jié)點i進(jìn)行堆化操作(i的左右子樹也都是堆)。
選擇左右節(jié)點的小節(jié)點與根節(jié)點比較,若是根節(jié)點還小于較小值,則滿足堆的性質(zhì)。
否則進(jìn)行交換,對交換過的節(jié)點繼續(xù)進(jìn)行堆化操作,直至全部堆化。

#對數(shù)組來說,以下標(biāo)index為根節(jié)點的左右子樹的下標(biāo)為 index * 2 + 1, index * 2 +  2
# 將length個元素,i為節(jié)點的數(shù)組堆化(i的子節(jié)點也都是堆)
def big_heap_array(array, i, length):
    # 左葉子節(jié)點
    temp_value = array[i]
    node_index = (i << 1) + 1
    while node_index < length:
        #左右葉子節(jié)點的較大值
        if node_index + 1 < length and array[node_index + 1] > array[node_index]:
            node_index = node_index + 1
        # 如果根節(jié)點大于葉子節(jié)點,說明已經(jīng)是堆,退出循環(huán)。
        if array[node_index] < temp_value:
            break
        array[i] = array[node_index]
        # 調(diào)整交換過元素的子節(jié)點
        i = node_index
        node_index = (i << 1) + 1
    array[i] = temp_value

上面操作是堆化i下標(biāo)節(jié)點的數(shù)組,從小到大的排序過程如下:

  1. 從最后一個根節(jié)點開始,往上進(jìn)行堆化, 此時array[0] 為最大值。
  2. 交換array[0]和最后一個元素,此時再進(jìn)行堆化,得到最小的元素與倒數(shù)第二個元素,逐次完成從小到大排序。
#n長度的數(shù)組,最后一個根節(jié)點的下標(biāo)為: n / 2 - 1
#構(gòu)建最大堆,從小到大排序
def heap_sort_one(array):
    # 最后一個跟節(jié)點
    last_node_index = (len(array) >> 1) - 1
    for node_index in range(last_node_index, 0 - 1, -1):  #[llast_node_index .. 0] 的列表
        big_heap_array(array, node_index, len(array))
    # 堆頂最大值和最后一個數(shù)互換, 然后堆化數(shù)組
    for index in range(len(array) - 1, 0, -1):
        array[0], array[index] = array[index], array[0]
        big_heap_array(array, 0, index)

下面來解決此問題。
首先利用數(shù)組的前k個元素建立一個k大小的小根堆。逐次取后面的元素與堆頂比較, 如果大于堆頂,則替換堆頂,然后進(jìn)行堆化。最終結(jié)果就是最大的前k個元素都在堆中,其中堆頂元素堆小,就是第k大的元素。

尋找的代碼見github:https://github.com/yunshuipiao/sw-algorithms

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 排序的基本概念 在計算機程序開發(fā)過程中,經(jīng)常需要一組數(shù)據(jù)元素(或記錄)按某個關(guān)鍵字進(jìn)行排序,排序完成的序列可用于快...
    Jack921閱讀 1,571評論 1 4
  • 1 序 2016年6月25日夜,帝都,天下著大雨,拖著行李箱和同學(xué)在校門口照了最后一張合照,搬離寢室打車去了提前租...
    RichardJieChen閱讀 5,377評論 0 12
  • 概述排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部的...
    Luc_閱讀 2,372評論 0 35
  • 曾經(jīng)我很敬重的一個領(lǐng)導(dǎo),一直以來,不說智商有多高,情商那是沒得說的。首先,他總能給人一種感覺是他站在你的角度考慮問...
    andyly閱讀 626評論 0 0
  • 看到這些花兒的時候,心想這片花開了有小半年了吧,記得上一次給它們拍照好像是很久的事兒了~ 現(xiàn)在,趁著寒冬未到,它們...
    尚小小閱讀 534評論 2 3

友情鏈接更多精彩內(nèi)容