求第k大的数(用到快速排序算法的思想)

//下面两种part效率比较:相同运算量下part比part2快5倍左右,part2写法简单但是效率低

#include "stdafx.h"
#include <iostream>
#include <stdio.h>
using namespace std;

int part(int *arr, int l , int r)
{
    c_num += r - l;
    swap(arr[r],arr[l+rand()%(r-l)]);
    int q = r--;
    while( l < r)
    {
        while(l <= r && arr[l] <= arr[q]) ++l;
        while(l < r && arr[r] >= arr[q]) --r;
        if(l<r&&arr[l]>arr[r]) swap(arr[l], arr[r]);
    }
    if(l<q&&arr[l]>arr[q]) swap(arr[l], arr[q]);
    return l;
}

int part2(int *arr, int l , int r)
{
    c_num += r - l;
    int k, q = l;
    swap(arr[l], arr[l+rand()%(r-l)]);
    for(k = l+1; k <= r; ++k)
    {
        if(arr[k] <= arr[q])
        {
            if(++l != k)
                swap(arr[l], arr[k]);
        }
    }
    swap(arr[l], arr[q]);
    return l;
}

void qsort(int *arr, int l, int r)
{
    if(l >= r) return;
    int mid = part(arr, l , r);
    qsort(arr, l, mid-1);
    qsort(arr,mid+1, r);
}

int findNumK(int *arr, int l, int r, const int k)
{
    if(l >= r)
    {
        return arr[k];
    }
    int mid = part(arr, l , r);
    if(k < mid)
    {
        return findNumK(arr, l, mid-1, k);
    }
    else if (k > mid)
    {
        return findNumK(arr,mid+1, r, k);
    }
    else
    {
        return arr[k];
    }
}
#define MAX_RAND 82934829
int myRand(int n)
{
    return  (long((double)rand()/RAND_MAX * MAX_RAND))%n;
}
const int n = 10000000;
int ki = 100;
int arr[n];
int brr[n];
int _tmain(int argc, _TCHAR* argv[])
{
    for(int i = 0; i < n; ++i)
    {
        arr[i] = i;
    }
    for(int i = 0; i < n; ++i)
    {
        swap(arr[i],arr[myRand(n)]);
    }
    for(int i = 0; i < n; ++i)
    {
        brr[i] = arr[i];
    }
    printf("@@@@@@@\n");
    while(cin>>ki)
    {
        printf("\n%d %d\n", c_num, findNumK(brr, 0, n-1, n-ki));
        for(int i = 0; i < n; ++i)
        {
            brr[i] = arr[i];
        }
        c_num = 0;
    }
    printf("\n################\n");
    c_num = 0;
    qsort(arr, 0, n-1);
    for(int i = n-1; i >= n - ki; --i)
    {
        printf("%d ", arr[i]);
    }
    printf("\n%d\n",c_num);
    getchar();
    return 0;
}
时间: 2024-10-07 06:40:30

求第k大的数(用到快速排序算法的思想)的相关文章

《数据结构与算法分析:C语言描述》读书笔记------练习1.1 求第K大的数

