基於快排和堆排的TopK算法


TopK算法,用於尋找若干個數據中最大或最小的K個數。

實現TopK有兩種方法,一種是基於快排的思想,一種是基於堆排的思想。

他們區別在於:

快排:時間復雜度O(n) 需要修改輸入數組 不能處理海量數據,因為內存不夠加載

堆排:時間復雜度O(nlogk) 不需要修改輸入數組 可以處理海量數據

基於快排的TopK:

快排中最重要的一點就是Partition函數,Partition使pos左側數據均小於num[pos],右側均大於num[pos]。

如果我們要找數組的TopK,其實只要找到Partition返回分界K的那個點時,該位置pos右側(或左側)即滿足要求。

如果某次Partition的返回值不等於分界點,則根據分界點與pos的關系繼續Partition:

如果pos在k外,即pos包括的區間內有大於K的數據,則在pos+1和k間重新Partition

如果pos在k內,即pos包括的區間內的數據個數小於K,則在k和pos-1間重新Partition

class Solution
{
public:
	void TopK_Qsort(vector<int>& arr,int k)
	{
		if(arr.empty()||arr.size()<=k)
			return;
		int pos=Partition(arr,0,arr.size()-1);
		int addr=arr.size()-1-k+1;
		while(pos!=addr)
		{
			if(pos<addr)
			{
				pos=Partition(arr,pos+1,addr);//當前區間過大,將舊區間減1后再在其中找分界點
			}
			else
			{
				pos=Partition(arr,addr,pos-1);//當前區間過小,將pos-1后再在其中找分界點
			}
		}
		for(int i=pos;i<arr.size();i++)
			cout<<arr[i]<<endl;
	}
private:
	int Partition(vector<int>& arr,int low,int high)
	{
		int tmp=arr[low];
		while(low<high)
		{
			while(high>low&&arr[high]>=tmp)
				high--;
			arr[low]=arr[high];
			while(low<high&&arr[low]<=tmp)
				low++;
			arr[high]=arr[low];
		}
		arr[high]=tmp;
		return high;
	}
};

 基於堆排的TopK:

  基於堆排的TopK思想很簡單,以尋找最大的K個數為例:首先使用輸入數組的前k個數構造一個小頂堆,然后從輸入數組的第k+1個數開始,與小頂堆的根進行對比。

  1)如果大於小頂堆的根,說明這個數比根更適合最大的K個數,則將小頂堆的根設置為這個新值,然后重新調整堆。

  2)如果小於或等於小頂堆的根,說明這個數比根,也就是當前K個數里最小的一個相比沒有優勢,因此不用調整,進行下一個數的判斷。

class Solution
{
public:
	void TopK_Heap(vector<int>& arr,int k)
	{
		if(arr.size()<=k)
			return;
		vector<int> box;
		box.resize(k);
		for(int i=0;i<k;i++)
			box[i]=arr[i];
		for(int i=box.size()/2;i>=0;i--)
			HeapAdjust(box,i);
		for(int i=k;i<arr.size();i++)
		{
			if(arr[i]>box[0])
			{
				box[0]=arr[i];
				HeapAdjust(box,0);
			}
		}
		for(int i=0;i<box.size();i++)
			cout<<box[i]<<endl;

	}
private:
	void HeapAdjust(vector<int>& nums,int pos)
	{
		for(int i=2*pos+1;i<nums.size();i=2*i+1)
		{
			if(i<nums.size()-1&&nums[i]>nums[i+1])
				i++;
			if(nums[i]>=nums[pos])
				break;
			swap(nums[i],nums[pos]);
			pos=i;
		}
	}
};

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM