堆数据结构是一种数组对象,可被视为一颗完全二叉树
堆结构的二叉树存储
最大堆:父>子
最小堆:父<子
如下图,先建立一个大堆
下面用代码模拟实现一个大堆(插入 ,头删)
#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;
template <class T>
class Heap
{
public:
Heap()
{}
Heap(const T* a, size_t n)
{
_a.reserve(n);//开辟n个空间
for (size_t i = 0; i < n; i++)
{
_a.push_back(a[i]);//插入数据
}
int parent = (n - 1) / 2;
for (parent; parent>=0; parent--)
{
adjustdown(parent);//向下调整 建大堆
}
}
void show()
{
if (_a.size())
{
for (size_t i = 0; i <_a.size(); i++)
{
printf("%3d ",_a[i]);
}printf("\n");
}
}
void push(const T& x)
{
_a.push_back(x);//尾插
adjustup(_a.size()-1);//向上调整
}
void pop()
{
assert(_a.size());
swap(_a[0], _a[_a.size() - 1]);
_a.pop_back();//尾删,然后向下调整
adjustdown(0);
}
protected:
vector<T> _a;
void adjustdown(int parent)//向下调整
{
int child = parent * 2 + 1;
while (child<_a.size())
{
//当右孩子存在,且大于左孩子时
if (child + 1 < _a.size() && _a[child + 1] > _a[child])
++child;
if (_a[child] > _a[parent])//当孩子大于父亲时,交换
{
swap(_a[child], _a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void adjustup(int child)//向上调整
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (_a[child] > _a[parent])//当孩子大于父亲时,交换
{
swap(_a[child],_a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else break;
}
}
};
void main()
{
int a[] = { 12,13,14,15,16,17,20,21,25};
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
printf("%3d ", a[i]);
}
printf("\n");
Heap<int>hp(a, sizeof(a) / sizeof(a[0]));
hp.show();
hp.push(23); printf("hp.push(23)\n");
hp.show();
hp.pop(); printf("hp.pop();\n");
hp.show();
system("pause");
}
结果如下
如上就是堆的简单实现,再进一步可以将建大小堆关键判断语句用仿函数代替
#pragma once
#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;
template<class T>
struct Greater//建大堆
{
bool operator()(const T& x1, const T& x2)
{
return x1 > x2;
}
};
template<class T>
struct Less//建小堆
{
bool operator()(const T& x1, const T& x2)
{
return x1 < x2;
}
};
template <class T,class Compare>
class Heap
{
public:
Heap()
{}
Heap(const T* a, size_t n)
{
_a.reserve(n);//开辟n个空间
for (size_t i = 0; i < n; i++)
{
_a.push_back(a[i]);//插入数据
}
int parent = (n - 1) / 2;
for (parent; parent >= 0; parent--)
{
adjustdown(parent);//向下调整 建大堆
}
}
void show()
{
if (_a.size())
{
for (size_t i = 0; i <_a.size(); i++)
{
printf("%3d ", _a[i]);
}printf("\n");
}
}
void push(const T& x)//尾插
{
_a.push_back(x);//尾插
adjustup(_a.size() - 1);//向上调整
}
void pop()//删除堆顶元素
{
assert(_a.size());
swap(_a[0], _a[_a.size() - 1]);
_a.pop_back();//尾删,然后向下调整
adjustdown(0);
}
size_t Size()
{
return _a.size();
}
const T& Top()
{
return _a[0];
}
protected:
vector<T> _a;
void adjustdown(int parent)//向下调整
{
Compare com;//
int child = parent * 2 + 1;
while (child<_a.size())
{
//当右孩子存在,且大于/小于左孩子时
if (child + 1 < _a.size() && com(_a[child +1] , _a[child]))//此处用仿函数替换
++child;
if (com(_a[child] , _a[parent]))//当孩子大于/小于父亲时,交换
{
swap(_a[child], _a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
void adjustup(int child)//向上调整
{
Compare com;//
int parent = (child - 1) / 2;
while (child > 0)
{
//此处用仿函数替换
if (com(_a[child] , _a[parent]))//当孩子大于/小于父亲时,交换
{
swap(_a[child], _a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else break;
}
}
};
如上所示为用仿函数替换的堆,根据需要建大堆或小堆