topk問題c++

題目:給定一個數組,求取前k個最大的數。返回的k個數不要求有序。

topk大問題:
1.先利用快排或者堆排序進行全局排序後取前k個數即可。時間複雜度爲o(nlogn)+o(k)
2.利用快排的思路
(1)先選擇一個劃分基準,然後依次遍歷數組,將大於劃分基準的數放在左邊,小於劃分基準的數放在右邊
(2)記左邊序列和劃分基準的元素個數爲len,如果len等於k,則已經找到;如果len小於k,則需要在右邊的
序列中找len-k個最大數;如果len大於k,則需要在左邊的序列中找k個最大數。依次遞歸找到topk。
時間複雜度爲o(nlogk)
3.利用堆排序的思路,找topk大利用最小堆,找topk小利用最大堆
(1)先去數組的前k個元素建立最小堆
(2)從第k+1個元素開始遍歷,如果當前元素比小堆頂元素大,則交換,然後調整堆。
時間複雜度爲o(nlogk)
如果給定的數據量很大的情況大,不能直接將數據加載到內存當中時,採用堆排序的方法。

尋找topk小的思路也一樣,就是利用最大堆,如果如果當前元素比大堆頂小,則交換。

下面給出第2,3方法的實現topk大。

#include "pch.h"
#include <iostream>

using namespace std;

//交換元素的函數
void swap(int a[], int i, int j)
{
	int temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}

/**********************利用快排思想***************************************/
/*
功能:找到劃分基準的位置
參數:
	-a:輸入的數組
	-first:起始下標
	-last:最後下標
返回:
	劃分基準的位置
*/
int partiton(int a[], int first,int last)
{
	int storeIndex = first;//當前存儲位置
	//選擇last作爲劃分基準
	for (int i = first; i < last; i++)
	{
		if (a[i] > a[last])
		{
			swap(a, storeIndex, i);
			storeIndex++;
		}
	}
	//將last與當前儲存位置交換
	swap(a, storeIndex, last);

	return storeIndex;

}

/*
功能:找到topk大,a[0]-a[k-1]
參數:
	-a:輸入的數組
	-first:起始下標
	-last:最後下標
	-k:要找的前最大元素個數
返回:
	無
*/
void quickFindMaxK(int a[], int first, int last, int k)
{
	int p = partiton(a, first, last);//尋找劃分基準位置
	int len = p - first + 1;//記錄左邊序列與劃分基準的元素個數
	if (len == k)
		return;
	else if (len < k)
		quickFindMaxK(a, p + 1, last, k - len);
	else
		quickFindMaxK(a, first, p-1, k);
}

int main()
{
	int a[5] = { 1,2,7,8,5 };
	int k = 3;
	quickFindMaxK(a, 0, 4, k);
	for (int i = 0; i < k; i++)
		cout << a[i] << " ";
	cout << endl;

}
#include "pch.h"
#include <iostream>

using namespace std;

//交換元素的函數
void swap(int a[], int i, int j)
{
	int temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}

/**********************利用最小堆思想***************************************/
/*
功能:調整堆成爲最小堆
參數:
	-a:輸入的數組
	-len:數組長度
	-i:待調整的元素下標
返回:
	無
*/
void adjustHeap(int a[], int len,int i)
{
	int minIndex = i;
	//如果左節點值比父節點小
	if (2 * i + 1 < len&&a[2 * i + 1] < a[i])
		minIndex = 2 * i + 1;
	//如果右節點值比父節點小
	if (2 * i + 2 < len&&a[2 * i + 1] < a[i])
		minIndex = 2 * i + 1;
	if (minIndex != i)
	{
		swap(a, minIndex, i);
		//重新調整堆
		adjustHeap(a, len, minIndex);
	}

}

/*
功能:建立最小堆
參數:
	-a:輸入的數組
	-len:數組長度
返回:
	無
*/
void buildMinHeap(int a[], int len)
{
	//從最後一個非葉子節點從下往上建立最小堆
	for (int i = (len - 2) / 2; i >= 0; i--)
		adjustHeap(a, len, i);
}

/*
功能:找出topk大,a[0]-a[k-1]
參數:
	-a:輸入的數組
	-len:數組長度
	-k:最大元素個數
返回:
	無
*/
void heapFindMaxK(int a[], int len,int k)
{
	//用前k個元素建立最小堆
	buildMinHeap(a, k);
	for (int i = k; i < len; i++)
	{
		if (a[i] > a[0])
		{
			swap(a, 0, i);
			adjustHeap(a, k, 0);
		}
	}

}

int main()
{
	int a[5] = { 1,2,7,8,5 };
	int k = 3;
	heapFindMaxK(a,5, k);
	for (int i = 0; i < k; i++)
		cout << a[i] << " ";
	cout << endl;

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章