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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

如何寻找无序数组中的第K大元素?

發(fā)布時(shí)間:2023/12/13 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何寻找无序数组中的第K大元素? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

如何尋找無(wú)序數(shù)組中的第K大元素?

有這樣一個(gè)算法題:有一個(gè)無(wú)序數(shù)組,要求找出數(shù)組中的第K大元素。比如給定的無(wú)序數(shù)組如下所示:

如果k=6,也就是要尋找第6大的元素,很顯然,數(shù)組中第一大元素是24,第二大元素是20,第三大元素是17...... 第六大元素是9

方法一:排序法

這是最容易想到的方法,先把無(wú)序數(shù)組從大到小進(jìn)行排序,排序后的第k個(gè)元素自然就是數(shù)組中的第k大元素。但是這種方法的時(shí)間復(fù)雜度是O(nlogn),性能有些差。

方法二:插入法

維護(hù)一個(gè)長(zhǎng)度為k的數(shù)組A的有序數(shù)組,用于存儲(chǔ)已知的K個(gè)較大的元素。然后遍歷無(wú)序數(shù)組,每遍歷到一個(gè)元素,和數(shù)組A中的最小元素進(jìn)行比較,如果小于等于數(shù)組A中的最小元素,繼續(xù)遍歷;如果大于數(shù)組A中的最小元素,則插入到數(shù)組A中,并把曾經(jīng)的最小元素"擠出去"。

比如K=3,先把最左側(cè)的7,5,15三個(gè)數(shù)有序放入到數(shù)組A中,代表當(dāng)前最大的三個(gè)數(shù)。

此時(shí),遍歷到3時(shí),由于3<5,繼續(xù)遍歷。

接下來(lái)遍歷到17,由于17>5,插入到數(shù)組A的合適位置,類似于插入排序,并把原先最小的元素5“擠出去”。

繼續(xù)遍歷原數(shù)組,一直遍歷到數(shù)組的最后一個(gè)元素......

最終,數(shù)組A中存儲(chǔ)的元素是24,20,17,代表著整個(gè)數(shù)組的最大的3個(gè)元素。此時(shí)數(shù)組A中的最小元素17就是我們要尋找的第K大元素。

這個(gè)方法的時(shí)間復(fù)雜度是O(nk),但是如果K的值比較大的話,其性能可能還不如方法一。

小頂堆法

二叉堆是一種特殊的完全二叉樹(shù),它包含大頂堆和小頂堆兩種形式。其中小頂堆的特點(diǎn)是每一個(gè)父節(jié)點(diǎn)都小于等于自己的兩個(gè)子節(jié)點(diǎn)。要解決這個(gè)算法題,我們可以利用小頂堆的特性。

維護(hù)一個(gè)容量為K的小頂堆,堆中的K個(gè)節(jié)點(diǎn)代表著當(dāng)前最大的K個(gè)元素,而堆頂顯然是這K個(gè)元素中的最小值
遍歷原數(shù)組,每遍歷一個(gè)元素,就和堆頂比較,如果當(dāng)前元素小于等于堆頂,則繼續(xù)遍歷;如果元素大于堆頂,則把當(dāng)前元素放在堆頂位置,并調(diào)整二叉堆(下沉操作)。
遍歷結(jié)束后,堆頂就是數(shù)組的最大K個(gè)元素中的最小值,也就是第K大元素

假設(shè)K=5,具體操作步驟如下:

1.把數(shù)組的前K個(gè)元素構(gòu)建成堆

2.繼續(xù)遍歷數(shù)組,和堆頂比較,如果小于等于堆頂,則繼續(xù)遍歷;如果大于堆頂,則取代堆頂元素并調(diào)整堆。

遍歷到元素2,由于2<3,所以繼續(xù)遍歷。

遍歷到元素20,由于20>3,20取代堆頂位置,并調(diào)整堆。

遍歷到元素24,由于24>5,24取代堆頂位置,并調(diào)整堆。

以此類推,我們一個(gè)一個(gè)遍歷元素,當(dāng)遍歷到最后一個(gè)元素8時(shí),小頂堆的情況如下:

3.此時(shí)的堆頂,就是堆中的最小元素,也就是數(shù)組中的第K大元素。

