堆的思想及实现


1.任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。
2.堆总是一棵完全树

完全树:即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。

支持的基本操作

操作描述时间复杂度
build创建一个空堆O(n)
insert向堆中插入一个新元素O(logn)
update将新元素提升使其匹配堆的性质
get获取当前堆顶元素的值O(1)
delete删除堆顶元素O(logn)
heapify使删除堆顶元素的堆再次成为堆

二叉堆的数组实现:给每个节点编号,使得每个父节点的左节点序列号为父节点的二倍,右节点的序列号为父节点序列号的二倍加1

parent(i) = i/2
left child(i) = 2*i
right child(i) = 2*i + 1
堆的基础实现:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cmath>
#include<cmath>
using namespace std;

template<typename Item>
class MaxHeap{
private:
    Item* data;
    int count;
public:
    MaxHeap(int capacity){
        data=new Item[capacity+1];   //从索引1开始存储 
        count=0;
    }
    ~MaxHeap(){
        delete [] data;
    } 
    int size(){
        return count;
    }
    bool isEmpty(){
        return count==0;
    }
};

int main(){
    MaxHeap<int> maxHeap = MaxHeap<int>(100);
    cout<<maxHeap.size()<<endl;
    return 0;
}

堆的基本操作:
1.ShiftUp:先将元素写入数组最后一个位置,然后不断和父节点比较大小,如果该元素大于父节点,则进行交换,直到找到合适的位置。
实现:

void ShiftUp(int k){
        while(k>1&&data[k]>data[k/2]){
            swap(data[k],data[k/2]);
            k/=2;
        }
    }

插入一个数组元素:

void insert(Item item){
        data[count+1]=item;
        count++;
        ShiftUp(count);
    }

2.ShiftDown:从堆中取出一个元素(优先级最高的元素),然后把最后一个元素移动到第一个元素的位置。不断与两个子节点中较大的进行交换,直到找到合适的位置。
实现:

void shiftDown(int k){
        //k必须有孩子,只要满足有左孩子即可 
        while(2*k<=count){
            int j=2*k;  //在此轮循环中,data[k]和data[j]交换位置
            if(j+1<=count&&data[j+1]>=data[j])
                j+=1;
            if(data[k]>=data[j])
                break;
            swap(data[k],data[j]);
            k=j;
        }
    }

取出一个元素:

Item extractMax(){
        assert(count>0);
        Item ret=data[1];
        swap(data[1],data[count]);
        count--;
        shiftDown(1);

        return ret;
    } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值