哈夫曼树(堆)

一、哈夫曼树

最优二叉树,是一类带权路径长度最短的树

所谓树的带权路径长度,就是树中所有的叶节点的权值乘上其到根节点的路径长度。树的路径长度是从树根到每一节点的路径长度之和。 

 二、堆

最大(小)堆,其实就是最大(小)完全二叉树

最大堆特性:

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();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你怎么知道我头发乌黑浓密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值