1. 程式人生 > >快速排序在Top k問題中的運用(quickSort and quickSelect in Top k)

快速排序在Top k問題中的運用(quickSort and quickSelect in Top k)

參考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);
        }
    }
}