這個(gè)方法的時(shí)間復(fù)雜度是多少呢?

1.構(gòu)建堆的時(shí)間復(fù)雜度是O(K)
2.遍歷剩余數(shù)組的時(shí)間復(fù)雜度O(n-K)
3.每次調(diào)整堆的時(shí)間復(fù)雜度是O(logk)
其中2和3是嵌套關(guān)系,1和2,3是并列關(guān)系,所以總的最壞時(shí)間復(fù)雜度是O((n-k)logk + k)。當(dāng)k遠(yuǎn)小于n的情況下,也可以近似地認(rèn)為是O(nlogk)

這個(gè)方法的空間復(fù)雜度是多少呢?
剛才我們?cè)谠敿?xì)步驟中把二叉堆單獨(dú)拿出來(lái)演示,是為了便于理解。但如果允許改變?cè)瓟?shù)組的話,我們可以把數(shù)組的前K個(gè)元素“原地交換”來(lái)構(gòu)建成二叉堆,這樣就免去了開(kāi)辟額外的存儲(chǔ)空間。因此空間復(fù)雜度是O(1)

代碼如下:

/*** 尋找第k大元素* @param array 待調(diào)整的數(shù)組* @param k 第幾大* @return*/public static int findNumberK(int[] array, int k) {//1.用前k個(gè)元素構(gòu)建小頂堆buildHeap(array, k);//2.繼續(xù)遍歷數(shù)組,和堆頂比較for (int i = k; i < array.length; i++) {if(array[i] > array[0]) {array[0] = array[i];downAdjust(array, 0, k);}}//3.返回堆頂元素return array[0];}private static void buildHeap(int[] array, int length) {//從最后一個(gè)非葉子節(jié)點(diǎn)開(kāi)始,依次下沉調(diào)整for (int i = (length - 2) / 2; i >= 0; i--) {downAdjust(array, i, length);}}/*** 下沉調(diào)整* @param array 待調(diào)整的堆* @param index 要下沉的節(jié)點(diǎn)* @param length 堆的有效大小*/private static void downAdjust(int[] array, int index, int length) {//temp保存父節(jié)點(diǎn)的值,用于最后的賦值int temp = array[index];int childIndex = 2 * index + 1;while (childIndex < length) {//如果有右孩子,且右孩子小于左孩子的值,則定位到右孩子if (childIndex + 1 < length && array[childIndex + 1] < array[childIndex]) {childIndex++;}//如果父節(jié)點(diǎn)小于任何一個(gè)孩子的值,直接跳出if (temp <= array[childIndex])break;//無(wú)需真正交換,單項(xiàng)賦值即可array[index] = array[childIndex];index = childIndex;childIndex = 2 * childIndex + 1;}array[index] = temp;}public static void main(String[] args) {int[] array = new int[] {7, 5, 15, 3, 17, 2, 20, 24, 1, 9, 12, 8};System.out.println(findNumberK(array, 5));}

方法四:分治法

大家都了解快速排序,快速排序利用分治法,每一次把數(shù)組分成較大和較小元素兩部分。我們?cè)趯ふ业贙大元素的時(shí)候,也可以利用這個(gè)思路,以某個(gè)元素A為基準(zhǔn),把大于A的元素都交換到數(shù)組左邊,小于A的元素交換到數(shù)組右邊。

比如我們選擇以元素7作為基準(zhǔn),把數(shù)組分成了左側(cè)較大,右側(cè)較小的兩個(gè)區(qū)域,交換結(jié)果如下:

包括元素7在內(nèi)的較大元素有8個(gè),但我們的K=5,顯然較大元素的數(shù)目過(guò)多了。于是我們?cè)谳^大元素的區(qū)域繼續(xù)分治,這次以元素12為基準(zhǔn):

這樣一來(lái),包括元素12在內(nèi)的較大元素有5個(gè),正好和K相等。所以,基準(zhǔn)元素12就是我們所求的。

這就是分治法的思想,這種方法的時(shí)間復(fù)雜度甚至優(yōu)于小頂堆法,可以達(dá)到O(n)。

轉(zhuǎn)載于:https://www.cnblogs.com/kyoner/p/10465633.html

總結(jié)

以上是生活随笔為你收集整理的如何寻找无序数组中的第K大元素?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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