转载并参考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的结果 }