演算法設計與分析 遞迴與分治策略 線性時間選擇

2021-10-22 10:51:17 字數 3748 閱讀 1127

問題描述:給定線性序集中n個元素和乙個整數k,1<=k<=n.要求找出這n個元素中第k小的元素,即如果將這個n個元素依其線性序排列時,排在第k個位置的元素就是要找的元素,當k== 1時,要找的就是最小的元素;當k==n,就是最大的元素;當k=(n+1)/2,稱為中位數。

問題分析:

在某些特殊的情況下,我們可以實現線性時間選擇,對於找最大最小的元素o(n)內可以實現;當k<=n/logn,通過堆排序演算法可以在o(n+klogn)=o(n)內實現;當k>=n-n/logn時也一樣。

下面是給出的一般的選擇問題,從漸近階的意義上看,這個也可以在o(n)時間內完成。

下面的演算法實現參考了《計算機演算法與分析》和一些部落格,是對其的乙個整理。

方法一:

演算法描述:用乙個隨機的序列中的數作為樞紐,用快速排序演算法,進行一次快排,然後將樞紐值和k值進行比較,以此來確定k值,我並沒有做任何的對比所以並不是清楚這種演算法的效率有多少,但是搜到的結果表明,這種演算法的最壞時間複雜度是o(n^2),相對與另一種是不太理想的。

解法:1.首先大家都會想到的解法是排序,之後找出第k個元素,但是排序的時間複雜度不符合要求,或者需要額外的空間。

2.利用快排的思想,以樞紐(隨機得到)為界,將陣列分為2部分,一部分小於等於這個樞紐值,一部分大於這個樞紐值,與快排不同的是,我們只處理一部分,另一部分捨棄。

#

include

using

namespace std;

intpartition

(vector<

int>

&vec,

int left,

int right)

while

(vec[i]

<=temp&&i

swap

(vec[i]

,vec[j]);

} vec[left]

=vec[j]

; vec[j]

=temp;

return j;

}int

quicksort

(vector<

int>

&vec,

int left,

int right,

int k)

void

print

(int x)

intmain()

;for_each

(vec.

begin()

,vec.

end(

),print)

; cout<

int k;

cout<<

"請輸入k(要求找出這n個元素中第k小的元素):"

方法二:

這裡我們就利用中位數來進行線性時間的選擇演算法!

中位數就是指將資料按大小順序排列起來,形成乙個數列,居於數列中間位置的那個資料就是中位數。

演算法思路

(1)將輸入的n個數劃分成 ⌈n5⌉⌈n5⌉ 個組,當然最後一組的數目可能是小於5的!

(2)用任意的排序方法對他們進行排序,並取出一共 ⌈n5⌉⌈n5⌉ 個中位數。

(3)找出該 ⌈n5⌉⌈n5⌉ 個中位數中的中位數。(如果 ⌈n5⌉⌈n5⌉ 是偶數則取相對大的那個數)

(4)將全部的數劃分為兩個部分,小於基準的在左邊,大於等於基準的放右邊。

我們用小圓點表示元素,得到如下圖:

說明:圖中中間白色圈表示各組資料的中位數,最中間灰色表示中位數的中位數! 箭頭是從較小的數指向較大的數!

故我們可以使用該數作為劃分的基準(比上乙個隨機基準的方法會好很多)!

圖中

當n≥75時,3a1大於等於 14n14n。所以按此基準劃分所得的左右2個子陣列的長度都至少縮短 1414。

#

include

using

namespace std;

intpartition

(vector<

int>

&vec,

int left,

int right,

int k)

while

(vec[i]

<=temp&&i

swap

(vec[i]

,vec[j]);

} vec[k]

=vec[j]

; vec[j]

=temp;

return j;

}void

print

(int x)

intselect

(vector<

int>

&vec,

int left,

int right,

int k)

for(

int i=

0;i<=

(right-left-4)

/5;i++

)int x=

select

(vec,left,left+

(right-left-4)

/5,(right-left-4)

/10);

int i=

partition

(vec,left,right,x)

;int j=i-left+1;

if(k<=j)

return

select

(vec,left,i,k)

;else

return

select

(vec,i+

1,right,k-j);}

intmain()

;for_each

(vec.

begin()

,vec.

end(

),print)

; cout<

int k;

cout<<

"請輸入k(要求找出這n個元素中第k小的元素):"

演算法分析與設計 遞迴與分治策略

直接或間接地呼叫自身的演算法稱為遞迴演算法。用函式自身給出定義的函式稱為遞迴函式。在計算機演算法設計與分析中,使用遞迴技術往往使函式的定義和演算法的描述簡潔且易於理解。例1 階乘函式 可遞迴地定義為 其中 n 0 時,n 1為邊界條件 n 0 時,n n n 1 為遞迴方程 邊界條件與遞迴方程是遞迴...

遞迴演算法與分治策略

關於遞迴的學習 1 遞迴演算法的基本思想是 把規模大的 較難解決的問題變成規模較小的的問題。規模較小的問題又變成規模更小的問題,並且小到一定程度可以直接得出它的解,從而得到原來問題的解。遞迴是一種直接或間接呼叫自身的函式的一種演算法,很常用,一般用於解決三類問題 資料的定義按遞迴定義的。fibona...

遞迴與分治策略

1 全排列問題 設r n 是要進行排列的n個元素。集合x中元素的全排列記為perm x 求r n 的全排列perm r n 用遞迴演算法求解 1 找出遞迴子結構性質 即原問題的解包含了子問題的解,且子問題的描述與原問題相同。這就可以用子問題的解來構造原問題的解。設r i r n 這是乙個子問題。設 ...