本文记录了使用C++模板实现了堆的基本操作,对于其他一些有用操作如IncreaseKey和DecreaseKey等则没有实现,这是因为使用模板把最小堆和最大堆揉在一起,对Key的增减我还没有找到比较好的处理方式,而现在写这个堆数据结构主要是因为在Hoffman树算法需要,基本操作已经够用了。
堆是一棵完全二叉树,所谓完全二叉树就是一棵从上倒下,从左到右依次填满每一个位置的二叉树,除了最后一层节点没有子节点外,最多只有倒数第二层后面部分节点没有子节点或只有一个节点(最多只有一个节点仅有一个子节点,这个节点后的节点没有子节点,而之前的节点都有两个子节点)。这棵树的元素是放在一个数组中的,父子关系通过数组下标来维护,如果从数组(下标从0开始)的第二个位置存放元素,那么某个元素A[i]的左孩子将被放到A[2*i],而右孩子放在A[2*i+1],父节点则放在A[i/2]。如果从数组(下标从0开始)的第一个位置存放元素,那么某个元素A[i]的左孩子将被放到A[2*i+1],而右孩子放在A[2*i+2],父节点则放在A[(i - 1)/2]。
最小堆中每个节点的Key值都不大于它的孩子(如果有的话),同理,最大堆中每个节点的Key值都不小于它的孩子(如果有的话)。概念完毕,看代码:
#ifndef _HEAP_H_
#define _HEAP_H_
#include "../include/Functor.h"
#include "../Utilites/type_traits.h"
#include "Vector.h"
namespace MyDataStructure
{
//堆数据结构,默认为最大堆,需要最
//小堆,只需指定比函数为大于比较
template<typename ValueType,typename Compare = less<ValueType>>
class Heap
{
public:
typedef typename ParameterTrait<ValueType>::ParameterType ParameterType;
typedef typename Heap<ValueType> self;
public:
Heap(){};
Heap(int capacity);
Heap(ValueType values[], int count);
Heap(const Heap& rhs);
self& operator = (const Heap& rhs);
~Heap(){}
void Insert(const ParameterType value);
bool GetTop(ValueType& top);
void RemoveTop();
void Clear(){ values.Clear(); }
int Size(){ return values.Size(); }
int Capacity(){ return values.Capacity(); }
private:
void copy(const Vector<ValueType>& values);
void clear();
void sift_down(int start,int end);
void sift_up(int start);
void build_heap();
private:
//使用Vector以支持动态扩容
Vector<ValueType> values;
Compare comp;
};
template<typename ValueType, typename Compare>
Heap<ValueType, Compare>::Heap(int capacity)
{
values.Resize(capacity);
}
template<typename ValueType, typename Compare>
Heap<ValueType, Compare>::Heap(ValueType values[], int count)
{
for (int i = 0; i < count; ++i)
{
this->values.PushBack(values[i]);
}
build_heap();
}
template<typename ValueType,typename Compare>
Heap<ValueType, Compare>::Heap(const Heap& rhs)
{
clear();
copy(rhs.values);
}
template<typename ValueType, typename Compare>
typename Heap<ValueType,Compare>::self&
Heap<ValueType, Compare>
::operator=(const Heap<ValueType, Compare>& rhs)
{
clear();
copy(rhs.values);
return *this;
}
template<typename ValueType, typename Compare>
void Heap<ValueType, Compare>::Insert(const ParameterType value)
{
values.PushBack(value);
sift_up(values.Size() - 1);
}
template<typename ValueType, typename Compare>
bool Heap<ValueType, Compare>::GetTop(ValueType& top)
{
if(values.Size() <= 0) return false;
else
{
top = values[0];
return true;
}
}
template<typename ValueType, typename Compare>
void Heap<ValueType, Compare>::RemoveTop()
{
int size = values.Size();
if (size <= 0) return;
ValueType temp = values[0];
//将最后一个元素覆盖到第一个元素
values[0] = values[size - 1];
//删除最后一个元素
values.Erase(size - 1);
--size;
//对第一个元素执行下滤操作
sift_down(0,size - 1);
}
template<typename ValueType, typename Compare>
void Heap<ValueType, Compare>::copy(const Vector<ValueType>& values)
{
this->values = values;
}
//清除堆中数据,并不需要销毁占用的内存
template<typename ValueType, typename Compare>
void Heap<ValueType, Compare>::clear()
{
values.Clear();
}
//下滤(以最大堆为例),从某个元素x开始,分别将其与他的左右孩子比较,
//如果小于其中任意一个,那么就把三者中最小的一个覆盖x,然后假设x被放到了
//之前三者中最小元素所在的位置上,重复上面的过程,直到x大于或等于他的
//左右孩子或到达了堆的末尾,然后把x放到最新空出来的位置上
template<typename ValueType, typename Compare>
void Heap<ValueType, Compare>::sift_down(int start,int end)
{
int i = start, j = 2 * i + 1;
ValueType temp = values[i];
while ( j <= end)
{
if (j < end && comp(values[j], values[j + 1])) ++j;
if (!comp(temp,values[j])) break;
else
{
values[i] = values[j];
i = j;
j = 2 * i + 1;
}
}
values[i] = temp;
}
//上滤(以最大堆为例),从某个元素x开始,如果其比父节点还大,
//那么就把父节点覆盖到x的位置上,然后假设x被放到父节点的位置,
//重复上面的过程,直到x大于或等于他的左右孩子
//或到达了堆顶,然后把x放到最新空出来的位置上
template<typename ValueType, typename Compare>
void Heap<ValueType, Compare>::sift_up(int start)
{
int j = start,i = (j - 1) / 2;
ValueType temp = values[j];
while (j > 0)
{
if (!comp(values[i],temp)) break;
else
{
values[j] = values[i];
j = i;
i = (j - 1) / 2;
}
}
values[j] = temp;
}
//建立堆(以最大堆为例),从堆的中间位置(堆中元素
//有偶数个时,取下中位数,为基数时,取中位数的前一个)
//开始向前对每个元素执行下滤操作。中间位置后的元素一定是
//前面元素的孩子,所以后半段中如果有较小的元素一定会被虑
//上来的,同时较大的元素会被下放
template<typename ValueType, typename Compare>
void Heap<ValueType, Compare>::build_heap()
{
int end = values.Size() - 1;
for (int i = (end - 1) / 2; i >= 0; --i)
{
sift_down(i, end);
}
}
}
#endif
下面利用利用堆排序来测试上面所列的各种操作:
// HeapTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "../include/Heap.h"
#include "../include/Functor.h"
#include <iostream>
using namespace MyDataStructure;
using namespace std;
//使用堆结构进行了排序操作
int _tmain(int argc, _TCHAR* argv[])
{
int v[] = { 1, 3, 3, 9, 7, 9, 4, 2, 8, 10 };
//建立一个最大堆
Heap<int> maxHeap(v, 10);
//建立一个最小堆
Heap<int, greater<int>> minHeap(v, 10);
int k = 0;
int size = maxHeap.Size();
//堆排序
for (int i = 0; i < size;++i)
{
if (maxHeap.GetTop(k))
cout << k << " ";
maxHeap.RemoveTop();
}
cout << endl;
for (int i = 0; i < size; ++i)
{
if (minHeap.GetTop(k))
cout << k << " ";
minHeap.RemoveTop();
}
cout << endl;
int v1[] = { 11, 33,19, 17, 14, 12, 18, 20 };
for (int i = 0; i < 8;++i)
{
maxHeap.Insert(v1[i]);
}
Heap<int> He1(maxHeap);
Heap<int> He2 = He1;
size = He2.Size();
for (int i = 0; i < size; ++i)
{
if (He2.GetTop(k))
cout << k << " ";
He2.RemoveTop();
}
cout << endl;
return 0;
}
测试程序结果:
原文地址:http://blog.csdn.net/liao_jian/article/details/45721119