一、哈夫曼树
最优二叉树,是一类带权路径长度最短的树
所谓树的带权路径长度,就是树中所有的叶节点的权值乘上其到根节点的路径长度。树的路径长度是从树根到每一节点的路径长度之和。
二、堆
最大(小)堆,其实就是最大(小)完全二叉树
最大堆特性:
1. 是完全二叉树,满足完全二叉树的特性
2. 堆中的任意一个节点的值都必须大于或等于其最大子节点的值
三、最大堆代码示例
1. 最大堆数据结构
template<typename T>
class Heap
{
T *pBuff;//数组实现最大堆
T len;//长度
T Maxsize;//最大容量
}
2. 基本函数
public:
Heap();//构造函数
~Heap();//析构函数
void clearHeap();//清空堆
void appendHeap(T const & data);//追加元素
void deleteHeap();//删除根节点
void InitHeap(T arr[],int lenght);//初始化堆
void printHeep();//输出堆
T const & getRoot() const;//输出根节点
3. 追加元素
template<typename T>
void Heap<T>::appendHeap(T const & data)
{
if (len >= Maxsize)//1. 判断空间是否剩余
{
//2. 扩大最大空间
Maxsize += ((Maxsize>>1 > 1) ? Maxsize>>1 : 1);
T *tempBuff = new T[Maxsize];//动态开辟辅助数组
for (int i = 0; i < len; i++)
{
tempBuff[i] = pBuff[i];
}
if (pBuff)
{
delete[] pBuff;//清空原数组
}
pBuff = tempBuff;//把辅助数组拷贝到原数组
}
pBuff[len++] = data;
//3. 满足最大堆特点
int Index = len - 1;//保存根节点下标
T temp = pBuff[Index];//保存根节点数据
int parentIndex;
while (Index)
{
parentIndex = (Index-1)>>1;//父节点下标
if (temp > pBuff[parentIndex])
{
pBuff[Index] = pBuff[parentIndex];
}
else
break;
Index = parentIndex;
}
pBuff[Index] = temp;//放回堆中
}
4. 删除根节点
template<typename T>
void Heap<T>::deleteHeap()
{
if (len == 0)//空堆
return;
if (len > 1)
pBuff[0] = pBuff[len-1];
len--;//除空堆删除都要--
int Index = 0;//保存根节点下标
T temp = pBuff[Index];//保存根节点数据
//1. 不清楚树有多少层
while (true)
{
int left = Index * 2 + 1;//左子树下标
int right = Index * 2 + 2;//右子树下标
if (left >= len)
{
break;
}
//3. 到这一步,证明根节点至少有一个子节点
if (right >= len)//一定没有右子树---
{
if (pBuff[left] > temp)
{
pBuff[Index] = pBuff[left];
Index = left;
}
else
break;
}
//4. 判断和哪个子树交换
else//一定有右子树---
{
//左子树比右子树大
if (pBuff[left] > pBuff[right])
{
if (pBuff[left] > temp)
{
pBuff[Index] = pBuff[left];
Index = left;
}
else
break;
}
//右子树比左子树大
else
{
if (pBuff[right] > temp)
{
pBuff[Index] = pBuff[right];
Index = right;
}
else
break;
}
}
}
pBuff[Index] = temp;//放回堆中
}
5. 初始化堆
template<typename T>
void Heap<T>::InitHeap(T arr[],int lenght)
{
clearHeap();//初始化可以调用很多次,先清空
if (lenght == 0)
return;
Maxsize = len = lenght;
T * tempBuff = new T[Maxsize];
for (int i = 0; i < len; i++)
{
tempBuff[i] = arr[i];
}
pBuff = tempBuff;
//1. 找最后一个有子节点的节点下标
int iIndex = (len - 2)>>1;
while (iIndex+1)//到下标为0停止比较
{
int Index = iIndex;//保存根节点下标
T temp = pBuff[Index];//保存根节点数据
//2. 不清楚树有多少层
while (true)
{
int left = Index * 2 + 1;//左子树下标
int right = Index * 2 + 2;//右子树下标
if (left >= len)
{
break;
}
//3. 到这一步,证明根节点至少有一个子节点
if(right >= len)//一定没有右子树---
{
if (pBuff[left] > temp)
{
pBuff[Index] = pBuff[left];
Index = left;
}
else
break;
}
//4. 判断和哪个子树交换
else//一定有右子树---
{
//左子树比右子树大
if (pBuff[left] > pBuff[right])
{
if (pBuff[left] > temp)
{
pBuff[Index] = pBuff[left];
Index = left;
}
else
break;
}
//右子树比左子树大
else
{
if (pBuff[right] > temp)
{
pBuff[Index] = pBuff[right];
Index = right;
}
else
break;
}
}
}
pBuff[Index] = temp;//放回堆中
iIndex--;//5. 有子节点的节点下标前移
}
}
6. 输出堆
template<typename T>
void Heap<T>::printHeep()
{
for (int i = 0; i < len; i++)
{
printf("%d\n",pBuff[i]);
}
}
7. 输出根节点
template<typename T>
T const & Heap<T>::getRoot() const
{
return pBuff[0];
}
8. 清空堆
template<typename T>
void Heap<T>::clearHeap()
{
if (pBuff)
delete [] pBuff;
pBuff = nullptr;
len = Maxsize = 0;
}
9. 构造析构
template<typename T>
Heap<T>::Heap()
{
pBuff = nullptr;
len = Maxsize = 0;
}
template<typename T>
Heap<T>::~Heap()
{
clearHeap();
}