题目:
输入n个整数,找出其中最小的k个数。如输入4、5、1、6、2、7、3、8 这8个数字,则最小的 4 个数字是1、2、3、4
思路:
1、基于快排的思路,每排序一次可以确定一个数的位置,如果这个位置正好为k,则前k个数就是最小的k个数字 。
时间复杂度:O(n) ,注意此时会改变原来的数组
代码:
#include <iostream>
#include <vector>
using namespace std;
//功能:找出最小的k个数
//使用快速排序找到下标为k的数即可,但是这样会改变原来的数组
int Partition(vector<int> &data , int begin , int end)
{
if(begin >= end)
return begin;
int j = begin ;
for(int i = begin + 1; i <= end ; i++)
{
if(data[i] < data[begin])
{
j++;
swap(data[i] , data[j]);
}
}
swap(data[j] , data[begin]);
return j;
}
void GetLeastNumbersPart(vector<int>& data , int k)
{
if(k < 1 || data.size() < k)
return;
int begin = 0 ;
int end = data.size() - 1;
int index = Partition(data , begin , end);
while(index != k - 1)
{
if(index > k)
{
begin = 0;
end = index - 1;
index = Partition(data , begin , end);
}
else
{
begin = index + 1;
end = data.size() - 1;
index = Partition(data , begin , end);
}
}
}
int main()
{
int num[] = {10 , 9 , 8 , 1 , 2 , 3 , 7 , 6 , 5 , 4};
int len = sizeof(num) / sizeof(*num);
vector<int> data(num , num + len );
GetLeastNumbersPart(data , 5);//找出最小的5个数字
for( int i = 0 ; i < 5 ; i++)
cout<<data[i]<<" ";
cout<<endl;
}
2、基于堆排序,
适合处理海量数据
时间复杂度:O(nlgk)
关于堆排序请参考:http://blog.youkuaiyun.com/u012243115/article/details/40474527 和 http://blog.youkuaiyun.com/u012243115/article/details/44198451 。这里使用algorithm库中的堆排序算法。
代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void GetLeastNumbersHeap(vector<int> &data , vector<int> &result , int k )
{
if( k < 1 || data.size() < k)
return;
for(int i = 0 ; i < data.size() ; i++)
{
if(i < k)
{
result.push_back(data[i]);//先把data的前k个数据放入result,然后再建堆
}
else
{
make_heap(result.begin() , result.end());//建堆使得堆顶最大(默认最大堆,找k个最小用最大堆,找k个最大用最小堆)
if(data[i] < result[0]) //和堆顶比较,如果比堆顶小,则替换掉堆顶
{
result[0] = data[i];
}
}
}
}
int main()
{
int num[] = {10 , 9 , 8 , 1 , 2 , 3 , 7 , 6 , 5 , 4};
int len = sizeof(num) / sizeof(*num);
vector<int> data(num , num + len );
vector<int> result;
GetLeastNumbersHeap(data , result , 5);
for(int i = 0 ; i < result.size() ; i++)
{
cout<<result[i]<<" ";
}
cout<<endl;
}
3、使用书中的multiset 。此时不能使用multiset的默认排序,要使用从大到小排序,原理同上
时间复杂度:O(nlgk) 。
代码:
#include <iostream>
#include <vector>
#include <set>
using namespace std;
typedef multiset<int , greater<int> > intSet;
typedef multiset<int , greater<int> >::iterator setIterator;
//使用具有自动排序功能的multiset,其实是基于红黑树
void GetLeastNumberRBTree(vector<int> &data , intSet &leastNumbers , int k)
{
leastNumbers.clear();
if( k < 1 || data.size() < k)
return;
vector<int>::iterator iter = data.begin();
for( ; iter != data.end() ; iter++)
{
if(leastNumbers.size() < k)
leastNumbers.insert(*iter);
else
{
setIterator iterGreatest = leastNumbers.begin();
if(*iter < *(leastNumbers.begin()))
{
leastNumbers.erase((iterGreatest));
leastNumbers.insert(*iter);
}
}
}
}
int main()
{
int num[] = {10 , 9 , 8 , 1 , 2 , 3 , 7 , 6 , 5 , 4};
int len = sizeof(num) / sizeof(*num);
vector<int> data(num , num + len );
intSet result2;
GetLeastNumberRBTree(data , result2 , 5);
setIterator iter = result2.begin();
for( ; iter != result2.end() ; iter++)
{
cout<<*iter<<" ";
}
cout<<endl;
}