堆
堆数据结构是一种数组对象,它可以被视为一科完全二叉树结构。它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆)。它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等。
最小堆:任一结点的关键码均小于等于它的左右孩子的关键码,位于堆顶结点的关键码最小。
最大堆:任一结点的关键码均大于等于它的左右孩子的关键码,位于堆顶结点的关键码最大。
#pragma once
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
template <class T> //比较器模板
struct Greater
{
bool operator ()(const T& a, const T& b)
{
return a > b;
}
};
template <class T> //比较器模板
struct Less
{
bool operator ()(const T& a,const T& b)
{
return a < b;
}
};
template <class T,class Comparator = Less<T>>
class Heap
{
public:
Heap() //构造函数(无节点)
{}
Heap(T* a, size_t size) //构造函数(创造堆)
{
Creatheap(a, size);
}
void Creatheap(const T* a, int size); //创建堆
void Adjustup(size_t child); //向上调节
void Adjustdown(size_t root); //向下调节
void Push(const T& a); //往对中压入一个值
void Pop(); //将堆顶端节点去除
T& Top(); //显示堆顶端节点
bool Empty(); //检测堆是否为空
void Display(); //打印堆中的值
private:
vector<T> _arr; //STL vector创建一个数组
};
template<class T, class Comparator>
inline void Heap<T,Comparator>::Creatheap(const T* a,int size)
{
_arr.reserve(size);
for (int idx = 0; idx < size; idx++)
{
_arr.push_back(a[idx]);
}
for (int i = (_arr.size() - 2 )/ 2; i>-1;i--)
{
Adjustdown(i);
}
}
template<class T,class Comparator>
inline void Heap<T, Comparator>::Adjustup(size_t child)
{
int parent = (child - 1) / 2;
while (parent >= 0)
{
if (Comparator()(_arr[child], _arr[parent]))
swap(_arr[parent], _arr[child]);
else
break;
}
}
template<class T,class Comparator>
inline void Heap<T, Comparator>::Adjustdown(size_t root)
{
size_t parent = root;
size_t child = parent * 2 + 1;
while (child < _arr.size())
{
if (child + 1 < _arr.size() && Comparator()(_arr[child + 1], _arr[child]))
child++;
if (Comparator()(_arr[child], _arr[parent]))
{
swap(_arr[child], _arr[parent]);
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
template<class T, class Comparator>
inline void Heap<T, Comparator>::Push(const T& a)
{
_arr.Push_back(a);
Adjustup(_arr.size() - 1);
}
template<class T,class Comparator>
inline void Heap<T, Comparator>::Pop()
{
assert(!Heap.Empty())
swap(_arr[0], _arr[_arr.size() - 2]);
_arr.Pop_back;
Adjustdown(0);
}
template<class T,class Comparator>
inline T& Heap<T, Comparator>::Top()
{
assert(!Heap.Empty())
return _arr[0];
}
template<class T,class Comparator>
inline bool Heap<T, Comparator>::Empty()
{
return _arr.empty();
}
template<class T,class Comparator>
inline void Heap<T, Comparator>::Display()
{
for (size_t idx = 0; idx < _arr.size(); idx++)
{
cout << _arr[idx] << " ";
}
}
1.在写堆的构造函数时,需要注意的是,创建一个空堆Heap()和创建一个有参数的Heap(T* a, size_t size)。
2.堆的创建函数void Creatheap(const T* a,int size)需要对容器vector实例化出来的_arr数组进行容量改变,满足放入数组大小,然后调用 _arr里的方法函数push _back()使数组放入容器,然后调用向下调整使其满足堆的条件。从最后一个叶子节点开始调整,一直调整到顶端节点。
3.向上调整中void Adjustup(size_t child)中,我们要得到孩子节点的形参,用孩子节点(child-1)/2得到他的双亲节点,进行比较,满足条件则交换,当双亲节点<0时,调整完毕。
4.向下调整void Adjustdown(size_t root)中,得到的是双亲节点,然后通过双亲节点得到他的左孩子节点,然后判断右孩子节点是否存在,如果存在找两个孩子中的最大值,然后用最大值与双亲节点进行比较,满足条件则进行交换。
5.void Pop()和T& Top()都需要先assert堆是否为空,当为空不能调用。
6.通过我们的比较器模板化,可将堆定义为大堆或者小堆,默认参数为大堆。