520礼物(利用权重数组建赫夫曼树)

简介: 520礼物(利用权重数组建赫夫曼树)

求赫夫曼编码长度


题目描述

每行一个大小写英文字母组成的字符串,长度不大于 1000,通过前缀编码后最短的编码长度。

输入

第一行输入一个整数t,表示有t组测试数据;

接下来输入t组测试数据,每组数据一行,大小写英文字母。

输出

每组数据输出赫夫曼编码长度

样例输入
4
AABBCCDEEEE
AAABCCC
BBACB
tPvlQHFbPN
样例输出
25
11
7
32
提示
  • 解题思路
  1. 将字符串转换成权重数组
for( int i=0, l= strlen(s); i<l; i++){
    a[ s[i]- 'A']++; // 在ascill里面大写的字母比小
}
  1. 初始化赫夫曼树节点的初始权重
// 初始化w数组
 int wl=1;
 w[0] = big;
 for(int i=0 ; i<99; i++  ){
     if( a[i] != 0 ){
         w[wl++] = a[i];
     }
 }
 wl--;
 root = 2*wl-1;
  1. 搜索最小权重的两棵子树,合并成一棵新树,并入权重数组
  2. dfs 计算赫夫曼编码长度
  • 完整代码
#include<iostream>
#include<cstring>
using namespace std;
const int big = 999;
struct Node{
    int parent,weight,left, right; 
};
Node node[100];
int a[99];
int w[99];
char s[1005];
int root;           // 赫夫曼树根节点下标
int ans;            //赫夫曼树编码的长度
// 搜索权重最小的数组下标
void search(int w[],int &m1,int  &m2, int len){
    for(int i=1; i <= len; i++ ){
        if( w[m1] > w[i] ){
            m1 = i;
        }
    }
    w[m1] = big;
    for(int i=1; i<=len; i++){
        if( w[m2] > w[i] ){
            m2 = i;
        }
    }
    w[m2] = big;
};
// 深搜求长度
void dfs(int index, int cnt){
    int l = node[index].left;
    int r = node[index].right;
    if(l==-1 && r==-1){
        // cout<<"index="<<index<<" cnt="<<cnt<<endl;
        ans += node[index].weight * cnt;
    }
    if(l!=-1){
        dfs(l,++cnt);
        cnt--;  // 注意搜索回溯的时候要将计数器 -1 
    }
    if(r!=-1){
        dfs(r,++cnt);
        cnt--;
    }
}
int main(){
    int t;
    cin >> t;
    while(t--){
        memset(s,'\0', sizeof(s));
        memset(a, 0, sizeof(a));
        memset(w, 0, sizeof(w));
        cin >> s;
        for( int i=0, l= strlen(s); i<l; i++){
            a[ s[i]- 'A']++; // 在ascill里面大写的字母比较小
        }
        // 初始化w数组
        int wl=1;
        w[0] = big;
        for(int i=0 ; i<99; i++  ){
            if( a[i] != 0 ){
                w[wl++] = a[i];
            }
        }
        wl--;
        root = 2*wl-1;
        for(int i=1; i<=root; i++){
            node[i].parent = node[i].left = node[i].right = node[i].weight = -1;
        }
        for(int i=1; i<=wl; i++){
            node[i].weight = w[i];
        }
        // 建树
        for(int i = wl+1; i<=root; i++){
            int m1=0, m2=1;
            search(w, m1, m2, wl);
            node[i].left = m1;
            node[i].right = m2;
            node[i].weight = node[m1].weight + node[m2].weight;
            node[m1].parent = node[m2].parent = i;
            w[++wl] = node[m1].weight + node[m2].weight; 
        }
        // for(int i=root; i>0; i--){
        //     cout<<"i="<<i<<"node[i].parent="<<node[i].parent<<" weight="<<node[i].weight<<" left="<<node[i].left<<" right=" <<node[i].right<<endl;
        // }
        dfs(root,0);
        cout<< ans <<endl;
        ans = 0;
    }
    return 0;
}


相关文章
|
6月前
|
人工智能 BI 测试技术
【深度优先搜索】【图论】【树】2646. 最小化旅行的价格总和
【深度优先搜索】【图论】【树】2646. 最小化旅行的价格总和
|
6月前
|
Go 算法
在运势计算中运用BST树
【5月更文挑战第3天】该文介绍了使用树进行简单的运势推算。通过`TaoBstManager`结构体管理运算,包括树的结构、变化节点和爻卦含义。提供了遍历、显示节点的功能以及执行“一变”和“一爻三变”的方法。最终,通过`YaoWithReBuild`生成六爻并形成一卦。代码实现可在给定的GitHub链接中查看。
58 0
在运势计算中运用BST树
|
6月前
|
人工智能 算法 BI
【深度优先搜索 图论 树】2872. 可以被 K 整除连通块的最大数目
【深度优先搜索 图论 树】2872. 可以被 K 整除连通块的最大数目
|
6月前
leetcode代码记录(二叉树的最小深度
leetcode代码记录(二叉树的最小深度
27 0
|
6月前
|
人工智能 算法 BI
【树】【因子数】【数论】【深度优先搜索】2440. 创建价值相同的连通块
【树】【因子数】【数论】【深度优先搜索】2440. 创建价值相同的连通块
|
6月前
|
人工智能 算法 BI
【图论】【树】 【拓扑排序】2603. 收集树中金币
【图论】【树】 【拓扑排序】2603. 收集树中金币
|
6月前
|
人工智能 算法 BI
【深度优先搜索】【树】【图论】2973. 树中每个节点放置的金币数目
【深度优先搜索】【树】【图论】2973. 树中每个节点放置的金币数目
|
6月前
|
人工智能 算法 BI
【深度优先搜索】【C++算法】834 树中距离之和
【深度优先搜索】【C++算法】834 树中距离之和
|
6月前
|
机器学习/深度学习 测试技术
【图论】【状态压缩】【树】【深度优先搜索】1617. 统计子树中城市之间最大距离
【图论】【状态压缩】【树】【深度优先搜索】1617. 统计子树中城市之间最大距离
|
算法
代码随想录算法训练营第十八天 | 力扣 513. 找树左下角的值、112. 路径总和、113. 路径总和 II、106. 从中序与后序遍历序列构造二叉树、105. 从前序与中序遍历序列构造二叉树
代码随想录算法训练营第十八天 | 力扣 513. 找树左下角的值、112. 路径总和、113. 路径总和 II、106. 从中序与后序遍历序列构造二叉树、105. 从前序与中序遍历序列构造二叉树
53 0