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 

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 

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;

}

你可能感兴趣的:(数据结构,topk,数据结构与算法,c++)