题目:输入N个整数,找出其中最小的k个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4.
方案一:就是先对数组进行排序,然后输出前K个数字。时间复杂度为O(N*logN)
方案二:根据[29]中数字超过一半的启发,我们可以用基于快速排序的思想,对其进行划分 ,时间复杂度为O(N)。找出前K小个元素,我们只需要利用Partion函数将小于X的前k个元素移动到X的前面就可以了。顺序输出这K个元素就是所求,可能不是有序的。
方案三:O(N*logN)的算法。适合处理海量的数据。
我们可以创建一个大小为K的容器来存储最小的K个数,接下来我们每次从输入的N个整数中读入一个数。如果容器中已有的数字少于K个,我们直接把这次读入的整数放入容器中;如果容器已满,也就是说容器中已有K个元素,此时我们不能在插入新的数字而只能是替换已有的数子。找出已有数据中的最大的数据,如果待插入的数据比该数据还大,则不可能是前K个最小的元素,舍弃;反之,则将其与最大元素进行替换。
容器满了以后我们要做三件事:第一,在K个元素中找到最大的元素;第二,有可能在这个容器中删除最大数;第三,有可能插入一个新的数据。如果用一个二叉树来实现该数据容器,则我们可以在O(logK)的时间内完成寻找,插入,删除操作。对于输入的N个元素,总的时间效率就是 O(N*logK)。例如最大堆和二叉树都是可以的。
这里如果可以用STL,我么不妨选择set和multiset来完成,因为它们都是基于红黑树实现的,严格控制了操作时间复杂度为O(logN)。
但是set和multiset的区别是:set插入的元素不能相同,但是multiset可以相同。
注意;方案二是会修改原数据的位置的,但是方案三不会修改,并且适合处理海量的数据。它是将数据读出来,在容器里操作。
方案二实现代码:
方案一:就是先对数组进行排序,然后输出前K个数字。时间复杂度为O(N*logN)
方案二:根据[29]中数字超过一半的启发,我们可以用基于快速排序的思想,对其进行划分 ,时间复杂度为O(N)。找出前K小个元素,我们只需要利用Partion函数将小于X的前k个元素移动到X的前面就可以了。顺序输出这K个元素就是所求,可能不是有序的。
方案三:O(N*logN)的算法。适合处理海量的数据。
我们可以创建一个大小为K的容器来存储最小的K个数,接下来我们每次从输入的N个整数中读入一个数。如果容器中已有的数字少于K个,我们直接把这次读入的整数放入容器中;如果容器已满,也就是说容器中已有K个元素,此时我们不能在插入新的数字而只能是替换已有的数子。找出已有数据中的最大的数据,如果待插入的数据比该数据还大,则不可能是前K个最小的元素,舍弃;反之,则将其与最大元素进行替换。
容器满了以后我们要做三件事:第一,在K个元素中找到最大的元素;第二,有可能在这个容器中删除最大数;第三,有可能插入一个新的数据。如果用一个二叉树来实现该数据容器,则我们可以在O(logK)的时间内完成寻找,插入,删除操作。对于输入的N个元素,总的时间效率就是 O(N*logK)。例如最大堆和二叉树都是可以的。
这里如果可以用STL,我么不妨选择set和multiset来完成,因为它们都是基于红黑树实现的,严格控制了操作时间复杂度为O(logN)。
但是set和multiset的区别是:set插入的元素不能相同,但是multiset可以相同。
注意;方案二是会修改原数据的位置的,但是方案三不会修改,并且适合处理海量的数据。它是将数据读出来,在容器里操作。
方案二实现代码:
#include <iostream>
using namespace std;
int arr[8]={4,5,1,6,2,7,3,8};
void Swap(int &a,int &b)
{
int temp=a;
a=b;
b=temp;
}
int Partion(int *array,int length,int low,int high)
{
while (low <high)
{
while(low<high && array[high]>=array[low])
high--;
Swap(array[high],arr[low]);
while(low < high && array[low]<=array[high])
low++;
Swap(array[low],array[high]);
}
return low;
}
int GetLeastNumbers(int *input,int *output,int k,int length)
{
if(NULL==input ||NULL==output || length<=0 || k>length || k<=0)
return 0;
int low=0;
int high=length-1;
int index=Partion(input,length,low,high);
while(index!=k-1)
{
if(index>k)
{
high=index-1;
index=Partion(input,length,low,high);
}
else
{
low=index+1;
index=Partion(input,length,low,high);
}
}
for(int i=0;i<k;i++)
output[i]=input[i];
}
int main()
{
int *result=new int[4];
GetLeastNumbers(arr,result,4,8);
cout<<"最小的4个数是:";
for(int i=0;i<4;i++)
cout<<result[i]<<" ";
delete []result;
cout<<endl;
system("pause");
return 0;
}
运行结果为:
#include <iostream>
#include <vector>
#include <set>
using namespace std;
int arr[8]={4,5,1,6,2,7,3,8};
vector<int > v1(arr,arr+8);
vector<int>::iterator it;
multiset<int,greater<int>> intSet;
multiset<int,greater<int>>::iterator itset;
//这个对象里面存贮的元素是从小到大排序的,(因为用std::less作为比较工具);
//如果是最大的元素:则是std::greater
int GetLeastNumbers(const vector<int> & vec,multiset<int,greater<int>> &leastNumbers,int k)
{
leastNumbers.clear();
if( k<=0|| vec.size()<k)
return 0;
vector<int>::const_iterator it1=vec.begin();
for(;it1!=vec.end();it1++)
{
if(leastNumbers.size()<k)
leastNumbers.insert(*it1);
else
{
itset=leastNumbers.begin();
if(*it1<*(leastNumbers.begin()))
{
leastNumbers.erase(itset);
leastNumbers.insert(*it1);
}
}
}
}
int main()
{
int i=0;
GetLeastNumbers(v1,intSet,4);
cout<<"原数据:";
for(it=v1.begin();it!=v1.end();it++)
cout<<*it<<" ";
cout<<endl<<"前4小的数据:";
for(itset=intSet.begin();itset!=intSet.end();itset++)
cout<<*itset<<" ";
cout<<endl;
system("pause");
return 0;
}
运行结果: