堆排序-在n個數中找出K個最大的數

在n個數中找出K個最大的數

主要思想:在n個數中找k個最大(小)的數,肯定要用到最小堆、最大堆的思想,而這種思想在C中STL中的優先隊列(priority_queue)中體現比較明顯,優先隊列底層實現就是運用了最大堆、最小堆原理,如果要求用c實現的話,可以直接用。如果用C語言實現的話,就需要自己定於堆的一系列操作,自己實現最大堆、最小堆。

實現一:C++實現

直接調用STL中的priority_queue.

vector<int>search_max_K(vector<int>vec,int k)
{
	priority_queue<int, vector<int>, greater<int> >que;

	for (int i = 0; i < k; i++)
		que.push(vec[i]);

	for (int i = k; i < vec.size(); i++)
	{
		if (vec[i]>que.top())
		{
			que.pop();
			que.push(vec[i]);
		}
	}

	vector<int>result;

	while (!que.empty())
	{
		result.push_back(que.top());
		que.pop();
	}

	return result;

}

注:STL中的堆的使用方法

STL裏面的堆操作一般用到的只有4個:make_heap();、pop_heap();、push_heap();、sort_heap(); 他們的頭文件函數是#include <algorithm>

(1)make_heap();函數原型是:void make_heap(first_pointer,end_pointer,compare_function);

一個參數是數組或向量的頭指針,第二個是數組或向量的尾指針(注意這裏是尾後指針或尾後迭代器,而不是最後一個元素的地址)。第三個參數是比較函數,在缺省的時候,默認是大跟堆(注意如果要自定義比較函數話:最大堆用小於函數;最小堆用大於函數)。

作用:把這一段的數組或向量做成一個堆的結構。堆的範圍是[first,last) 注意不包括last尾後指針或尾後迭代器

(2)pop_heap();函數原型是:void pop_heap(first_pointer,end_pointer,compare_function);

作用:pop_heap()不是真的把最大(最小)的元素從堆中彈出來。而是重新排序堆。它把first和last-1這兩個堆元素交換位置,然後將[first,last-1)的之間的元素做成一個堆,不包括last-1。

(3)push_heap();函數原型是: void pushheap(first_pointer,end_pointer,compare_function);

作用:push_heap()假設由[first,last-1)是一個有效的堆,然後,再把堆中的新元素last-1加進來,做成一個堆,堆的範圍變成[first,last)。

(4)用的不多。sort_heap();函數原型是:void sort_heap(first_pointer,end_pointer,compare_function);

作用:sort_heap對[first,last)中的序列進行排序。它假設這個序列是有效堆。(當然,經過排序之後就不是一個有效堆了)

linkhttps://blog.csdn.net/my_lovely_lemon_tree/article/details/78007316

linkhttps://blog.csdn.net/xiajun07061225/article/details/8553808

實現二:C語言實現

手動實現最小堆所有操作(堆的插入、刪除、調整、建立等操作)

主要的函數:

vector<int>Get_Max_K(vector<int>vec, int k)
{
	vector<int>num_k(vec.begin(), vec.begin()+k);
	CreatHeap(&num_k[0], k);

	for (int i = k; i < vec.size(); i++)
	{
		if (vec[i]>=num_k[0])
		{
			num_k[0] = vec[i];
			HeapAdjust(&num_k[0], 0, k);
		}

	}

	vector<int>result(num_k.begin(), num_k.begin()+k);

	return result;

}

定義的子函數:

#include<iostream>
#include<functional>
#include<vector>
#include<set>
#include<queue>
#include<hash_map>

using namespace std;


//hash_map<const char*, int>f_ip;
void HeapAdjust(int *heap, int top, int n);

vector<int>search_max_K(vector<int>vec,int k)
{
	priority_queue<int, vector<int>, less<int> >que;

	for (int i = 0; i < k; i++)
		que.push(vec[i]);

	for (int i = k; i < vec.size(); i++)
	{
		if (vec[i]<que.top())
		{
			que.pop();
			que.push(vec[i]);
		}
	}

	vector<int>result;

	while (!que.empty())
	{
		result.push_back(que.top());
		que.pop();
	}

	return result;

}

//自己寫最小堆進行實現,其中包括插入、刪除、調整等子操作


//堆的插入
/*

* 堆插入算法。(小頂堆)

* 先將num插入堆尾,易知從新數據的父結點到根結點是一個有序的序列,

* 將num插入到該有序序列當中,該過程爲直接插入排序。

* 未插入前數據長度爲n。

*/

void HeapInsert(int *heap, int n, int num)

{

	int i, j;



	heap[n] = num;//num插入堆尾

	i = n;

	j = (n - 1) / 2;//j指向i的父結點



	//注意不要漏掉i!=0的條件。因爲必須保證i有父結點j。j>=0並不能保證i!=0。

	//如果沒有此條件,當i=0時,j=0,若heap[0]>num,程序就會陷入死循環。

	while (j >= 0 && i != 0)

	{

		if (heap[j] <= num)

			break;

		heap[i] = heap[j];

		i = j;

		j = (i - 1) / 2;

	}

	heap[i] = num;

}


//堆元素的刪除
/*

* 堆刪除算法。(刪除堆頂元素)

* n表示未刪除前堆中數據的總數。

*/

void HeapDelete(int *heap, int n)

{

	//使用堆尾元素直接覆蓋堆頂元素。

	heap[0] = heap[n - 1];

	//從堆頂到堆尾(此時堆中只有n-1個元素)進行堆調整。

	HeapAdjust(heap, 0, n - 1);

}



/*

* 堆調整算法。(小頂堆)

* 已知heap[top]結點的左右子樹均爲堆,調整堆中元素,使以heap[top]爲根結點的樹爲堆。

* n爲堆中元素總數。

*/

void HeapAdjust(int *heap, int top, int n)

{

	int j = 2 * top + 1;    //左孩子結點

	int temp = heap[top];



	while (j < n)

	{

		if (j + 1 < n&&heap[j + 1] < heap[j])

			j++;    //使j指向左右孩子中較小的結點。

		if (heap[j] >= temp)

			break;

		heap[top] = heap[j];

		top = j;

		j = 2 * top + 1;

	}

	heap[top] = temp;


}



//堆的建立

/*

* 建堆算法。

* 將無序數組array[]轉換爲堆。

*/

void CreatHeap(int *array, int n)

{

	int i;

	//最後一個結點的編號爲n-1,該結點的父節點(n-2)/2爲最後一個非終端結點。
	//但是感覺這裏的n不是頂點的個數,而應該是存儲數組最後一個的索引,即最後一個頂點對應數組中的位置。

	//從結點(n-2)/2到根結點,依次進行堆調整。

	for (i = (n - 2) / 2; i >= 0; i--)

	{

		HeapAdjust(array, i, n);

	}

}


vector<int>Get_Max_K(vector<int>vec, int k)
{
	vector<int>num_k(vec.begin(), vec.begin()+k);
	CreatHeap(&num_k[0], k);

	for (int i = k; i < vec.size(); i++)
	{
		if (vec[i]>=num_k[0])
		{
			num_k[0] = vec[i];
			HeapAdjust(&num_k[0], 0, k);
		}

	}

	vector<int>result(num_k.begin(), num_k.begin()+k);

	return result;

}

int main()
{
	int a[] = { 1, 2, 1, 3, 4, 5, 6, 9, 6, 9, 4, 9 };

	vector<int>vec(a,a+12);

	//vector<int>result = search_max_K(vec, 4);
	vector<int>result = Get_Max_K(vec, 4);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章