题目:给定一个数组,求取前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;
}