7-1 哈夫曼编码

7-1 哈夫曼编码

题目描述

本题目要求针对给定的字符串,按照哈夫曼编码原理对其进行编码(即:转换为01串),并输出其对应的哈夫曼编码。注:字符串中的字符按照ASCII码给定序号,如vggba这个字符串中的字符序号分别为43321;构建哈夫曼树时则按照序号顺序排列字符,如权值最小的两个字符为a和b,而不是b和a。

输入格式:

输入一个整数n,然后依次输入n个字符串。

输出格式:

针对每个输入的字符串,输出其哈夫曼编码。

输入样例:

2
avvvdddeeeffffgggggjk
eeeffrnvjshvhssnn

输出样例:

11110110110110100100100101101101000000000101010101111111110
11011011001001010111111001010000111000110000111111

题解思路

前言

对于基本哈夫曼树的思想我就不做解释了,其实用来构造哈夫曼树的方法很多,例如小根堆(见往期博客),数组,结构等等,我之前尝试用小根堆解决本题,但是编码结果一直和本题结果不相同,一种原因是,在removefirst之后的小根堆重建时,可能会导致相同权重的叶节点无法按照题目要求的ASCII码排序,但本次用的 struct类型的数组则不会出现这种问题。

基本思路

我们利用一个两倍长度数组来存储节点,前n个就是原本的叶子节点,后面n个就是我们不断合并的新节点,因为最开始我们是用 map 来存给定字符串的 value 和 weight,其中的顺序就是按照 value的ASCII 码的升序,同时我们是从前往后遍历,所以在构建 huffman 树的过程并不会破坏这种排序,结合代码和注释理解理解叭--------

#include <bits/stdc++.h>
using namespace std;

const int MAX = 50;
map<char,string> codeMap; //存编码

struct huffNode {
    char val;
    int weight;
    int left;
    int right;
    int parent;
    string code;
};

//初始化每个节点
void init(huffNode * huffTree, int *wgt, char *value, int n) {
    for (int i = 0; i < 2*n-1; i++) {
        huffTree[i].val = value[i];
        huffTree[i].weight = wgt[i];
        huffTree[i].left = -1;
        huffTree[i].right = -1;
        huffTree[i].parent = -1;
    }
}

//建立一颗huffTree
//我们把空间定义为叶子节点的2倍,然后合并的节点就往后加
//找到权重最小的两个节点合并,然后放到后面
 //因为我们是从前往后找,所以能保证是按照ASCII升序
void setHuffTree(huffNode * huffTree, int n) {
    int min1,min2,pos1,pos2;
    for (int i = n; i < 2*n-1; i++) {   //新节点的位置
        min1 = min2 = INT_MAX;
        pos1 = pos2 = 0;
        for (int j = 0; j < i; j++) {   //找到当前范围内的权重唯二最小
            if (huffTree[j].parent == -1 && huffTree[j].weight < min1) {
                min2 = min1;
                pos2 = pos1;
                min1 = huffTree[j].weight;
                pos1 = j;
            } else if (huffTree[j].parent == -1 && huffTree[j].weight < min2) {
                min2 = huffTree[j].weight;
                pos2 = j;
            }
        }
        //建立联系
        huffTree[pos1].parent = i;
        huffTree[pos2].parent = i;
        huffTree[i].left = pos1;
        huffTree[i].right = pos2;
        huffTree[i].weight = min1+min2;
    }
}

void huffCode(huffNode *huffTree, int n) {
    for (int i = 0; i < n; i++) {
        string nodeCode = "";
        int parent = huffTree[i].parent; 
        int curr = i;
        while (parent != -1) {   //一直找到根节点
            if (huffTree[parent].left == curr)  //左孩子
                nodeCode += "0";
            else nodeCode += "1";
            curr = parent;
            parent = huffTree[parent].parent;
        }
        reverse(nodeCode.begin(),nodeCode.end());
        huffTree[i].code = nodeCode;
        //存到map里,方便后面输出
        codeMap[huffTree[i].val] = nodeCode;
    }
}

int main() {
    int N;
    cin >> N;
    while (N--) {
        map<char,int> valMap;
        string str = "";
        cin >> str;
        for(auto x : str) valMap[x]++;
        int n = valMap.size();

        char *val = new char(MAX);
        int *wgt = new int(MAX);
        huffNode huffTree[MAX];
        int i = 0;
        for(auto it=valMap.begin(); it!=valMap.end();it++,i++) {
            val[i] = it->first;
            wgt[i] = it->second;
        }

        init(huffTree,wgt,val,n);
        setHuffTree(huffTree,n);
        huffCode(huffTree,n);

        string ans = "";
        for (auto x : str) {
            ans += codeMap[x];
        }
        cout << ans<<endl;
    }
}

学习愉快!!!

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值