如果想要拿到第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誤打誤撞的就上了地 區第一名。這個詞並非是杭州白冰...