大顶堆的C++模板实现及二叉堆的简介

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tanswer_/article/details/52824153

何为二叉堆?

二叉堆是一种特殊的堆,二叉堆是完全二叉树或者近似完全二叉树。二叉堆满足堆特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左右子树都是一个二叉堆

当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆(大顶堆)。
当父节点的键值总是小于或等于任何一个子节点的键值时为最小堆(小顶堆)。

根据二叉树的性质,可得:
1. 如果根节点在数组的位置是1,第n个位置的子节点分别在2n和2n+1,第n个位置的双亲节点在[i/2]。因此,第1个位置的子节点在2和3。
2. 如果根节点在数组的位置是0,第n个位置的子节点分别在2n+1和2n+2,第n个位置的双亲节点在[(i-1)/2]。因此,第0个位置的子节点在1和2。

二叉堆一般用数组来表示,得益于数组的随机存储能力,我们能够很快确定堆中节点的父节点和子节点。

这里写图片描述
在本文中,我们主要介绍大顶堆的C++模板实现过程,以根节点在0位置存储为例。

二叉堆的具体实现

1. 二叉堆的抽象数据类型

/*大顶堆类定义*/
template <typename T>
class MaxHeap
{
public:
    MaxHeap(int cap);
   ~MaxHeap();

    bool insert(T val);     //往二叉堆中插入元素
    bool remove(T val);     //从二叉堆中删除元素
    void print();           //打印二叉堆
    T    getTop();          //获取堆顶元素
    bool creatMaxHeap(T a[],int size);//根据指定数组创建大顶堆

private:

    int ArraySize;      //数组的大小
    int size;           //堆的大小,数组中有效元素的个数
    T*  maxheap;        //底层数组

    //从index节点往根节点调整堆
    void filterUp(int index);
    //从begin节点向end节点调整堆
    void filterDown(int begin,int end);

};

2. 构造函数与析构函数

/*构造函数*/
template <typename T>
MaxHeap<T>::MaxHeap(int cap)
{
    ArraySize = cap;   //初始化数组的大小
    size = 0;      
    maxheap = new T[ArraySize]; //开辟空间
};
/*析构函数*/
template <typename T>
MaxHeap<T>::~MaxHeap()
{
    delete []maxheap;      //释放空间  
}

3. 大顶堆的插入

在数组的最末尾插入节点,然后自上而下地调整子节点与父节点的位置:比较当前节点与父节点的大小,若不满足大顶堆的性质,则交换两节点。时间复杂度为O(log n)。

这里写图片描述

/*从下往上调整堆--插入元素时使用*/
template <typename T>
void MaxHeap<T>::filterUp(int index)
{
    //记录下当前节点
    T value = maxheap[index];
    while(index>0)
    {
        //得到其双亲节点
        int indexparent = (index - 1) / 2;

        if(value < maxheap[indexparent])
            break;
        else  //交换两节点
        {
            //新节点被其父节点覆盖
            maxheap[index] = maxheap[indexparent];
            //记录下新节点的位置
            index = indexparent;   
        }
    }
    //给新节点赋值
    maxheap[index] = value;
};

/*插入元素*/
template<typename T>
bool MaxHeap<T>::insert(T val)
{
    if(ArraySize == size)  //如果数组放不下
        return false;
    maxheap[size] = val;   //数组末尾放入新节点
    filterUp(size);        //自下而上调整节点
    size++;                //堆的元素数量加1
    return true;
};

实际编码过程中,我们不进行节点的交换,我们直接使用父节点覆盖当前节点,然后记录新节点的位置,最后直接把新节点放入它最后的位置即可。

4. 大顶堆的删除

堆删除节点的过程:用数组最末尾节点覆盖被删结点,然后数组的有效元素(即堆中的元素)数量减1,再由该节点从上到下调整二叉堆。
/*从上到下调整堆--删除元素时使用*/
template <typename T>
void MaxHeap<T>::filterDown(int current,int end)
{
    int child = current * 2 + 1;  //当前结点的左孩子

    T value = maxheap[current];  //保存当前节点

    while(child <= end)
    {
        //选出两个孩子中较大的孩子
        if(child < end && maxheap[child] < maxheap[child + 1])
            child++;  
        if(value > maxheap[child])//无需调整
            break;
        else
        {
            maxheap[current] = maxheap[child]; //孩子节点覆盖当前节点
            current = child;                   //当前节点为较大的孩子节点
            child = child * 2 + 1;             //child重新指向当前节点的左孩子节点
        }
    }
    maxheap[current] = value;                  //找到合理地位置后 赋值
};
/*删除元素*/
template <typename T>
bool MaxHeap<T>::remove(T key)
{
    if(size == 0)
        return false;
    int index;  //被删除元素的下标

    for(index = 0; index < size; index++)
    {

        if(maxheap[index] == key)
            break;  //找到被删元素的下标
    }

    if(index == size) 
        return false;  //数组中没有要删除的元素

    //使用数组最后一个元素来代替该被删除元素
    maxheap[index] = maxheap[size - 1];

    //覆盖完成后 从上到下调整堆
    filterDown(index,size--);

    return true;
};

5. 其他操作

/*获取堆顶元素*/
template <typename T>
T MaxHeap<T>::getTop()
{
    if(size != 0)
        return maxheap[0];    
};

/*打印大顶堆*/
template <typename T>
void MaxHeap<T>::print()
{
    for(int i=0; i<size; i++)
        cout << maxheap[i] << " ";
    cout << endl;
};

/*根据指定数组创建大顶堆*/
template <typename T>
bool MaxHeap<T>::creatMaxHeap(T a[],int size)
{
    if(ArraySize < size)
        return false;
    for(int i=0; i<size; i++)
        insert(a[i]);

    return true;
};

6. 测试代码

int main()
{
    MaxHeap<int> heap1(11);

    //逐个元素创建大顶堆
    for(int i=0; i<10; i++)
        heap1.insert(i);
    cout << "堆顶元素为:" << heap1.getTop() << endl;
    heap1.print();

    /*从堆中删除元素5*/
    heap1.remove(5);
    heap1.print();

    //根据指定数组创建大顶堆*/
    int array[10] = { 1,2,3,4,5,6,7,8,9,10 };
    MaxHeap<int> heap2(11);
    heap2.creatMaxHeap(array,10);
    cout << "堆顶元素为:" << heap2.getTop() << endl;
    heap2.print();

    return 0;
}

7. 输出结果

堆顶元素为:9
9 8 5 6 7 1 4 0 3 2 
9 8 4 6 7 1 2 0 3 
堆顶元素为:10
10 9 6 7 8 2 5 1 4 3 

ok,all right.

展开阅读全文

没有更多推荐了,返回首页