尋找第n個數 與前n個數的幾種方法

尋找第n個數 與前n個數的幾種方法

<span style="font-size:18px;">#include<iostream>
#include<string>
#include<functional>
#include<iterator>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<cassert>
using namespace std;
//平均情況 O(n)
//前nth-1個元素是無序的 可以調快排
int NthElement(int* p,int left, int right, int nth);
int partition(int* p,int left, int right);
//O(nlogn) 
const vector<int>* PartSortByqueue(int *p, int len,int k);
const vector<int>* PartSortByheap(int *p, int len, int k);
const vector<int>* PartSortBymultiset(int *p, int len, int k);
template<class T>
class display
{
public:
	void operator()(const T& val)
	{
		cout << val << " ";
	}
};
//劃分函數 返回軸值所在下標
int partition(int* p,int left, int right)
{
	assert(nullptr!=p);
	if (left > right)
	{
		return -1;
	}
	//軸值選取可以優化 否則會增大惡化概率
	int key = p[left];
	int i = left, j = right;
	while (i < j)
	{
		while (i < j&&p[j] >= key)
		{
			--j;
		}
		p[i] = p[j];
		while (i < j&&p[i] <= key)
		{
			++i;
		}
		p[j] = p[i];
	}
	p[i] = key;//很容易忘記這一句
	return i;
}
//left right 爲閉區間 nth 爲第n個元素 從1開始
int NthElement(int* p,int left, int right, int nth)
{
	assert(nullptr != p);
	assert(left >= 0 && right >= 0 && nth > 0);
	assert(left <= right&&nth>left&&nth<=right+1);
	int index = partition(p, left, right);
	if (index > nth - 1)
	{
		NthElement(p,left,index-1,nth);
	}
	else if (index < nth - 1)
	{
		NthElement(p, index+1, right, nth);
	}
	else
	{
		return p[index];
	}
}
//使用堆(STL priority_queue)來求k個最大的數
const vector<int>* PartSortByqueue(int *p, int len,int k)
{
	assert(nullptr != p&&len>0&&k>0&&k<=len);
	//先將數組前k個元素建堆
	priority_queue<int>* pPr= new priority_queue<int>(p,p+k);
	//默認小根堆 最小元素在begin處
	assert(nullptr!=pPr);
	for (int i = k; k < len; ++k)
	{
		//新元素比最小元素小 則將該元素彈出 壓入新元素
		if (p[k] > pPr->top())
		{
			pPr->pop();
			pPr->push(p[k]);
		}
	}
	vector<int>* pVec = new vector<int>();
	pVec->reserve(len);
	assert(nullptr!=pVec);
	//priority_queue 不提供遍歷與迭代器 只能pop
	while (!pPr->empty())
	{
		pVec->push_back(pPr->top());
		pPr->pop();
	}
	copy(pVec->begin(), pVec->end(), ostream_iterator<int>(cout, " "));
	puts("");
	delete  pPr;
	return pVec;
}

//使用STL提供的堆算法 與vector 結合
const vector<int>* PartSortByheap(int *p, int len, int k)
{
	assert(nullptr != p&&len>0 && k>0 && k <= len);
	vector<int>* pVec=new vector<int>(p,p+k);
	//默認小根堆
	assert(nullptr != pVec);
	make_heap(pVec->begin(), pVec->end(),less<int>());
	for (int i = k; i < len; ++i)
	{
		if (p[i] > (*pVec)[0])
		{
			//默認也是小根堆
			pop_heap(pVec->begin(),pVec->end(),less<int>());
			/*
			begin() 與end()-1 交換 最小元素已在最末位置
			然後在區間first last-1 調用adjust_heap算法
			*/
			//將末尾元素彈出
			pVec->pop_back();
			//上邊完成堆得pop過程 下邊完成push過程
			pVec->push_back(p[i]);
			push_heap(pVec->begin(),pVec->end(),less<int>());
		}
	}
	copy(pVec->begin(), pVec->end(), ostream_iterator<int>(cout, " "));
	puts("");
	return pVec;
}

const vector<int>* PartSortBymultiset(int *p, int len, int k)
{
	assert(nullptr != p&&len>0 && k>0 && k <= len);
	multiset<int, less<int>> mset(p,p+k);
	for (int i = k; k < len; ++k)
	{
		if (p[i] > (*mset.begin()))
		{
			mset.insert(p[i]);
			mset.erase(mset.begin());
		}
	}
	vector<int>* pVec = new vector<int>(mset.rbegin(), mset.rend());
	assert(nullptr != pVec);
	copy(pVec->begin(), pVec->end(), ostream_iterator<int>(cout, " "));
	puts("");
	return pVec;
}

int main(void)
{
	int array[] = { 10,11,9,3,1,5,7,4,2};
	int len = sizeof(array) / sizeof(array[0]);
	/*
	cout << "NthElement  :" << NthElement(array, 0, len - 1,2) << endl;
	//左邊與右邊不保證有序
	for_each(array, array + len, display<int>());
	puts("");
	*/
	delete PartSortByqueue(array,len,3);
	delete PartSortByheap(array,len,3);
	delete PartSortBymultiset(array,len,3);
	return 0;
}</span>


点赞