转载并参考July的博客http://topic.csdn.net/u/20101126/10/b4f12a00-6280-492f-b785-cb6835a63dc9.html,万分感谢!
题目:
输入n个整数,输出其中最小的k个。例如输入1,2,3,4,5,6,7,8和4这几个数字,则最小的4个数字为1,2,3和4。
解一:
/*Title: 5.求n个数中最小的k个:解一
Author: gocode
Date: 2012-10-03*/
#include<iostream>
using namespace std;
class MinK
{
private:
void shiftDown(int *ret,int pos,int length)
{
int t=ret[pos];
for(int s=2*pos+1;s<=length;s=2*s+1)
{
if(s<length&&ret[s]<ret[s+1])
++s;
if(t<ret[s])
{
ret[pos]=ret[s];
pos=s;
}
else break;
}
ret[pos]=t;
}
int *array;
int size;
public:
MinK(int *arr,int si):array(arr),size(si){}
bool kmin(int k,int*& ret)
{
if(k>size)
{
ret=NULL;
return false;
}
else
{
ret=new int[k--];
int i;
for(i=0;i<=k;++i)
ret[i]=array[i];
for(int j=(k-1)/2;j>=0;--j)
shiftDown(ret,j,k);
for(;i<size;++i)
if(array[i]<ret[0])
{
ret[0]=array[i];
shiftDown(ret,0,k);
}
return true;
}
}
void remove(int*& ret)
{
delete[] ret;
ret=NULL;
}
};
int main()
{
int array[]={1,2,3,4,5,6,7,8};
MinK mink(array,sizeof(array)/sizeof(array[0]));
int *ret;
int k=4;
if(mink.kmin(k,ret))
{
for(int i=0;i<k;++i)
cout<<ret[i]<<" ";
cout<<endl;
mink.remove(ret);
}
system("pause");
return 0;
}
解二:
思路:利用make_heap选出vector前K个数的最大值,对于后面的元素,与最大值作比较,如果小于最大值,则替换最大值,然后再次make_heap,选出当前k个数中的最大值。此种解法利用STL函数跳过了建堆过程。make_heap是标准算法库里的模板函数,用于将存储在vector/deque中的元素进行堆操作,将[start, end)范围进行堆排序,默认使用less<int>, 即最大元素放在第一个,也即大根堆
/*Title: 5.求n个数中最小的k个:解二-最大堆
Author: gocode
Date: 2012-10-03*/
#include <iostream>
#include <vector>
#include <algorithm> // 用于使用make_heap()和sort()
using namespace std;
// 利用make_heap()函数创建最大根堆,这样0-K个数中得最大值被保留在数组的第一个位置
// 然后让数组的第一个值和N-K之后的数组值比较,发现小的就替换
// 并重新构建最大根堆,永远保持数组第一个值是堆中最大,直到替换完
void find(vector<int> &a, int k)
{
if(a.size() < k)
return;
// 构建最大根的堆结构
make_heap(a.begin(), a.begin() + k);
// 将堆中的最大值替换为k之后的小值,然后重新构建堆
for(vector<int>::size_type i = k; i != a.size(); i++)
{
if(a[i] < a[0])
{
a[0] = a[i];
make_heap(a.begin(), a.begin() + k);
}
}
// 从小到大排序
sort(a.begin(), a.begin() + k);
// 打印
for(vector<int>::size_type i = 0; i != k; i++)
cout<<a[i]<<" ";
}
int main()
{
vector<int> a;
for(int j = 8; j > 0; j--)
a.push_back(j);
find(a, 4);
system("pause");
return 0;
}
解三:
每次循环求出数组0-K个数的最大值max,然后和N-K个值比较,把小的值赋给max。
参考:http://xingyunbaijunwei.blog.163.com/blog/static/7653806720122293850244/
/*Title: 5.求n个数中最小的k个:解三-数组
Author: gocode
Date: 2012-10-03*/
#include<stdlib.h>
#include<stdio.h>
#define K 4 // K个最小值
#define N 10 // 数组容量
// 求当前datas[0]...datas[K]数组里的最大值
// 并与N-K个值newdata做比较
// 如max小于datas[N-K],则交换
void replace(int datas[], int newdata)
{
int i, pos = -1, max = -(2<<31);
for(i = 0; i < K; i++)
{
if(max < datas[i])
{
max = datas[i];
pos = i;
}
}
if(newdata < datas[pos])
datas[pos] = newdata;
}
void main()
{
int datas[K] = {0};
int j = 0, input;
// 这里的input.txt位置是相对于*.cpp文件的
// freopen会把文件里的内容读入到stdin中
freopen("Debug\\input.txt","r",stdin);
// 这里的scanf会把上面stdin里的内容赋值给input
// EOF表示流末尾
while(EOF != scanf("%d", &input))
{
if(j < K)
datas[j++] = input;
else
replace(datas, input);
}
printf("List array:\n");
for(j = 0; j < K; j++)
printf("%d ",datas[j]);
fclose(stdin);
system("pause"); // 使程序暂停,可以看console的结果
}