中位數和順序統計量---演算法導論學習筆記
演算法導論斷斷續續看了一小部分,但是還沒有寫過總結和筆記,很多思考和學習到的東西都隨著時間流失掉了(痛心)。
下面進入正題:
1.最大值和最小值問題
最簡單的確定一個有n個元素的集合中最小元素(最大元素)的方法就是所謂“打擂臺”的思路。遍歷集合,過程中將每個元素與現在所持有的最小元素進行比較,如果該元素小於現有最小元素則更新最小元素為該元素,否則繼續遍歷。可見至少要進行n-1次比較,從次數看來,這個演算法是最優的。
那麼,如果要同時找出最小元素和最大元素的話,該怎麼做?
(1).若n為奇數,則max=arr[0],min=arr[0];
若n為偶數,則max=arr[0],min=arr[1];
(2).集合中每兩個元素組成一對,分別求其大小關係。
(3).遍歷集合,將max和min與每對元素集中的最大元素與最小元素比較,進行更新
分奇數和偶數的情況是因為奇數個元素的集合不能被正好分成n/2個集合,所以乾脆將第一個元素孤立出來。
現在分析比較次數:
奇數:遍歷n/2個子集,max和min分別比較,加上每個子集內部比較,於是總共是3*floor(n/2)次.
偶數:第一次max和min子集的初始化比較,加上(n-2)/2個子集內部比較,加上遍歷的2*(n-2)/2次比較,所以總共是3n/2-2次比較。
2.選擇演算法(期望為線性時間)
這裡提供了一個分治演算法來確定集合中的第i個元素。
(1).p為集合第一個元素,r為元素最後一個元素,q為分割槽關鍵字索引,i為所求元素在集合中的次序 (2).對集合中的元素進行一次基於快速排序的隨機分割槽(randomized-patition),並得到分割槽關鍵元素的索引值q。 (3).k=q-p+1,得到q之後的分割槽首元素,此時k代表q在該集合中的索引,而q得到的是整個集合中的索引值. (4).若k=i,則返回A「q」, 若k>i,返回呼叫select(A,p,q-1,i) 若k<i,返回呼叫select(A,q+1,r,i-k)
下面貼上java實現:
import java.util.Random;
public class RandomSelect {
public static void exchange(int[] arr,int i,int j) {
if(i<0||i>=arr.length||j<0||j>=arr.length||i==j)
return;
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static int patition(int[] arr,int p,int r) {
Random random=new Random();
int index=Math.abs(random.nextInt(r));
while(index<p)
index=Math.abs(random.nextInt(r));
exchange(arr,r,index);
int x=arr[r];
int i=p-1;
for(int j=p;j<r;j++) {
if(arr[j]<x) {
i++;
exchange(arr,i,j);
}
}
exchange(arr,i+1,r);
return i+1;
}
public static int randomized_select(int[] arr,int p,int r,int i) {
if(p==r)
return arr[p];
int q=patition(arr,p,r);
int k=q-p+1;
if(k==i)
return arr[q];
if(i<k)
return randomized_select(arr,p,q-1,i);
else
return randomized_select(arr,q+1,r,i-k);
}
public static void main(String...args) {
int[] arr={2,5,4,6,35,11,7,55,3,73,80};
System.out.println(randomized_select(arr,0,arr.length-1,arr.length));
}
}
瞭解了基本的演算法,下面對時間期望進行分析:
k-1和n-k分割槽是隨機分區分出的兩個子集,對T(n)求期望值
所以,
最終,
如果假設對