数据结构-最大值堆构建过程

  • 二叉堆(Binary Heap)
    • 二叉堆是一颗完全二叉树
    • 堆中某个节点的值总是大于等于(或小于等于)其子节点, 对应的就是最大堆和最小堆
      可以用数组存储二叉堆,数组以1下标开始
      在这里插入图片描述
      数组以下标0开始:
      在这里插入图片描述

操作

添加元素

  1. 在数组的最后一个位置添加一个新元素
  2. 新的元素进行上浮(Sift Up), 上浮操作如下图:
    在这里插入图片描述

取出元素

堆每次只能取出最大的元素, 具体取出元素的步骤如下 :

  • 将堆的根节点与最后一个元素交换位置
  • 删除最后的一个元素, 此时最后一个元素位于根节点
  • 如果左右子节点不小于现在的根节点, 则将现有根节点和左右子节点中较大的那个交换位置
  • 重复上一步, 直到不再需要最后的那个节点找到它应该存放的位置, 示意图如下:
    在这里插入图片描述

初始化最大值堆

  • 首先将数组当成一个完全二叉树
  • 找到最后一个非叶子节点, 方法是根据最后一个元素计算其父节点
  • 从最后一个非叶子节点之前的节点都执行Sift Down操作
    在这里插入图片描述

C++代码实现

//构建最大值堆  堆排序
// 使用动态数组实现最大值堆,这里使用vector实现
// 数组下标以1开始时,父节点parent(i)=i/2  左孩子=2*i  右孩子=2*i+1
// 数组下标以0开始时,父节点parent(i)=(i-1)/2  左孩子=2*i+1  右孩子=2*i+2
// 这里使用下标0开始
class MaxHeap{
    private:
        vector<int> data;  //动态数组保存堆元素

        int getParent(int index); //返回下标index节点的父节点
        int getLeftChild(int index);// 返回下标为index节点的左孩子
        int getRightChild(int index);// 返回下标为index节点的右孩子
        void siftUP(int index); // 下标为index节点上浮
        void siftDown(int index); // 节点下沉
    public:
        MaxHeap(vector<int>& nums);
        void insert(int value); // 向最大堆插入元素
        int pop(); // 取出最大元素
        bool empty();  // 最大值堆是否为空
        void printHeap();
};
// 默认构建最大值堆,找到最后一个非叶子节点(最后一个节点父节点 getParent(data.size() - 1))
// 然后从最后一个非叶节点之前节点都执行下沉操作,则可以保证具有最大值性质
MaxHeap::MaxHeap(vector<int>& nums){
    for(int val : nums){
        data.push_back(val);
    }
    for(int i = getParent(data.size() - 1); i >= 0; --i){
        siftDown(i);
    }
}
int MaxHeap::getParent(int index){
    if(index == 0){
        cout<<"下标为0的节点不存在父节点!!!"<<endl;
        return -1;
    }
    return (index - 1) / 2;
}
int MaxHeap::getLeftChild(int index){
    return 2 * index + 1;
}
int MaxHeap::getRightChild(int index){
    return 2 * index + 2;
}
bool MaxHeap::empty(){
    return data.empty();
}
//向最大值堆插入元素:在数组最后一个位置添加新元素,然后新元素进行上浮
void MaxHeap::insert(int value){
    data.push_back(value);
    siftUP(data.size() - 1);
}
// 取出元素,每次只能取出最大元素:
// 将堆最后一个节点和根节点交换位置
// 删除最后一个元素,即删除最大元素
// 然后将根节点进行下沉
int MaxHeap::pop(){
    if(empty()){
        cout<<"当前堆为空, 无最大值!!!"<<endl;
        return -1;
    }
    int res = data[0]; //获得最大值
    swap(data[0],data[data.size()-1]);// 将最大值和最后一个叶子节点交换位置, 即用最后一个叶子节点替换了根节点
    data.erase(data.end() - 1);// 删除最后一个叶子节点, 即删除了最大值
    siftDown(0);//现在根节点下沉
    return res;
}
// 节点上浮: 让插入的数和父节点的数值比较,当大于父节点时就和父节点交换
void MaxHeap::siftUP(int index){
    while(index != 0 && (data[getParent(index)] < data[index])){
        swap(data[index],data[getParent(index)]);
        index = getParent(index);
    }
}
// 节点下沉
void MaxHeap::siftDown(int index){
    while(getLeftChild(index) < data.size()){ // 一直往下沉,直到到叶子节点
        int swapindex = getLeftChild(index); // 用于和index进行比较的节点,默认先为左孩子
        // swaoindex + 1 < data.size()表示还有右孩子,若右孩子比左孩子大,则使用右孩子和index比较
        if((swapindex + 1 < data.size()) && data[swapindex+1] > data[swapindex]){
            swapindex = getRightChild(index);
        }
        if(data[swapindex] > data[index]){ // 如果孩子比index大,则下沉,并使用孩子继续往下沉
            swap(data[index],data[swapindex]);
            index = swapindex;
        }
        else{return ;}
    }
}
void MaxHeap::printHeap(){
    for(int val : data){
        cout<<val<<" ";
    }
    cout<<endl;
}

排序算法总结

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值