#用堆排序(最小堆):top-k最大的数字
题目:top-k算法,从n个大小的数组中,找出k个最大的数字并输出
输入:数组大小n=10;k的值为5;数组为:9,8,3,2,10,20,13,1,5
输出:20,13,10,9,8
思路:1、维护k个最小堆,如果某个新进来的数字大于最小堆的根节点,那么将根节点换为新进来的数字,然后在对最小堆进行调整。
2、在找出k个大的数字后,对k个大的数字进行一次堆排序,因为我们做的是最小堆,所以堆排序后得到的序列就是升序的序列
Ps:堆排序的平均时间复杂度都为O(n*logn),它比快排好的地方是,快排在最坏的情况下(数组已有序)时间复杂度为O(n^2)
/*
题目:堆排序的用法:
1、利用堆排序从n个数字中取出top-k个最大的数字
2、主要使用最小堆,维护k个大小的最小堆
*/
#include<iostream>
#include<vector>
using namespace std;
void headAdjust(vector<int> &arr, int start, int end){
//i这里指向的是左子树
int i = start * 2 + 1;
while (i <= end){
//先找左右子树中最小的
if (i + 1 <= end&&arr[i] > arr[i + 1]){
//如果左子树大于右子树,则i指向右子树
i++;
}
if (arr[start] > arr[i]){
swap(arr[start], arr[i]);
start = i;
i = 2 * start + 1;
}
else{
break;
}
}
}
void heapSort(vector<int> &arr, int start, int end){
//堆排序是从第一个非叶节点开始从下往上更新,直到更新到根节点为止
for (int i = (end - 1) / 2; i >= 0; i--){
headAdjust(arr,i,end);
}
//下面进行堆排序,进行堆排序的时候,因为上面已经调整过一遍堆了,这次只是替换了堆顶元素,所以只需要对堆顶元素进行一次调整即可。
for (int i = end; i-1 >= 0; i--){
swap(arr[i], arr[0]);
headAdjust(arr, 0, i-1);
}
}
int main(){
//堆排序维护k个大小的最小堆
int k;
int n;
cin >> n;
cout << "top-k的值为:";
cin >> k;
cout << "依次输入数组,然后找出top-" << k << "个值" << endl;
vector<int> arr(k,0);
for (int i = 0; i < n; i++){
if (i > k - 1){
int temp;
cin >> temp;
if (temp > arr[0]){
arr[0] = temp;
headAdjust(arr, 0, k - 1);
}
}
else{
int temp;
cin >> temp;
arr[i] = temp;
if (i == k - 1){
//这里先建堆
for (int j = (k - 1 - 1) / 2; j >= 0; j--) {
heapAdjust(arr, j, k-1);
}
}
}
}
//对堆进行最小堆排序
heapSort(arr, 0, k - 1);
for (int i = 0; i < arr.size(); i++){
cout << arr[i];
if (i < arr.size()-1){
cout << " ";
}
}
system("pause");
return 0;
}