乱序中找k大

来源:互联网 发布:日语网络考试 编辑:程序博客网 时间:2024/05/20 02:25

求一个数组中第k大的数,我第一印象是冒泡,因为只要冒泡k趟即可,第一趟冒泡第一大,第二次冒泡第二大,第k次冒泡第k大,时间复杂度为O(kn),n为数组长度。但是我们都知道快速排序是对冒泡的改进,降低冒泡的递归深度,使时间复杂度降低到O(nlgn),为什么不用快排呢?那么快排的时间复杂度又是多少呢?

因为快排每次将数组划分为两组加一个枢纽元素,每一趟划分你只需要将k与枢纽元素的下标进行比较,如果比枢纽元素下标大就从右边的子数组中找,如果比枢纽元素下标小从左边的子数组中找,如果一样则就是枢纽元素,找到,如果需要从左边或者右边的子数组中再查找的话,只需要递归一边查找即可,无需像快排一样两边都需要递归,所以复杂度必然降低。

最差情况如下:假设快排每次都平均划分,但是都不在枢纽元素上找到第k大

第一趟快排没找到,时间复杂度为O(n),第二趟也没找到,时间复杂度为O(n/2),。。。。。,第k趟找到,时间复杂度为O(n/2k),所以总的时间复杂度为

O(n(1+1/2+….+1/2k))=O(n),明显比冒泡快,虽然递归深度是一样的,但是每一趟时间复杂度降低。

这段来自:http://www.cnblogs.com/GODYCA/archive/2013/01/02/2842297.html

好了,接下来附上我的代码,原文的快排代码和我的有点不一样:

#include <iostream>using namespace std;#define SWAP(x, y) {int t; t=x; x=y; y=t;}#define length(array) sizeof(array)/sizeof(array[0])int quicksort(int *array, int left, int right){    int res = 0;    if (left < right){        int temp = array[left];        int i = left + 1;        int j = right;        while (1){            while ((i < right) && (array[i] < temp)){                i++;            }            while ((j > left) && (array[j] > temp)){                j--;            }            if (i >= j){                res = j;                break;            }            /* swap为什么不传地址呢,因为是宏,不是函数,这个函数会展开成语句 */            SWAP(array[i], array[j]);            i++;            j--;        }        SWAP(array[j], array[left]);    }    return res;}int QuickSort_K_MAX(int *a, int low, int high, int k){    if (low >= high)        return a[low];    else    {        int mid = quicksort(a, low, high); //划分子递归数组        if (mid > k)            QuickSort_K_MAX(a, low, mid - 1, k); //左递归        else if (mid < k)            QuickSort_K_MAX(a, mid + 1, high, k); //右递归,一旦右递归mid+1=high,将退化成冒泡,递归深度将变成n,n为数组长度        else            return a[mid];    }}int main(){    int a[10] = { 10, 7, 8, 6, 3, 1, 5, 2, 4, 9 };    int k = 6;    int len = length(a);    printf("%d", QuickSort_K_MAX(a, 0, len - 1, k-1));    return 0;}

代码中,我求k=6,即求第6大,然后传的是k-1,因为索引时0开始的嘛,第6大索引为5。

这里写图片描述

然后就找到了6。

0 0
原创粉丝点击