线性时间选择算法(Java)
線性時間選擇算法(Java)
- 線性時間選擇算法
- 隨機劃分線性選擇
- 分析
- 代碼
- 利用中位數線性時間選擇
- 分析
- 例題
- 代碼
線性時間選擇算法
最近算法課的知識點之一,自己以前沒遇見過(是我菜了沒錯),這次寫一篇。
那么什么是線性時間選擇呢???一句話,在線性時間內完成選擇。
一般情況下是這樣的,我們想要找出一個數組中的最大值或最小值,那就只需要一次排列,然后輸出第一個或最后一個元素就行了,但如果是要找出一個數組中的第k小的元素呢?
在某些特殊情況下,很容易設計出解選擇問題的線性時間算法。如:當要選擇最大元素或最小元素時,顯然可以在O(n)時間完成。(遍歷一次)
一般的選擇問題,特別是中位數的選擇問題似乎比最小(大)元素要難。但實際上,從漸近階的意義上,它們是一樣的。也可以在O(n)時間完成。
之前我記得我更過一篇,里面說到就是先排個序,然后通過下標去得到,因此這個問題的解決效率取決于排序算法的效率。
但是現在不一樣了,我們有了更好的辦法。
隨機劃分線性選擇
分析
隨機劃分線性選擇。模仿快速排序算法,對數組在left——right范圍內進行一次劃分(partition方法,我們這里默認采用隨機元素為基準),得到基準下標i,不大于基準的在左邊,比基準大的在右邊。計算出left——i(包含i)中有多少個元素(j),與k進行比較。
一直到left=right的時候就可以返回a[left]了(其實我覺得如果有上述2的情況的話就不需要這個了)
這是課堂上PPT給的思路
這是算法導論的(就是我剛剛說的)
代碼
/** @Title randomizedSelect* @Description 基于隨機元素為基準的線性時間選擇* @author 滑技工廠* @Date 2020/3/26* @param [a, L, R, k -> L---R中的第k小]* @return int* @throws*/public static int randomizedSelect(int[] a, int L, int R, int k) {if (L == R)return a[L];//獲取為基準的隨機元素的下標int i = randomizedPartition(a, L, R);//j為劃分后左序列到基準(包含基準)的元素個數int j = i - L + 1;if (k < j)//如果k小于j,說明在基準i的左邊return randomizedSelect(a, L, i - 1, k);else if (k == j)//return a[i];else//k大于j 說明在i的右邊序列return randomizedSelect(a, i + 1, R, k - j);}利用中位數線性時間選擇
分析
算法的思路:如果能在線性時間內找到一個劃分基準使得按這個基準所劃分出的2個子數組的長度都至少為原數組長度的ε倍(0<ε<1),那么就可以在最壞情況下用O(n)時間完成選擇任務。例如,當ε=9/10,算法遞歸調用所產生的子數組的長度至少縮短1/10。所以,在最壞情況下,算法所需的計算時間T(n)滿足遞推式T(n)<=T(9n/10)+O(n)。由此可得T(n)=O(n)。
先描述下過程。
將n個輸入元素劃分成n/5個組,每組5個元素,最只可能有一個組不是5個元素。用任意一種排序算法,將每組中元素排好序,并取出中位數,共n/5個。
遞歸調用Select來找出這n/5個元素中的中位數。如果n/5是個偶數,就找它兩個中位數中較大的一個。以該元素作為劃分基準。
這種情況下,找出的基準x至少比3(n-5)/10個元素大,同理也比3(n-5)/10個元素小。(下圖中箭頭指向是從大到小,紅+藍的數量為3(n-5)/10)而當n>=75時,3(n-5)/10>=n/4所以按此基準劃分所得的兩個子數組的長度都至少縮短1/4。
得到劃分基準后,后面就和第一個一樣,計算左序列個數,和k進行比較。判斷在左序列還是右序列,在遞歸調用該方法(k在右序列仍要減j),直到k=j為止,返回那個基準。
例題
代碼
/** @Title select* @Description 利用中位數線性時間選擇* @author 滑技工廠* @Date 2020/3/27* @param [a, l, r, k]* @return int* @throws*/public static int select(int[] a, int l, int r, int k) {if (r - l < 75) {insertSort(a, l, r); //用插入排序進行排序return a[l + k - 1];}int group = (r - l + 5) / 5;for (int i = 0; i < group; i++) {int left = l + 5 * i;int right = (l + i * 5 + 4) > r ? r : l + i * 5 + 4; //如果超出右邊界就用右邊界賦值int mid = (left + right) / 2;insertSort(a, left, right);swap(a, l + i, mid); // 將各組中位數與前i個}int pivot = select(a, l, l + group - 1, (group + 1) / 2); //找出中位數的中位數int p = partition(a, l, r, pivot); //用中位數的中位數作為基準的位置int j = p - l + 1; //leftNum用來記錄基準位置的前邊的元素個數if (k == j)return a[p];else if (k < j)return select(a, l, p - 1, k);else //若k在基準位子的后邊,則要從基準位置的后邊數起,即第(k - leftNum - 1)個return select(a, p + 1, r, k - j - 1);}詳細代碼去我的G站
作業又完成了一個 (^-^)V
總結
以上是生活随笔為你收集整理的线性时间选择算法(Java)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: css网格_一个CSS网格可以全部统治
- 下一篇: [html] html的标签元素分为哪