快速排序在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 result = new ArrayList();

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

你可能感兴趣的:(算法)