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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线性时间选择——寻找第k小的数

發布時間:2023/12/9 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线性时间选择——寻找第k小的数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

以下引用自:《算法設計與分析java版》

2.9 線性時間選擇
  本節討論與排序問題類似的元素選擇問題。元素選擇問題的一般提法是:給定線性序集中n個元素和一個整數k,1≤k≤n,要求找出這n個元素中第k小的元素,即如果將這n個元素依其線性序排列時,排在第k個的元素即為要找的元素。當k=1時,就是要找最小元素;當k=n時,就是要找最大元素;當k=(n+1)/2時,稱為找中位數。
  
  在某些特殊情況下,很容易設計出解選擇問題的線性時間算法。例如,找n個元素的最小元素和最大元素顯然可以在O(n)時間完成。如果k≤n/logn,通過堆排序算法可以在O(n+ klogn)= O(n)時間內找出第k小元素。當k≥n- n/logn時也一樣。
  
  一般的選擇問題,特別是中位數的選擇問題似乎比找最小元素要難。但事實上,從漸近階的意義,上看,它們是一樣的。一般的選擇問題也可以在O(n)時間內得到解決。下面要討論解–般的選擇問題的分治算法randomizedSelect。該算法實際上是模仿快速排序算法設計出來的。其基本思想也是對輸人數組進行遞歸劃分。與快速排序算法不同的是,它只對劃分出的子數組之一進行遞歸處理。

題目一:在一個無序數組中,找出其中的第一小的值和第二小的值。

通過變量 min1 min2 很容易就可以完成算法。其中,min1是最小的元素,min2是次小元素。

void Select_2Min2(int* br, int n) {if (NULL == br || n < 2) return;int min1 = br[0] < br[1] ? br[0] : br[1]; // 第一小:最小 int min2 = br[0] + br[1] - min1; // 第二小:次小for (int i = 2; i < n; i++){if (br[i] < min2){if (br[i] < min1) // ( , min1) min1 = br[i]{min2 = min1; // 更新次小值min1 = br[i]; // 更新最小值}else min2 = br[i]; // [min1,min2) min2 = br[i]}}cout << "min1: " << min1 << "min2: " << min2 << endl; }

題目二:在一個無序數組中,找出其中的第k小的值。

對于此類問題,我們可以繼續按照題目一的解法,通過設置k個變量,分別為 min1 ... mink 解決,但未免過于麻煩。我們也可以采用排序的方式,使之無序數組有序,而后返回對應的索引即可。但是我們其實只是需要第k小這一個元素罷了,不需要專門為其進行一次排序。

因此,我們可以使用類快排的方法。

快速排序每一趟排序都會將原數組分成兩部分,基準左邊基準右邊。(升序排列)而基準的左側都是比基準小的元素,也就是說當前基準的位置就是第m小的元素。

下標0123456789
元素532861014181119

如上表:

  • 5號下標的元素10為當前基準,而array[0] ~ array[4] 都小于10,也就是說array[5] 是第6小元素。
  • 如果我們要找第3小,那么我們只需在基準左側再進行一趟快排即可得到。
  • 如果我們要找第8小,那么我們只需在基準右側再進行一趟快排即可得到。

由此一來,我們就可以按照快排的特點設計算法了。

template<typename _T> // 按首位基準劃分,一趟快排 int OnePartition(_T* arr, int left, int right) {int i = left + 1, j = i;while (j <= right){if (arr[j] <= arr[left]){swap(arr[i++], arr[j++]);}else j++;}i = i - 1;swap(arr[left], arr[i]);return i; // 返回基準下標 } template<typename Type> const Type& Select_K(Type* br, int left, int right, int k) {int i = OnePartition(br, left, right); // 找基準位置int pos = i - left + 1; // 找到第pos小if(pos == k) return br[left]; // return br[i] // 是否找到第k小else if (k < pos) return Select_K(br, left, i-1, k); // 左側區間找else return Select_K(br, i + 1, right, k - pos); // 右側區間找 } template<typename Type> const Type& Select_K_Min(int* br, int n, int k) {assert(NULL != br && n > 0 && k <= n && k > 0);return Select_K(br, 0, n - 1, k); }

測試:

int main() {int ar[] = { 89,100,67,78,23,34,56,12,45,90 };int n = sizeof(ar) / sizeof(ar[0]);Select_2Min2(ar, n); // 問題一:第一、第二小for (int k = 1; k <= n; k++) // 分別輸出最小 ~ 最大元素{cout << "["<<k<<"]min ==>" <<Select_K_Min<int>(ar, n, k) << endl;}return 0; }

輸出:

min1: 12min2: 23 [1]min ==>12 [2]min ==>23 [3]min ==>34 [4]min ==>45 [5]min ==>56 [6]min ==>67 [7]min ==>78 [8]min ==>89 [9]min ==>90 [10]min ==>100

總結

以上是生活随笔為你收集整理的线性时间选择——寻找第k小的数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。