堆是一个用数组表示的完全二叉树,并满足以下两个特性:
1)父节点的键值总是大于或等于(小于等于)其子树上的任意结点
2)每个结点的左子树和右子树都是个堆。
如果父节点的键值总是大于等于任何一个子节点的键值,那么这时称之为最大堆或者大顶堆。
如果父节点的键值总是小于等于任何一个子节点的键值,那么这时称之为最小堆或者小顶堆。

#pragma once
#include<iostream>
#include<assert.h>
#include<vector>
using namespace std;
//用仿函数将大小堆都实现
template<class T>
struct Less
{
    bool operator()(const T& left,const T& right)const
    {
        return left < right;
    }
};

template<class T>
struct Greater
{
    bool operator()(const T& left, const T& right) const
    {
        return left > right;
    }
};

//大堆
template<class T, class Compare = Greater<T>>
class Heap // MinHeap
{
public:
    Heap()
    {}

    Heap(T*a, size_t n)
    {
        _a.reserve(n);
        for(size_t i = 0; i < n; ++i)
        {
            _a.push_back(a[i]);
        }

        // 建堆
        // O(N*lgN)
        for (int i = (_a.size()-2)/2; i >= 0; --i)
        {
            AdjustDown(i); // O(lgN)
        }
    }

    void Push(const T& x)
    {
        _a.push_back(x);
        AdjustUp(_a.size()-1);
    }

    void Pop()
    {
        assert(!_a.Empty());
        swap(_a[0], _a[_a.size()-1]);
        _a.pop_back();
        AdjustDown(0);
    }

    void AdjustUp(int child)
    {
        Compare com;
        int parent = (child-1)/2;
        while (child > 0)
        {
            //if (_a[child] > _a[parent])
            if (com(_a[child],_a[parent]))
            {
                swap(_a[parent], _a[child]);
                child = parent;
                parent = (child-1)/2;
            }
            else
            {
                break;
            }
        }
    }

    void AdjustDown(int root)
    {
        Compare com;
        int parent = root;
        int child = parent*2+1;
        while (child < _a.size())
        {
            // 选出大的那一个孩纸
            if (child+1 < _a.size() && com(_a[child+1],_a[child]))
            //if (child+1 < _a.size() && _a[child+1] > _a[child])
            {
                ++child;
            }

            if (com(_a[child],_a[parent]))
            //if (_a[child] > _a[parent])
            {
                swap(_a[child], _a[parent]);
                parent = child;
                child = child*2+1;
            }
            else
            {
                break;
            }
        }
    }

    size_t Size()
    {
        return _a.size();
    }
    bool Empty()
    {
        return _a.Empty();
    }
    T& Top()
    {
        assert(_a.size() > 0);
        return _a[0];
    }
private:
    vector<T> _a;
};

void AdjustDown(int*heap,size_t n,int root)
{
    assert(heap);
    int parent = root;
    int child = parent*2+1;
    while(child < n)
    {
        if(child+1<n && heap[child+1] > heap[child])
        {
            ++child;
        }
        if(heap[child] > heap[parent])
        {
            swap(heap[child],heap[parent]);
            parent = child;
            child = parent*2+1;
        }
        else
        {
            break;
        }
    }
}

void HeapSort(int* a,size_t n)
{
    //建堆
    for(int i =(n-2)/2;i>= 0;--i)
    {
        AdjustDown(a,n,0);
    }
    size_t end = n-1;
    while(end > 0)
    {
        swap(a[0],a[end]);
        AdjustDown(a,end,0);
        --end;
    }
}
void TestHeap()
{
    int a[] = {10,11, 13, 12, 16, 18, 15, 17, 14, 19};
    Heap<int> hp1(a, sizeof(a)/sizeof(a[10]));
    Heap<int, Less<int>> hp2(a, sizeof(a)/sizeof(a[10]));
    hp1.Push(78);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值