二叉堆------小根堆

二叉堆是完全二叉树,每个结点中存有一个元素。
小根堆堆性质:父亲的权值不大于儿子的权值。

插入操作
插入操作是指向二叉堆中插入一个元素,要保证插入后也是一棵完全二叉树。

最简单的方法就是,最下一层最右边的叶子之后插入。
如果最下一层已满,就新增一层。

向上调整:如果这个结点的权值大于它父亲的权值,就交换,重复此过程直到不满足或者到根。
可以证明,插入之后向上调整后,没有其他结点会不满足堆性质。
向上调整的时间复杂度是log(n)。

删除操作
删除操作指删除堆中最大的元素,即删除根结点。
但是如果直接删除,则变成了两个堆,难以处理。
所以不妨考虑插入操作的逆过程,设法将根结点移到最后一个结点,然后直接删掉。
然而实际上不好做,我们通常采用的方法是,把根结点和最后一个结点直接交换。
于是直接删掉(在最后一个结点处的)根结点,但是新的根结点可能不满足堆性质

向下调整:在该结点的儿子中,找一个最小的,与该结点交换,重复此过程直到底层。
可以证明,删除并向下调整后,没有其他结点不满足堆性质。
时间复杂度log(n) 。

应用:
寻找数组中第K个最小的元素

BinHeapMin.h

#pragma once

#include <iostream>

class BinHeapMin
{
public:
    BinHeapMin();
    ~BinHeapMin();
    bool Insert(int k);
    bool Delete(int k);
    int GetIndex(int k);
    void show();

private:
    static const int CAPACITY;
    int *prique;
    int size;
};

const int BinHeapMin::CAPACITY = 100;

BinHeapMin::BinHeapMin()
{
    prique = new int[CAPACITY];
    size = 0;
}

BinHeapMin::~BinHeapMin()
{
    if (prique != nullptr)
    {
        delete[] prique;
        prique = nullptr;
    }
}

bool BinHeapMin::Insert(int k)
{
    if (size >= CAPACITY)
        return false;

    //percolate up
    int parent = (size - 1) / 2;
    int curIndex = size;

    while (curIndex > 0 && k <= prique[parent])
    {
        prique[curIndex] = prique[parent];
        curIndex = parent;
        parent = (parent - 1) / 2;
    }
    prique[curIndex] = k;

    ++size;

    return true;
}

int BinHeapMin::GetIndex(int k)
{
    if (size == 0)
        return -1;

    for (int i = 0; i < size; ++i)
        if (prique[i] == k )
            return i;

    return -1;
}

 

bool BinHeapMin::Delete(int k)
{
    if (size == 0)
        return false;

    int targetIndex = GetIndex(k);
    if (targetIndex < 0)
        return false;

    int lastElem = prique[--size];
    //percolate down
    int child = 2 * targetIndex + 1;
    int parent = targetIndex;
    while (child < size)
    {
        // find smaller child
        if ((child + 1) < size && prique[child] > prique[child + 1])
            ++child;

        // percolate one level
        if (lastElem > prique[child])
            prique[parent] = prique[child];
        else
            break;

        parent = child;
        child = 2 * child +1;
    }
    prique[parent] = lastElem;

    return true;
}

void BinHeapMin::show()
{
    for (int i = 0; i < size; ++i)
        std::cout << prique[i] << " ";
    std::cout << std::endl;
}

BinHeapMin.cpp

#include "BinHeapMin.h"

int main()
{
    BinHeapMin prique;
    int arr[] = { 13, 14, 16, 19, 21, 19, 68, 65, 26, 32, 31 };
    for (int i = 0; i < sizeof(arr) / sizeof(int); ++i)
    {
        prique.Insert(arr[i]);
    }
    prique.show();

    std::cout << "After delete 13" << std::endl;
    prique.Delete(13);
    prique.show();

    return 0;
}
 

13 14 16 19 21 19 68 65 26 32 31
After delete 13
14 19 16 26 21 19 68 65 31 32

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值