现在的位置: 首页 > 综合 > 正文

第三题 数组中最小的K个数

2018年04月13日 ⁄ 综合 ⁄ 共 2138字 ⁄ 字号 评论关闭

题目:输入n个整数,输出其中最小的k个。例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。本文思路来自这里http://blog.csdn.net/v_JULY_v/article/details/6403777,对其方法进行了修改,算法思路按照编程之美。

思路:类似快速排序的划分方法,N个数存储在数组S中,再从数组中随机选取一个数X把数组划分为Sa和Sb俩部分,Sa<=X<=Sb,如果要查找的k个元素小于Sa的元素个数,则返回Sa中较小的k个元素,否则返回Sa中所有元素+Sb中小的k-|Sa|个元素。

伪代码:

PARTITION(A, p, r)         //partition过程 p为第一个数,r为最后一个数
1  x ← A[r]               //以最后一个元素作为主元
2  i ← p - 1
3  for j ← p to r - 1
4       do if A[j] ≤ x
5             then i ← i + 1
6                  exchange A[i] <-> A[j]
7  exchange A[i + 1] <-> A[r]
8  return i + 1

RANDOMIZED-PARTITION(A, p, r)      //随机快排的partition过程
1  i ← RANDOM(p, r)                                 //i  随机取p到r中个一个值
2  exchange A[r] <-> A[i]                         
//以随机的 i作为主元
3  return PARTITION(A, p, r)            //调用上述原来的partition过程

RANDOMIZED-SELECT(A, p, r, i)       //以线性时间做选择,目的是返回数组A[p..r]中的第i 小的元素
1  if p = r          //p=r,序列中只有一个元素 
2      then return A[p]
3  q ← RANDOMIZED-PARTITION(A, p, r)   //随机选取的元素q作为主元 
4  k ← q - p + 1                     //k表示子数组 A[p…q]内的元素个数,处于划分低区的元素个数加上一个主元元素
5  if i == k                        //检查要查找的i 等于子数组中A[p....q]中的元素个数k
6      then return A[q]        //则直接返回A[q] 
7  else if i < k       
8      then return RANDOMIZED-SELECT(A, p, q - 1, i)   
          //得到的k 大于要查找的i 的大小,则递归到低区间A[p,q-1]中去查找
9  else return RANDOMIZED-SELECT(A, q + 1, r, i - k)
          //得到的k 小于要查找的i 的大小,则递归到高区间A[q+1,r]中去查找。

#include <iostream>
#include <assert.h>

using namespace std;
int *getmink(int a[],int left,int right,int k)
{
 assert(a!=nullptr||k>left||k<right)
 if (k==right+1)
 {
  return a;
 } 
 //选取key值为中位数的中位数
 int midIndex = (left + right)/2; 
 if(a[left] < a[midIndex]) 
    swap(a[left], a[midIndex]); 
 if(a[right] < a[midIndex]) 
    swap(a[right], a[midIndex]); 
 if(a[right] < a[left]) 
    swap(a[right], a[left]); 
 swap(a[left], a[right]);
 int key=a[right];
 int i = left;
 int h=i-1;
 int j = right-1; 
    for (;i<=j;i++)
    {
  if (a[i]
  {
   h++;
   swap(a[h],a[i]);
  }
 }
 swap(a[h+1],a[right]);
 //由于在搜索下半部分时k一般情况下比h+1小所以无法输出结果,这里用k+left与h+1进行比较,由于h+1是

//在left基础上得到的,所以每次递归中对k+left,这样保证了我们在高半部分时是获得k-h-1个数
 if ((h+1) == k+left) 
  return a; 
 else if ((h+1)>k+left) 
  return getmink(a, left, h+1, k); 
 else return getmink(a, h+1, right, k-h-1); 
}
int main()
{
 int a[] = {7, 8, 9, 54, 6, 4, 11, 1, 2,33,0,23,12,5};
 getmink(a,0,sizeof(a)/sizeof(int)-1,5);
 cout<<a[0]<<endl;
 cout<<a[1]<<endl;
 cout<<a[2]<<endl;
 cout<<a[3]<<endl;
 cout<<a[4]<<endl;
 return 0;
}

抱歉!评论已关闭.