求一组N个数中的第k个最大者,设k=N/2. 1 import java.util.Random; 2 3 4 public class K_Max { 5 6 /** 7 * @param args 8 */ 9 //求第K大的数,保证K大于等于1,小于等于array.length/2哦 10 public static int TopK(int array[],int K) 11 { 12 int topk[] = new int [K]; 13 for(int i = 0; i<topk.

普林斯顿公开课 算法3-2:求第k大的数

问题 给定N个元素的数组,求第k大的数. 特例 当k=0时,就是求最大值,当k=N-1时,就是求最小值. 应用 顺序统计 求top N排行榜 基本思想 使用快速排序方法中的分区思想,使得a[k]左侧没有更小的数,右侧没有更大的数 性能 快速选择算法的复杂度是N. 最坏情况下的复杂度是1/2N^2,但是可以通过预先洗牌来防止出现最坏情况 代码 public class QuickSort { // 对区间 [start, end) 进行分区 public static int partition(

POJ2985 并查集+线段树 求第k大的数

其实这题之前做过,线段树一直不熟,所以也一直没有搞懂 本题的关键是线段树原始区间代表的是每一种容器(size不同)的数量 比如 刚开始都是互不相关的,所以1的容器有n个 2 3 4...为0个 线段树每个结点的附加信息是该区间的和 本题查找出的代码是关键 比如左右子树分别为sum 27 25 ,则第26大的容器必然在左子树上,继续递归下去,则要在该左子树找 (26-25)大的容器... 通俗讲 本题就是改变点修改 求和变化(附加信息)的情况 只是用k大转化了一下 线段树还是做的太少,近期还要加强

poj 2886 Who Gets the Most Candies? 线段树动态求第k大的数

题意: n个小孩站一圈,每个小孩拿一个数字,从第k个孩子开始出局,然后下一个出局的孩子是刚刚出局的孩子之前或之后第v个(刚刚出局的孩子的数字是+v则之后v个,-v则之前v个),这样所有孩子终将出局,第p个出局的孩子得f(p)分,f(p)定义为p的因子个数.求分数最高的孩子. 分析: 设顺时针为正方向,关键是模拟出每次出局的孩子是剩下的孩子中的正方向的第几个,设当前要出局的是第k个,然后要求出第k个小孩的下标(pos)以便下一次计算下一个出局的孩子是第几个,这些步骤可用线段树维护. 代码: //p

寻找数列中第k大的数算法分析

问题描述:给定一系列数{a1,a2,...,an},这些数无序的,现在求第k大的数. 看到这个问题,首先想到的是先排序,然后直接输出第k大的数,于是得到啦基于排序的算法 算法一: #include<iostream>#include<algorithm>using namespace std;bool cmp(int a, int b){ return a > b; }int main(){ int k; int a[9] = { 6, 5, 9, 8, 2, 1, 7, 3

poj 2401 划分树 求区间第k大的数

题目:http://poj.org/problem?id=2104 划分树待我好好理解下再写个教程吧,觉得网上的内容一般,,, 模板题: 贴代码: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define CLR(a) memset(a,0,sizeof(a)) const int MAXN = 1000

给定两个数组,这两个数组是排序好的,让你求这两个数组合到一起之后第K大的数。

题目:给定两个数组,这两个数组是排序好的,让你求这两个数组合到一起之后第K大的数. 解题思路: 首先取得数组a的中位数a[aMid],然后在b中二分查找a[aMid],得到b[bMid],b[bSt]到b[bMid]的数小于等于a[aMid],b[bMid+1]到b[bEd]大于等于a[aMid],这样数组a和数组b就被划分为了两个部分,第一个部分的数小于等于a[aMid],第二部分的数大于等于a[aMid],然后统计这两个区域数的个数,个数相加等于k就返回,否则重复二分查找.代码如下: def

无序数组求第K大/第K小的数

方法一:quicksort 根据快排思想,从后往前找比基准数小的,交换位置. 从前往后找比基准数大的,交换位置. 最后安放基准数. 保证 l到p 是大数,若 p-l+1==k 那么p就是第K大 若 p-l+1<k 那么从 p+1 到 r 中 找 k-(p-l+1)大的数 若 p-l+1>k 那么从 l 到 p-1中 找第k大的数. 1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #in

51 nod 1105 第K大的数

1105 第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 数组A和数组B,里面都有n个整数.数组C共有n^2个整数,分别是A[0] * B[0],A[0] * B[1] ......A[1] * B[0],A[1] * B[1]......A[n - 1] * B[n - 1](数组A同数组B的组合).求数组C中第K大的数. 例如:A:1 2 3,B:2 3 4.A与B组合成的C包括2 3 4 4 6 8 6 9 12共9个数. I