剑指Offer之 - 最小的k个数

题目:

输入n个整数,找出其中最小的k个数。如输入4、5、1、6、2、7、3、8 这8个数字,则最小的 4 个数字是1、2、3、4

思路:

1、基于快排的思路,每排序一次可以确定一个数的位置,如果这个位置正好为k,则前k个数就是最小的k个数字 。

时间复杂度:O(n) ,注意此时会改变原来的数组

代码:

#include 
#include 
using namespace std;

//功能:找出最小的k个数
//使用快速排序找到下标为k的数即可,但是这样会改变原来的数组
int Partition(vector &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& 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 data(num , num + len );
	GetLeastNumbersPart(data , 5);//找出最小的5个数字
	for( int i = 0 ; i < 5 ; i++)
		cout<
2、基于堆排序, 适合处理海量数据

时间复杂度:O(nlgk)

关于堆排序请参考:http://blog.csdn.net/u012243115/article/details/40474527 和 http://blog.csdn.net/u012243115/article/details/44198451 。这里使用algorithm库中的堆排序算法。

代码:

#include 
#include 
#include 
using namespace std;

void GetLeastNumbersHeap(vector &data , vector &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 data(num , num + len );
	vector result;
	GetLeastNumbersHeap(data , result , 5);

	for(int i = 0 ; i < result.size() ; i++)
	{
		cout<

3、使用书中的multiset 。此时不能使用multiset的默认排序,要使用从大到小排序,原理同上

时间复杂度:O(nlgk) 。

代码:

#include 
#include 
#include 
using namespace std;

typedef multiset > intSet;
typedef multiset >::iterator setIterator;

//使用具有自动排序功能的multiset,其实是基于红黑树
void GetLeastNumberRBTree(vector &data , intSet &leastNumbers , int k)
{
	leastNumbers.clear();
	if( k < 1 || data.size() < k)
		return;
	vector::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 data(num , num + len );

	intSet result2;
	GetLeastNumberRBTree(data , result2 , 5);
	setIterator iter = result2.begin();
	for( ; iter != result2.end() ; iter++)
	{
		cout<<*iter<<" ";
	}
	cout<



你可能感兴趣的:(剑指Offer)