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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

选择问题(求第k个最小元素)

發(fā)布時間:2025/3/15 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 选择问题(求第k个最小元素) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

  • 什么是選擇問題
  • 劃分的思路
  • Lomuto 劃分
  • 利用劃分求第k小元素
  • C語言實現(xiàn)
  • 改進
  • 參考資料

什么是選擇問題

選擇問題(selection problem)是求一個n個數(shù)列表的第k個最小元素的問題。這個數(shù)字被稱為第k個順序統(tǒng)計量(order statistic)。當然,對于k=1或者k=n的情況,我們可以掃描整個列表,找出最小或者最大的元素。對于其他情況,我們可以對列表進行排序,然后返回第k個元素。

可是,對于整個列表進行排序是不是小題大做?因為該問題僅僅是要找出第k小的元素,而不是要求把列表從小到大排列。

劃分的思路

我們可以將給定的列表根據(jù)某個值p(例如列表的第一個元素)進行劃分。一般來說,這是對列表元素的重新整理,使左邊部分包含所有小于等于p的元素,緊接著是中軸(pivot)p本身,再接著是所有大于等于p的元素。如下圖所示

有兩種主要的劃分方法,本文討論 Lomuto 劃分,以后會介紹更有名的 Hoare 劃分。

Lomuto 劃分

Lomuto(洛穆托)劃分的偽代碼如下:

// 算法:Lomuto_Partition(A[l..r]) // 用第一個元素作為中軸對子數(shù)組進行劃分 // 輸入:數(shù)組A[0..n-1]的一個子數(shù)組A[l..r],它由左右兩邊的索引l和r(l<=r)定義 // 輸出:A[l..r]的劃分和中軸的新位置p = A[l] s = l for i=l+1 to r doif A[i] < ps = s+1;swap(A[s], A[i]) swap(A[l], A[s]) return s

利用劃分求第k小元素

我們?nèi)绾卫脛澐至斜韥韺ふ移涞趉小元素呢?

假設列表是以數(shù)組實現(xiàn)的,其元素索引從0開始,那么第k小的元素就是把此列表從小到大排序后,索引在k-1位置上的元素。

假設首次劃分此列表,s是分割位置,也就是劃分后中軸元素的索引。我們分3種情況進行討論:

[1]. 當s=k-1 ,那么中軸p本身顯然就是第k小的元素;

[2]. 如果s>k-1,那么整個列表的第k小元素就是左邊部分的第k小元素;

[3]. 如果s<k-1,那么問題就轉(zhuǎn)換為求右邊部分的第(k-s-1)小元素;推導過程是這樣的:本來是求第k小,通過劃分,篩除了最前面的(s+1)個元素,所以只用求右邊部分(藍色)的第 k-(s+1)小。

可以看出,第2種情況和第3種情況雖然沒有徹底解決問題,但是使問題的實例變小了。對于這個較小的實例可以用同樣的方法來解決,即遞歸求解。這個算法被稱為“快速選擇”,在算法思想中屬于減可變規(guī)模算法(減治法的一種)。

C語言實現(xiàn)

// 交換*a和*b void swap(int* a, int* b) {int temp = *a;*a = *b;*b = temp; } // a是數(shù)組首地址,l和r分別是兩端的索引,要求l<=r int Lomuto_partition(int a[], int l, int r) {int pivot = a[l];int j = l;for(int i = l + 1; i <= r; ++i){if( a[i] < pivot ){swap( &a[++j], &a[i]);}}swap(&a[l], &a[j]);return j; // j是下標 }// 返回第k小的元素值。 // 注意:k不是下標,表示第k個 int __quick_select(int a[], int l, int r, int k) {// s是分裂點,中軸的下標int s = Lomuto_partition(a, l, r);if(s == l+k-1)return a[s];else if( s > (l+k-1) )// 處理左邊的部分return __quick_select(a, l, s-1, k);else // 處理右邊的部分return __quick_select(a, s+1, r, k-(s-l+1)); }// 快速選擇主函數(shù) int quick_select_min(int a[], int len, int k) {return __quick_select(a, 0, len-1, k); }

測試代碼如下:

#include <stdio.h> #include <stdlib.h>int main(int argc,char *argv[]) {int k = atoi(argv[1]); //把命令行輸入的字符串轉(zhuǎn)為整數(shù)printf("k = %d \n",k);int array[] = {9,9,8,7,6,5,4,3,3,3,2,2,2,1,1,0,}; int len = sizeof array/sizeof array[0];printf("%dth min = %d\n", k, quick_select_min(array,len,k) );return 0; }

運行截圖:

改進

該算法也可以不用遞歸實現(xiàn)。在非遞歸版本中,甚至不需要調(diào)整k的值,只要一直調(diào)用Lomuto_partition,直到s=k-1為止。

代碼如下:

int quick_select_min_2(int a[], int len, int k) {int left = 0;int right = len - 1;int s;// 直到返回的下標是 k-1 為止while( (s = Lomuto_partition(a, left, right)) != (k-1) ){if(s < k-1)left = s+1; //處理右邊的部分elseright = s-1; // 處理左邊的部分}return a[s]; }

參考資料

《算法設計與分析基礎(第3版)》(清華大學出版社)

與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的选择问题(求第k个最小元素)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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