C++数据结构 18 堆

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

堆:使用数组实现

堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质。

任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。 
堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

简单来说,堆的存储结构是数组,逻辑结构是一棵完全二叉树,通过索引的方式表示二叉树父节点和孩子节点的关系,父节点大于孩子节点叫大根堆,反之叫小根堆.堆支持的主要操作有:入堆,出堆,调堆,堆排序,其中插入操作复杂度为O(logn)O(logn),因此堆排序的复杂度是O(nlogn)O(nlogn)
实现
主要实现几个操作push,pop

1.插入:
也就是,首先插入一定是插入到完全二叉树的最右下,对应数组中,也就是back()的位置,那么为了满足堆的性质,就需要不断的上溯,也就是将新插入的元素往上到合适的位置.这里沿用STL中的实现方式,并不是直接的swap,而是先生成一个HoleInex也就是产生一个空洞,这个空洞就是待插入的位置,但是这个空洞需要不断的上溯到合适位置,然后将新值插入即可.

2.弹出:
弹出堆中的最大值/最小值,对应的就是堆顶元素,数组索引位置为0或者1(取决于实现)。这个时候将堆顶元素放到末尾(覆盖最后一个元素),堆顶的这个位置就变成了空洞了,此时需要将原来的末尾的元素插入到这个空洞中,就需要将这个空洞下沉到合适位置,然后将元素插入,并且堆大小减1

3.排序:
pop操作每次都会弹出最大或者最小的元素到堆尾,那么执行n-1次弹出操作,数组就有序了。
 

堆可分为大顶堆和小顶堆

大顶堆就是最大的元素为根元素,小顶堆最小的元素是根元素

堆的操作:

   插入新节点-向上渗透(先把节点插入到最后,和父节点依次比大小)

   删除根节点-向下渗透(先把最后一个节点放置到根节点,再依次比较大小)

#ifndef __MAXHEAP_H__
#define __MAXHEAP_H__
#include <iostream>

using namespace std;

template<class T>
class MaxHeap
{
public:
    MaxHeap(int mx=10);   //构造函数
    virtual ~MaxHeap();   //析构函数

    bool isEmpty();        //是否为空
    void Push(const T&);   //插入数据
    void Pop();            //删除数据
    const T& Top()const;   //查看根节点数据
private:
    T*  HeadArry;        //数组
    int maxSize;        //最大的大小
    int currentSize;    //当前大小

    void trickUp(int index); //向上渗透
    void trickDown(int index);//向下渗透
};


template<class T>
MaxHeap<T>::MaxHeap(int mx)//构造函数
{
    if(mx<1)
        throw "Error";
    maxSize=mx;
    currentSize=0;
    HeadArry=new T[maxSize];
}

template<class T>
MaxHeap<T>::~MaxHeap()
{
    delete [] HeadArry;
}

template<class T>
bool MaxHeap<T>::isEmpty()  //查看是否为空
{
    return currentSize==0;   //为空返1
}

template<class T>
void MaxHeap<T>::Push(const T&e)   //插入数据
{
    if(currentSize==maxSize)
        throw "Head has already full";
    HeadArry[currentSize]=e;   //在最后插入
    trickUp(currentSize++);  //向上渗透
}

template<class T>
void MaxHeap<T>::trickUp(int index) //向上渗透
{
    int parent=(index-1)/2;     //获取父节点的序号
    T bottom=HeadArry[index];  //先保存最后一个数
    while((index>0)  && (HeadArry[parent]<bottom)) //当达到根或者子节点比父节点大停止
    {
        HeadArry[index]=HeadArry[parent];  //交换
        index=parent;
        parent=(parent-1)/2;
    }
    HeadArry[index]=bottom;         //找到合适的位置
}

template<class T>
const T& MaxHeap<T>::Top() const       //查看最顶端的数
{
    return HeadArry[0];
}

template<class T>
void MaxHeap<T>::Pop()      //删除
{
    HeadArry[0]=HeadArry[--currentSize];  //把最后一个数拿到最上面来
    trickDown(0);  //从根开始渗透
}

template<class T>
void MaxHeap<T>::trickDown(int index)
{
    int large;
    T top=HeadArry[index];  //临时保存父节点

    while(index<currentSize/2)  //循环到第二层
    {
        int Left=2*index+1;   //左儿子
        int Right=Left+1;     //右儿子
        if(Right<currentSize  && HeadArry[Left]<HeadArry[Right]) //右儿子存在并且右儿子比儿子大
        {
            large=Right;          //得到右儿子
        }
        else
            large=Left;           //得到左儿子
        if(top>= HeadArry[large])  //父节点比儿子大
          break;     //结束
        HeadArry[index]=HeadArry[large];  //否则交换顺序
        index=large;       //继续向下渗透
    }
    HeadArry[index]=top;      //把top插入到这个里面

}









#endif // __MAXHEAP_H__
#include <iostream>
#include "MaxHeap.h"
using namespace std;

int main()
{
    MaxHeap<int> p;
    p.Push(10);
    p.Push(30);
    p.Push(15);

    //cout<<p.Top()<<endl;
    p.Push(60);
       cout<<p.Top()<<endl;

    p.Pop();
     cout<<p.Top()<<endl;
    //cout << "Hello world!" << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u014183456/article/details/83505770