哈夫曼树的实现

具体的原理可以去看原博主的文章,很详细。

/*构造哈夫曼树的算法步骤:

① 初始化:用给定的 n 个权值{w1,w2,…,wn}构造 n 棵二叉树并构成的森林F={T1,T2,…,Tn},其中每一棵二叉树Ti(1<=i<=n)都只有一个权值为 wi 的根结点,其左、右子树为空。

② 找最小树:在森林 F 中选择两棵根结点权值最小的二叉树,作为一棵新二叉树的左、右子树,标记新二叉树的根结点权值为其左、右子树的根结点权值之和。

③ 删除与加入:从 F 中删除被选中的那两棵二叉树,同时把新构成的二叉树加入到森林 F 中。

④ 判断:重复②、③操作,直到森林中只含有一棵二叉树为止,此时得到的这棵二叉树就是哈夫曼树。

简单的说就是先选择权小的,所以权小的结点被放置在树的较深层,而权较大的离根较近,这样一来所构成的哈夫曼树就具有最小带权路径长度。

————————————————

版权声明:本文为CSDN博主「素锦流年つ」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/weixin_51450101/article/details/122893828*/

#include <climits>

#include<iostream>

#include <vector>



using namespace std;



typedef struct {

    int weigth;    // 出现的次数

    int code;      // 当前点的哈夫曼编码

    int ParLabel;  // 当前点的父节点标签

    int LChLabel;  // 当前点的左子叶节点标签

    int RChLabel;  // 当前点的右子叶节点标签

}HuffmanNode;



// 次函数将完成挑选权重最小的父节点,以建树

void myselect(vector<HuffmanNode>& HT, int sz, int* label1, int* label2){

    int min1 = INT_MAX, min2 = INT_MAX;

    *label1 = 0, *label2 = 0;

    for(int j = 1; j <= sz; j++){

        if(HT[j].code == 0){

            if(HT[j].weigth < min1){ // min1是最小的一个

                // 先把min1的当前值给到老二(min2)

                min2 = min1;

                *label2 = *label1;

                // 再更新自己

                min1 = HT[j].weigth;

                *label1 = j;

            }

            else if (HT[j].weigth < min2) {

                min2 = HT[j].weigth;

                *label2 = j;

            }

        }

    }// 最后返回的是最小父节点的两个标签



}

int main(){

    int CharTypeNumber = 0;

    cin >> CharTypeNumber;

    // 用vector来记录哈夫曼树

    vector<HuffmanNode> HuffmanTree(CharTypeNumber+1, {0});

    HuffmanTree[0] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX};

    for(int i = 1; i < CharTypeNumber + 1; i++){

        cin >> HuffmanTree[i].weigth;

    }

    // 开始建树操作

    for(int j = 0; j < CharTypeNumber - 1; j++){

        int l1 = 0, l2 = 0;

        myselect(HuffmanTree, CharTypeNumber + j, &l1, &l2);

        HuffmanNode temp = {0};

        temp.weigth = HuffmanTree[l1].weigth + HuffmanTree[l2].weigth;

        HuffmanTree[l1].code = 1; // 利用code来标志是否访问过该子树

        HuffmanTree[l2].code = 1; // 利用code来标志是否访问过该子树

        temp.LChLabel = l1;

        temp.RChLabel = l2;

        HuffmanTree.push_back(temp);

        HuffmanTree[l1].ParLabel = HuffmanTree.size()-1;

        HuffmanTree[l2].ParLabel = HuffmanTree.size()-1;

        HuffmanTree[HuffmanTree.size()-1].ParLabel = 0;

    }

    // 开始编码操作,顺带把路径和长度算了

    int k = HuffmanTree.size() - 1;

    int depth = 0, sum = 0;

    while(HuffmanTree[k].LChLabel != 0 && HuffmanTree[k].RChLabel != 0){

        int l1 = 0, l2 = 0;

        l1 = HuffmanTree[k].LChLabel;

        l2 = HuffmanTree[k].RChLabel;

        HuffmanTree[l1].code = 0;

        HuffmanTree[l2].code = 1;

        // 上面完成了编码,下面是算路径和长度

        /*depth++;

        if(HuffmanTree[l1].LChLabel == 0 && HuffmanTree[l1].RChLabel == 0){

            sum = depth*HuffmanTree[l1].weigth + sum;

        }

        if(HuffmanTree[l2].LChLabel == 0 && HuffmanTree[l2].RChLabel == 0){

            sum = depth*HuffmanTree[l2].weigth + sum;

        }*/

        k--;

    }

    cout << sum << endl;

    return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值