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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

算法题04:分治法:求第K小元素(线性时间选择算法)

發布時間:2023/12/9 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法题04:分治法:求第K小元素(线性时间选择算法) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
求第k小元素

題目內容

給定一個線性序列集,要求使用分治法求出其中指定的第 KKK 小的數的值和位置,如給定 nnn 個元素和一個整數 iii1≤i≤n1≤i≤n1in,輸出這 nnn 個元素中第 iii 小元素的值及其位置。

一、問題分析(模型、算法設計和正確性證明等)

解決第K小問題有如下幾種方法

①將n個數排序(比如快速排序或歸并排序),選取排序后的第k個數,時間復雜度為O(nlogn)O(nlogn)O(nlogn)

②維護一個k個元素的最大堆,存儲當前遇到的最小的k個數,時間復雜度為O(nlogk)O(nlogk)O(nlogk)。這種方法同樣適用于海量數據的處理。

③部分的快速排序(快速選擇算法),每次劃分之后判斷第k個數在左右哪個部分,然后遞歸對應的部分,平均時間復雜度為O(n)O(n)O(n)。但最壞情況下復雜度為O(n2)O(n^2)O(n2)

④線性時間選擇算法,修改快速選擇算法的主元選取規則,使用中位數的中位數的作為主元,最壞情況下時間復雜度為O(n)O(n)O(n)

? 實驗要求使用分治策略,所以可以使用歸并排序、快速排序、以及線性時間選擇算法,我選擇的是線性時間選擇算法,本質上是快速排序的升級版,算法的思想是修改快速選擇算法的主元選取方法,提高算法在最壞情況下的時間復雜度。

? 算法的思路是:

  • 首先把數組按5個數為一組進行分組,最后不足5個的忽略。對每組數進行排序(如插入排序)求取其中位數。
  • 把上一步的所有中位數移到數組的前面,對這些中位數遞歸調用線性時間選擇算法求得他們的中位數。
  • 將上一步得到的中位數作為劃分的主元進行整個數組的劃分。
  • 判斷第k個數在劃分結果的左邊、右邊還是恰好是劃分結果本身,前兩者遞歸處理,后者直接返回答案。
  • 二、復雜度分析

    ? 當n<75n<75n<75時,時間復雜度很低,近似于常數, n大于75時,劃分時以5個元素為一組求取中位數,共得到n/5個中位數,再遞歸求取中位數,復雜度為T(n/5),剩余要處理的最大規模變為3n/43n/43n/4,加上多次線性掃描,其時間復雜度為C2nC_{2}nC2?n,所以可以得到遞推式:

    T(n)≤{C1n<75C2n+T(n/5)+T(3n/4)n≥75∴T(n)=O(n)\begin{aligned} T(n) & \leq\left\{\begin{array}{ll}C_{1} & n<75 \\ C_{2} n+T(n / 5)+T(3 n / 4) & n \geq 75\end{array}\right.\\ \therefore T(n)=O(n) \end{aligned}T(n)T(n)=O(n)?{C1?C2?n+T(n/5)+T(3n/4)?n<75n75??

    三、程序實現和測試過程和結果(主要描述出現的問題和解決方法)

    偽代碼:

    public static int DAC_Linear_Select(int a[], int l, int r, int key) {if(a.length <= 5): //當長度小于5時,直接使用冒泡排序,返回查找到的值bubbleSort(a,l,r);return a[key-1];int index=l-1; //定義中位數替換下標for(int star=l,end; (end=star+4)<=r; st+=5){bubbleSort(a,star,end);//每五個數排序swap(a,++t,star+2); //將中位數替換到數組前面,便于遞歸求取中位數的中位數}int pivot=DAC_Linear_Select(a, l, l+(r-l-4)/5, (l+(r+l-4)/5-l+1)/2);int i = partition(a, l, r, pivotId), j = i-l+1;if(key==j) return a[j]; //相等則直接返回else if(key<j) return DAC_Linear_Select(a,l,j-1,key); //小于則向左遞歸else return DAC_Linear_Select(a, j+1,r,key-j) //大于則向右遞歸 }

    java代碼:

    package root;/*** @author 宇智波Akali* 這是線性時間選擇算法(BFPRT算法)解決前k小問題程序* @version2.0*/ public class T3_DAC_Liner_SelectN {public static void swap(int a[], int i,int j){int temp=a[j];a[j] = a[i];a[i] = temp;}//冒泡排序public static void bubbleSort(int a[], int l, int r){for(int i=l; i<r; i++){for(int j=i+1; j<=r; j++){if(a[j]<a[i])swap(a,i,j);}}}//遞歸尋找中位數的中位數public static int FindMid(int a[], int l, int r){if(l == r) return l;int i = 0;int n = 0;for(i = l; i < r - 5; i += 5){bubbleSort(a, i, i + 4);n = i - l;swap(a,l+n/5, i+2);}//處理剩余元素int num = r - i + 1;if(num > 0){bubbleSort(a, i, i + num - 1);n = i - l;swap(a,l+n/5, i+num/2);}n /= 5;if(n == l) return l;return FindMid(a, l, l + n);}//進行劃分過程public static int Partion(int a[], int l, int r, int p){swap(a,p, l);int i = l;int j = r;int pivot = a[l];while(i < j){while(a[j] >= pivot && i < j)j--;a[i] = a[j];while(a[i] <= pivot && i < j)i++;a[j] = a[i];}a[i] = pivot;return i;}public static int Select(int a[], int l, int r, int k){int p = FindMid(a, l, r); //尋找中位數的中位數int i = Partion(a, l, r, p);int m = i - l + 1;if(m == k) return a[i];if(m > k) return Select(a, l, i - 1, k);return Select(a, i + 1, r, k - m);}public static void main(String[] args) {int a[]= {3,0,7,6,5,9,8,2,1,4,13,11,17,16,15,19,18,12,10,14,23,21,27,26,25,29,28,22,20,24,33,31,37,36,35,39,38,32,30,34,43,41,47,46,45,49,48,42,40,44,53,51,57,56,55,59,58,52,50,54,63,61,67,66,65,69,68,62,60,64,73,71,77,76,75,79,78,72,70,74};for(int i = 0; i < 80; i++){System.out.println("第"+(i+1)+"小數為: "+Select(a, 0, 79, i+1));}} }

    ? 算法的思路倒是容易理解,但是把算法轉換為代碼就有太多細節要處理,不同編程語言之間也有差異,一開始用Java寫的,結果因為參數傳遞的機制沒注意,數組值交換有bug,java中定義swap(a[],i,j),要把數組也傳進去。

    運行結果:

    我輸入的數組為10個隨機數,循環輸出低k小數,結果如下:

    為了確保正確性,我又測試了長度為80的0-79的亂序數組,結果也正確。

    總結

    以上是生活随笔為你收集整理的算法题04:分治法:求第K小元素(线性时间选择算法)的全部內容,希望文章能夠幫你解決所遇到的問題。

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