第八节课:9.5:哈夫曼和堆
文章目录
一、哈夫曼
1.概念:
(1)哈夫曼树的定义:
最优二叉树,是一类带权路径长度最短树
(2)节点的带权路径的定义:(先理解路径和路径长度两个概念)
带权路径是指该节点的权重值和根节点到该节点的路径长度的乘积
例:如下图所示:节点d的带权路径是1*2 = 2
(3)路径的定义:
在一颗树中,从一个节点到另外一个节点,之间所经过的所有的节点称为路径;
如下图所示:a到d的路径为:a,b,d
(4)路径长度的定义:
在一颗树中,从一个节点到另外一个节点,之间所经过的所有的边数之和称为路径长度;
如下图所示:a到d的路径长度为2
(5)树的带权路径
所谓树的带权路径长度,就是树中所有的叶节点的权值乘上其到根节点的路径长度(若根节点为0层,叶节点到根节点的路径长度为叶节点的层数)。树的路径长度是从树根到每一个节点的路径长度之和
例:如下图树的带权路径WPL为:1*2 + 5*2 + 2*1
= 14
2.哈夫曼树的建立过程:
以后再来补上:
参考博文:哈夫曼树构建步骤和代码
3.哈夫曼树的code实现:
以后再补上:
参考博文:哈夫曼树构建步骤和代码
二、堆
1.概念:
堆本质就是完全二叉树,但是最大(小)堆的每一个节点必须要大于等于(小于等于)其任意子节点
2.特性:
(1)满足完全二叉树的特性;
(2)最大(小)堆的每一个节点必须要大于等于(小于等于)其任意子节点
3.code:
#pragma once
#include <stdio.h>
template <class T>
class CMy_heap
{
T* pBuff;
int len;
int size;
public:
CMy_heap();
~CMy_heap();
void clear();
public:
bool find(T const& find_data) const;
bool del();//删除根节点最大值(小)才有意义
void append(T const& append_data);
T const & GetRoot() const { return pBuff[0]; }
bool print() const;
bool init(T arr[], int srcLen);
private:
int _find(T const& find_data) const;
void amplify_scale();
};
template <class T>
bool CMy_heap<T>::init(T arr[], int srclen)
{
clear();
if (srclen == 0) return false;
//扩容
size = len = srclen;
pBuff = new T[size];
for (size_t i = 0; i < srclen; i++)
{
pBuff[i] = arr[i];
}
//pBuff赋值完成,但是还没有排序
for (int i = ((len - 1) >> 1); i >= 0; i--)//找到最后一个有子节点的节点
{
int current_index = i;//待插入排序的节点的坐标
int left_child_index = 2 * current_index + 1;
int right_child_index = 2 * current_index + 2;
int tempval = pBuff[current_index];//待插入排序的节点
while (right_child_index <= len - 1)//注意:这里是len - 1待删除的节点不要比较!!!!易错
{
//3.3.1判断是和左节点比较还是和右节点比较:做一个开关
int isleft = true;
if (pBuff[left_child_index] < pBuff[right_child_index]) isleft = false;
if (isleft)//和左节点比较:包括了只有左节点,左节点比右节点大的情况
{
if (tempval < pBuff[left_child_index])
{
pBuff[current_index] = pBuff[left_child_index];
}
current_index = left_child_index;
}
else//和右节点比较
{
if (tempval < pBuff[right_child_index])
{
pBuff[current_index] = pBuff[right_child_index];
}
current_index = right_child_index;
}
left_child_index = 2 * current_index + 1;
right_child_index = 2 * current_index + 2;
}
//3.3排序完成
pBuff[current_index] = tempval;
}
}
template <class T>
bool CMy_heap<T>::print() const
{
if (pBuff == nullptr) return false;
for (size_t i = 0; i < (size_t)len; i++)
{
printf("%d ",pBuff[i]);
}
return true;
}
template <class T>
bool CMy_heap<T>::del()
{
//1.空堆:
if (pBuff == nullptr) return false;
//3.2准备index坐标,左子树节点坐标和右子树节点坐标用于判断
int current_index = 0;//待插入排序的节点的坐标
int left_child_index = 2 * current_index + 1;
int right_child_index = 2 * current_index + 2;
//2.只有根节点
if (left_child_index > len);//直接len--
else//3.包含后面所有情况;
{
//3.1尾结点覆盖根节点
pBuff[0] = pBuff[len - 1];
int tempval = pBuff[current_index];//待插入排序的节点
//3.2准备index坐标,左子树节点坐标和右子树节点坐标用于判断
//3.3循环排序:
while (right_child_index < len - 1)//注意:这里是len - 1待删除的节点不要比较!!!!易错
{
//3.3.1判断是和左节点比较还是和右节点比较:做一个开关
int isleft = true;
if (pBuff[left_child_index] < pBuff[right_child_index]) isleft = false;
if (isleft)//和左节点比较:包括了只有左节点,左节点比右节点大的情况
{
if (tempval < pBuff[left_child_index])
{
pBuff[current_index] = pBuff[left_child_index];
}
current_index = left_child_index;
}
else//和右节点比较
{
if (tempval < pBuff[right_child_index])
{
pBuff[current_index] = pBuff[right_child_index];
}
current_index = right_child_index;
}
left_child_index = 2 * current_index + 1;
right_child_index = 2 * current_index + 2;
}
//3.3排序完成
pBuff[current_index] = tempval;
}
len--;
return true;
}
template <class T>
void CMy_heap<T>::amplify_scale()
{
if (len >= size)
{
size += ((size >> 1) < 1 ? 1 : (size >> 1));
T* tempbuff = new T[size];
for (size_t i = 0; i < (size_t)len; i++)//深拷贝
{
tempbuff[i] = pBuff[i];
}
//内存重分配
delete[]pBuff;
pBuff = tempbuff;
tempbuff = nullptr;
}
}
template <class T>
void CMy_heap<T>::append(T const& append_data)
{
//1.没有根节点:
if (pBuff == nullptr)
{
//扩容:
if (len >= size)
{
size += ((size >> 1) < 1 ? 1 : (size >> 1));
pBuff = new T[size];
}
pBuff[len++] = append_data;
}
//2.有根节点,进行插入操作
else
{
//2.0扩容操作:
amplify_scale();
//2.1插入节点:
pBuff[len++] = append_data;
//2.2进行插入排序:
//2.2.1准备当前节点的坐标和父亲节点的坐标
int current_index = len - 1;
int parent_index = ((current_index - 1) >> 1);
int tempval = pBuff[current_index];//保存待插入的值
//2.2.2插入操作-后移
while (parent_index >= 0 && tempval > pBuff[parent_index])//一直比较到根节点
{
pBuff[current_index] = pBuff[parent_index];
current_index = parent_index;
parent_index = ((current_index - 1) >> 1);
}
//2.2.3插入操作-最大值归位
pBuff[current_index] = tempval;
}
}
template <class T>
int CMy_heap<T>::_find(T const& find_data) const
{
for (size_t i = 0; i < (size_t)len; i++)
{
if (pBuff[i] == find_data)
return i;
}
else
return -1;
}
template <class T>
bool CMy_heap<T>::find(T const& find_data) const
{
int index = _find(find_data);
if (index != -1)
return true;
return false;
}
template <class T>
void CMy_heap<T>::clear()
{
if (pBuff)
{
delete[]pBuff;
pBuff = nullptr;
len = size = 0;
}
}
template <class T>
CMy_heap<T>::CMy_heap()
{
pBuff = nullptr;
len = size = 0;
}
template <class T>
CMy_heap<T>::~CMy_heap()
{
clear();
}