堆排序与TopK问题c++源码

#include <iostream>
using namespace std;
#include <vector>

//调整数组v以i位置为根的子树为小根堆,数组堆的范围0到k-1
void HeadAdjustDown(vector<int>& v, int i, int k);
//对前k个元素建立小根堆
void BuildMinHeap(vector<int>& v, int k);
//取最小k个数
void GetLeastNumbers_Solution(vector<int>& input, int k);

//调整数组v以i位置为根的子树为大根堆,数组堆的范围0到k-1
void HeadAdjustUp(vector<int>& v, int i, int k);
//对前k个元素建立大根堆
void BuildMaxHeap(vector<int>& v, int k);
//取最大k个数
void GetMostNumbers_Solution(vector<int>& input, int k);

//堆排序从小到大
void MinHeapSort(vector<int>& v);
//堆排序从大到小
void MaxHeapSort(vector<int>& v);


int main() {
    vector<int> v;
    v.push_back(53);
    v.push_back(17);
    v.push_back(78);
    v.push_back(9);
    v.push_back(45);
    v.push_back(65);
    v.push_back(87);
    v.push_back(32);

    int k = 8;
    
    cout << "这是原始数组:";
    for (auto& a : v) {
        cout << a << " ";
    }
    cout << endl;

    GetLeastNumbers_Solution(v,5);
    GetMostNumbers_Solution(v,5);

    MaxHeapSort(v);
    MinHeapSort(v);

    return 0;
}

//调整数组v以i位置为根的子树为小根堆,数组堆的范围0到k-1
void HeadAdjustDown(vector<int>& v, int i, int k) {
    int tmp = v[i];
    //调整v[i]节点为根的子树,v[i]的左右孩子为v[2i+1]和v[2i+2]
    for (int j = 2 * i + 1; j < k; j = 2 * j + 1) {
        if (j + 1 < k && v[j] > v[j + 1]) {
            //在右孩子存在的情况下
            //左孩子小,j就已经指向左孩子
            //右孩子小,那么让j指向右孩子,也就是j++
            j++;
        }
        if (tmp < v[j])
            break;//根节点本来就比左右孩子小
        else {
            v[i] = v[j]; //左右孩子中最小的数往上提
            i = j; //让i指向它的左右孩子中最小的
        }
    }
    v[i] = tmp;
}

//对前k个元素建立小根堆
void BuildMinHeap(vector<int>& v,int k) {
    //前k个数下标0到k-1  最后一个非叶子节点下标是(k - 1)/2      
    for (int i = (k - 1) / 2; i >= 0; i--) {
        //从最后一个非叶子节点开始逐个调整建立小根堆
        HeadAdjustDown(v, i, k);
    }
}

//取最小k个数 
void GetLeastNumbers_Solution(vector<int>& input, int k) {
    BuildMaxHeap(input, k);
    for (int i = k; i < input.size(); i++) {
        if (input[i] >= input[0])
            continue;
        else {
            int tmp = input[0];
            input[0] = input[i];
            input[i] = tmp;

            HeadAdjustUp(input, 0, k);
        }
    }
    vector<int> v;
    for (int i = 0; i < k; i++) {
        v.push_back(input[i]);
    }
    cout << "数组最小k个数:";
    for (auto& a : v) {
        cout << a << " ";
    }
    cout << endl;
}

//调整数组v以i位置为根的子树为大根堆,数组堆的范围0到k-1
void HeadAdjustUp(vector<int>& v, int i, int k) {
    int tmp = v[i];
    //调整v[i]节点为根的子树,v[i]的左右孩子为v[2i+1]和v[2i+2]
    for (int j = 2 * i + 1; j < k; j = 2 * j + 1) {
        if (j + 1 < k && v[j + 1] > v[j]) {
            j++;
        }
        if (tmp > v[j])
            break;
        else {
            v[i] = v[j];
            i = j;
        }
    }
    v[i] = tmp;
}

//对前k个元素建立大根堆
void BuildMaxHeap(vector<int>& v, int k) {
    //前k个数下标0到k-1  最后一个非叶子节点下标是(k - 1)/2      
    for (int i = (k - 1) / 2; i >= 0; i--) {
        //从最后一个非叶子节点开始逐个调整建立小根堆
        HeadAdjustUp(v, i, k);
    }
}

//取最大k个数
void GetMostNumbers_Solution(vector<int>& input, int k) {
    BuildMinHeap(input, k);
    for (int i = k; i < input.size(); i++) {
        if (input[i] <= input[0])
            continue;
        else {
            int tmp = input[0];
            input[0] = input[i];
            input[i] = tmp;
    
            HeadAdjustDown(input, 0, k);
        }
    }
    vector<int> v;
    for (int i = 0; i < k; i++) {
        v.push_back(input[i]);
    }
    cout << "数组最大k个数:";
    for (auto& a : v) {
        cout << a << " ";
    }
    cout << endl;
}

//堆排序从小到大
void MinHeapSort(vector<int>& v) {
    int len = v.size();
    while (len) {
        BuildMaxHeap(v, len);
        swap(v[0], v[len-1]);
        len--;
    }
    cout << "堆排序从小到大:";
    for (auto& a : v) {
        cout << a << " ";
    }
    cout << endl;
    
}
//堆排序从大到小
void MaxHeapSort(vector<int>& v) {
    int len = v.size();
    while (len) {
        BuildMinHeap(v, len);
        swap(v[0], v[len-1]);
        len--;
    }
    cout << "堆排序从大到小:";
    for (auto& a : v) {
        cout << a << " ";
    }
    cout << endl;    
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值