快速排序在Top k問題中的運用(quickSort and quickSelect in Top k)
阿新 • • 發佈:2018-12-30
參考http://blog.csdn.net/shuxingcq/article/details/75041795
快速排序演算法在陣列中選擇一個稱為主元(pivot)的元素,將陣列分為兩部分,使得 第一部分中的所有元素都小於或等於主元,而第二部分的所有元素都大於主元。對第一部分遞迴地應用快速排序演算法,然後對第二部分遞迴地應用快速排序演算法。
在最差情況下,劃分由 n 個元素構成的陣列需要進行 n 次比較和 n 次移動。因此劃分所需時間為 O(n) 。最差情況下,每次主元會將陣列劃分為一個大的子陣列和一個空陣列。這個大的子陣列的規模是在上次劃分的子陣列的規模減 1 。該演算法需要 (n-1)+(n-2)+…+2+1= O(n^2) 時間。在最佳情況下,每次主元將陣列劃分為規模大致相等的兩部分。設 T(n) 表示使用快速排序演算法對包含 n 個元素的陣列排序所需的時間,因此,和歸併排序的分析相似,快速排序的 T(n)= O(nlogn)。
參考https://www.cnblogs.com/en-heng/p/6336625.html
對於快排在Top k問題中的運用,我們運用Quick Select,Quick Select [1]脫胎於快排(Quick Sort),兩個演算法的作者都是Hoare,並且思想也非常接近:選取一個基準元素pivot,將陣列切分(partition)為兩個子陣列,比pivot大的扔左子陣列,比pivot小的扔右子陣列,然後遞推地切分子陣列。Quick Select不同於Quick Sort的是其沒有對每個子陣列做切分,而是對目標子陣列做切分。其次,Quick Select與Quick Sort一樣,是一個不穩定的演算法;pivot選取直接影響了演算法的好壞,worst case下的時間複雜度達到了 O(n2)
O(n2)
Quick Select的目標是找出第k大元素,所以
- 若切分後的左子陣列的長度 > k,則第k大元素必出現在左子陣列中;
- 若切分後的左子陣列的長度 = k-1,則第k大元素為pivot;
- 若上述兩個條件均不滿足,則第k大元素必出現在右子陣列中。
下面貼上JAVA程式碼:
import java.util.ArrayList; public class QuickSort { //存放最大的k個數 public ArrayList<Integer> result = new ArrayList<Integer>(); public int partition(int[] a,int low,int high){ int privotKey = a[low]; while (low < high){ while (low < high && a[high] >= privotKey){ high --; } // swap(a[high],a[low]); int temp = a[high]; a[high] = a[low]; a[low] = temp; while (low < high && a[low] <= privotKey ){ low ++; } // swap(a[low],a[high]); temp = a[low]; a[low] = a[high]; a[high] = temp; } // for (int b:a) { // System.out.print(b + " "); // } // System.out.println(""); //此時,low = high // low的位置是基準數的下標 return low; } //快排 public void quickSort(int[] a,int low,int high){ if (low < high){ int privotLoc = partition(a,low,high); quickSort(a,low,privotLoc - 1); quickSort(a,privotLoc + 1,high); } } //找第k個最大的元素 public int findKthLargest(int[] nums, int k) { return quickSelect(nums, k, 0, nums.length - 1); } // 快速選擇找第k個最大的元素 public int quickSelect(int[] arr, int k, int left, int right) { // if (left == right) return arr[right]; int index = partition(arr, left, right); if (right - index + 1 > k){ return quickSelect(arr, k, index + 1, right); } else if (right - index + 1 == k){ for (int i = index; i <= arr.length - 1; i++) { result.add(arr[i]); } return arr[index]; } else{ return quickSelect(arr, k - right + index - 1, left, index - 1); } } public static void main(String[] args){ int [] a ={47,25,16,24,15,23,1548,255,445,47,54,0,99999,2312213,1223123123,2}; QuickSort quickSort = new QuickSort(); int num = quickSort.findKthLargest(a,3); // System.out.println(num); for (Integer i:quickSort.result) { System.out.println(i); } } }