堆:使用数组实现
堆的实现通过构造二叉堆(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;
}