O n 級選排名第k位數(附上演算法複雜度分析)

2021-08-28 07:27:48 字數 3723 閱讀 4561

如果想要拿到第k位,一般說複雜度都比較高。例如,用快排等方式,要用了o(nlogn)水平的時間複雜度。就算是用快排改進,每次在快排的基礎上,只排剩下的一部分,在平均水平上,也會變成了o(nlogn)。

原因是,如果是第乙個數本來就比較小,這樣在快排的基礎上,第一步根本都沒有能夠發生多少的移動。那麼,這樣子演算法複雜度降低會特別慢的。

乙個比較好的方式就是,如果能保證每次都能有很大乙個比例(重點!!)的資料會被排開,而不是一開始的快排的改進只做常數級別的降維。

演算法描述:

假設

第一步:

那麼總的時間為:

n 5∗

5log

(5

)\frac*5log(5)

5n​∗5l

og(5

)其中,後者為每個組內排序的時間(其實無論是怎樣的排序方式,但是由於每個組都是固定的數額,所以,後者怎麼說都是乙個引數),所以,這個步驟的演算法複雜度為o(n)

第二步:

n

5\frac

5n​

複雜度也是o(n)

第三步:(關鍵的一步)

想到這裡,大家肯定能猜到了,我們現在就是要拿到這些中位數的中位數

但是由於,這個陣列的長度是o(n)的,如果我們要用以前的方法的話,那麼最後就會使得整個東西變成了更高的時間複雜度了。

但是,這裡,我們注意到,中位數本身就是乙個選k的問題。

所以,就可以用乙個遞迴來操作。

假設整個操作的複雜度為f(n

)f(n)

f(n)

那麼,這裡的操作就是

f (n

5)

f(\frac)

f(5n​)

第四步:遞迴關鍵步驟

但是這一步的操作,所需要的時間複雜度是:

o (n

)o(n)

o(n)

通過這一步的描述,任然可以得到演算法的複雜度問題。(多個o(n)相加任然是o(n)

遞推公式為:f(n

)=f(

n5)+

f(3n

4)+o

(n

)f(n) = f(\frac) + f (\frac) + o(n)

f(n)=f

(5n​

)+f(

43n​

)+o(

n)通過這個遞推公式,我們很容易就可以推理出來,f(n

)f(n)

f(n)

的複雜度為o(n

)o(n)

o(n)

。這裡為o(n)的原因就是每次的降低比例和演算法中前面的係數乘起來是小於1的。

對這塊沒興趣的,可以跳過了,直接看**就好了。

#include

#include

using namespace std;

intselect

(int n,

int*arr,

int begin,

int k)

;int

partition

(int

*arr,

int begin,

int end)

;int

main()

intpartition

(int

*arr,

int begin,

int end)

arr[i]

= flag;

return i - begin;

}int

select

(int n,

int*arr,

int begin,

int k)

int mid_len = n /5+

(n %5!=

0), mid_index;

int*arr_ = new int

[mid_len]

;for

(int i =

0; i < mid_len;

++i)

int mid_k =

select

(mid_len, arr_,

0, mid_len /2+

(mid_len %2!=

0));

int index =0;

for(

int i =

0; i < n; i ++)}

int temp = arr[begin]

; arr[begin]

= mid_k;

arr[begin + index]

= temp;

temp =

partition

(arr, begin, begin + n-1)

; delete [

]arr_;

if(temp == k)

return mid_k;

else

if(temp > k)

select

(temp, arr, begin, k)

;else

if(temp < k)

select

(n - temp -

1, arr, temp +

1, k - temp -1)

;}

又根據書上的演算法描述寫了另外乙個版本。

#include #include using namespace std;

int select(int *arr, int n, int k);

int main()

int select(int *arr, int n, int k)

// 滿五個才湊成一組

int *mid_ = new int[n / 5];

for (int i = 0; i < n / 5; ++i)

int m = select(mid_, n / 5, n / 10 + (n / 5) % 2);

int* bigger = new int[3 * n / 4];

int* smaller = new int[3 * n / 4];

int* equal = new int[3 * n / 4];

int i = 0, j = 0, s = 0, t = 0;

for (t = 0; t < n; ++t)

int ans;

if (s > k)

ans = select(smaller, s, k);

else if (s + j > k)

ans = m;

else

ans = select(bigger, i, k - s - j);

delete mid_; delete bigger; delete smaller; delete equal;

return ans;

}

中位數與第K小元素

演算法實際上是模仿快速排序演算法設計出來的,其基本思想也是對輸入陣列進行遞迴劃分,與快速排序不同的是,它只對劃分出來的子陣列之一進行遞迴處理 int randompartition int a,int l,int r tmp a i a i a r a r tmp return i randompa...

中位數與第K小元素

演算法實際上是模仿快速排序演算法設計出來的,其基本思想也是對輸入陣列進行遞迴劃分,與快速排序不同的是,它只對劃分出來的子陣列之一進行遞迴處理 int randompartition int a,int l,int r tmp a i a i a r a r tmp return i randompa...

例項分析長尾關鍵詞助杭州seo百度排名第一

最近杭州seoer群裡熱鬧起來了,排名風雲變化,我的個人 很榮幸的排名第一。杭州seo並不是我想優化的詞,畢竟目前從事 s程式設計客棧eo培訓。之前,杭州seo第一的現在都是自己的朋友,像胡餘豐 羽毛哥 馬明浩。畫圈的就是杭州白冰的 半斤八兩的seo誤打誤撞的就上了地 區第一名。這個詞並非是杭州白冰...