哈夫曼树,哈夫曼编码及解码详解

这篇具有很好参考价值的文章主要介绍了哈夫曼树,哈夫曼编码及解码详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🌍新人小白的博客
⌛️希望大家多多关注
🌱一起加油,共同成长
🎃以后会经常更新哒~🙈
⭐️个人主页: 收藏加关注,永远不迷路~⭐️

数据结构系列👀

一:顺序表的操作,你真的学会了吗?
二:顺序栈的基本操作
三:循环队列的基本操作,你学会了吗?
四:单链表的操作(超详细),保证你看完不后悔
五:5分钟带你快速解决二叉树问题,你确定不进来看看?


前言😺

Tips:文章有点长,小主耐心一点哦~

介绍哈夫曼树,掌握哈夫曼树及哈夫曼编码的构造过程,体会网络发送端和接收端编码和译码过程及其工作原理。
哈夫曼树,哈夫曼编码及解码详解


一、问题描述😜

给定报文中26个字母a-z及空格的出现频率{64, 13, 22, 32, 103, 21, 15, 47, 57, 1, 5, 32, 20, 57, 63, 15, 1, 48, 51, 80, 23, 8, 18, 1, 16, 1, 168},构建哈夫曼树并为这27个字符编制哈夫曼编码,并输出。模拟发送端,从键盘输入字符串,以%为结束标记,在屏幕上输出输入串的编码;模拟接收端,从键盘上输入0-1哈夫曼编码串,翻译出对应的原文。


二、实现步骤🙊

1.定义存储表示

2.定义操作函数

定义选择权值最小的函数Select,构造哈夫曼树的函数CreatHuffmanTree,创建哈夫曼编码的函数CreateHCode,打印哈夫曼编码函数PrintHTree,按输入的字符打印编码函数Printe,字符转码函数change,解码函数decoding

3. 采用菜单样式让操作更加方便清楚。

4.调试实验代码并进行相关测试,得出实验结果。

三、完整代码🐻

代码可直接运行😄

#include <iostream>
#include <cstring>
#include <algorithm>
#include <iomanip>

using namespace std;

int m,n;

// int letter[27] = {64, 13, 22, 32, 103, 21, 15, 47, 57, 1, 5, 32, 20, 57, 63, 15, 1, 48, 51, 80, 23, 8, 18, 1, 16, 1, 168};
// 64 13 22 32 103 21 15 47 57 1 5 32 20 57 63 15 1 48 51 80 23 8 18 1 16 1 168
int letter[28]; // 用于存储26个字母以及空格的出现的概率次数
char lee[28] = {' ','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',' '};

// 动态分配数组存储哈夫曼编码表
typedef char** HCode;

// 哈夫曼树的存储结构
typedef struct
{
    int w;
    int parent,lchild,rchild;
} HTNode,*HTree;

// 全局调用
HTree T;
HCode HC;

// ======================= 哈夫曼树的构造 ===========================

// 在树T中,k为节点的总个数,获取两个节点权值最小的值
void Select(HTree T,int k,int &s1,int &s2)
{
    int tmp = 100000,tmp1 = 100000;
    // 先获得一个最小的,然后再获得倒数第二小的,依次遍历,求最小权值
    for(int i = 1; i <= k; i ++)
    {
        if(!T[i].parent)
        {
            if(tmp > T[i].w)
            {
                tmp = T[i].w;
                s1 = i;
            }
        }
    }
    for(int i = 1; i <= k; i ++)
    {
        if(!T[i].parent && i != s1)
        {
            if(tmp1 > T[i].w)
            {
                tmp1 = T[i].w;
                s2 = i;
            }
        }
    }
}

// 构造哈夫曼编码树
void CreateHuffmanTree(HTree &T,int n) // n 是指叶子节点的个数
{
    if(n <= 1) return ;
    m = 2 * n - 1; // 拥有n个叶子结点的哈夫曼树共有2n-1个结点
    T = new HTNode[m + 1]; // 分配单元,存放结点
    for(int i = 1; i <= m; i ++)
    {
        T[i].parent = 0;
        T[i].lchild = 0;
        T[i].rchild = 0;
        T[i].w = 0;
    }
    for(int i = 1; i <= n; i ++) T[i].w = letter[i]; // 将输入的权值赋给每个结点的权值

    for(int i = n+1; i <= m; i ++)
    {
        int s1 = 0,s2 = 0;
        // 选择两个双亲域为0,且权值最小的节点,并返回他们的序号s1,s2;
        Select(T,i - 1, s1,s2);

        // 得到新节点i,从森林中删除s1,s2,将s1,s2的双亲域由0变为i
        T[s1].parent = i;
        T[s2].parent = i;

        // s1,s2为新节点的两个孩子,i的权值是两个子孩子的和
        T[i].lchild = s1;
        T[i].rchild = s2;
        T[i].w = T[s1].w + T[s2].w;
    }
}

// ======================= 哈夫曼树编码的生成 ===========================

// 创建哈夫曼编码
void CreateHCode(HTree T, HCode &HC, int n)
{
    HC = new char* [n + 1]; // 存放n个字符的编码的表
    char* cd = new char[n]; // 临时存放每个字符的编码

    cd[n - 1] = '\0'; // 编码结束符

    // 一次得到每个结点的编码
    for(int i = 1; i <= n; i ++)
    {
        // start 一般指向最后一个 ,倒着开始遍历
        int start = n - 1;
        int c = 0, f = 0;
        c = i;
        f = T[i].parent;
        while(f != 0)
        {
            -- start ;
            if(T[f].lchild == c) cd[start] = '0';
            else cd[start] = '1';
            c = f ;
            f = T[f].parent;
        }
        HC[i] = new char[n - start];
        // 从 start 后的所有值 复制给 HC[i]
        strcpy(HC[i], &cd[start]);
    }
    delete cd;
}

// 打印哈夫曼编码的打印
void PrintHTree(HCode &HC,int n)
{
    cout << std::left << setw(10) <<"字母" << std::left << setw(10) << "编码" << endl;

    for(int i = 1; i <= n; i ++)
    {
        // std::left 使后面输出的值向左对齐
        cout << std::left << setw(10) << lee[i] ;
        string str = HC[i];
        cout << std::left << setw(10) << str << endl;
    }
}


//======================= 字符的转码功能 ============================


// 按输入的字符打印编码
void Printe(HCode &HC,int l)
{
    string str = HC[l];
    cout <<str;
}

// 字符的转码
void change()
{
    cin.ignore();
    char a[100]; // 最多输入一百个字符,包含空格
    cin.getline(a,100);
    int len = strlen(a);
    for(int i = 0; i < len ; i ++)
    {
        int l = a[i]; // 转化为ASCII值
        if(a[i] == ' ') l = 27;
        else if(l >= 97)
        {
            l -= 96;
        }
        else if(l < 97 && l >= 65)
        {
            l -= 64;
        }
        Printe(HC,l);
    }
    cout << endl;
}


// ======================== 哈夫曼编码解码 =================================

void decoding(HCode &HC,int n,string s)
{
    string temp = ""; // 依次获取一个字符,并和编码表里面的字符串对比
    char str[1000]; // 用来存放解码后的数字
    for(int i = 0; i < 1000; i ++) str[i] = '1'; // 每次定义char ,防止上次的结果影响这次的答案
    int h = 0; // str 存储的下标
    for(unsigned int i = 0; i < s.length(); i ++)
    {
        temp = temp + s[i]; // 依次获取一个字符
        for(int j = 1; j <= n; j ++)
        {
            string str2 = HC[j];
            if(temp == str2)
            {
                str[h ++] = lee[j];
                temp = "";
            }
            else if(i == s.length() - 1&& j == n  && temp != "")
            {
                cout <<"解码错误";
                break;
            }
        }
    }
    for(int i = 0; i < 1000 ; i ++)
    {
        if(str[i] != '1') cout << str[i];
        else break;
    }
    cout << endl;
}

// ==================== 功能的展示 ============================

void show()
{
    cout <<"1 ---- 输入26字母的出现频率" << endl;
    cout <<"2 ---- 创建哈夫曼树和编码表,并输出编码表" << endl;
    cout <<"3 ---- 输入字符,并实现转码" << endl;
    cout <<"4 ---- 输入编码,并翻译为字符" << endl;
    cout <<"5 ---- 退出" << endl;

}

int main()
{
    show();
    memset(letter, 0,sizeof letter);
    n = 27;
    m = 2*n - 1;
    char fir;
    while(cin >> fir)
    {
        if(fir == '1')
        {
            for(int i = 1; i <= n; i ++)
            {
                cin >> letter[i];
            }
        }
        else if(fir == '2')
        {
            CreateHuffmanTree(T,n);
            CreateHCode(T,HC,n);
            PrintHTree(HC,n);
        }
        else if(fir == '3')
        {
            change();
        }
        else if(fir == '4')
        {
            string s;
            cin >> s;
            decoding(HC,n,s);
        }
        else if(fir == '5')
        {
            exit(0);
        }
        else
        {
            cout << "请输入合法的字符"<<endl;
            show();
        }
    }

    return 0;
}


四、运行结果🐾

这里是运行的结果哦 ❤️

1.模拟发送端
输入:I love you
输出:01101111011110011100000010111100011100100001
2.模拟接收端 输入
输入:01101101111011000111111010111101101001100001
输出:it is a dog
哈夫曼树,哈夫曼编码及解码详解
哈夫曼树,哈夫曼编码及解码详解


结语🌍

通过该实验,理解哈夫曼树的概念,掌握哈夫曼树哈夫曼编码的构造过程,体会网络发送端接收端编码和译码过程及其工作原理。🚀🚀🚀

哈夫曼树,哈夫曼编码及解码详解


如果有什么问题或者建议,欢迎在评论区留言哦,博主会第一时间回复哒❤️❤️❤️
哈夫曼树,哈夫曼编码及解码详解文章来源地址https://www.toymoban.com/news/detail-445580.html

到了这里,关于哈夫曼树,哈夫曼编码及解码详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 15哈夫曼树/哈夫曼编码

    哈夫曼树又称为 最优树 ,作用是找到一种效率最高的判断树。 路径 :从树中一个结点到另一个结点之间的 分支 构成这两个结点之间的路径。 结点的路径长度 :两结点间路径上的分支树 如图 a :从 A - D 的路径长度就是是 2。从 A 到 B C D E F G F I 的路径长度分别为 1 1 2 2 3

    2024年02月05日
    浏览(44)
  • 哈夫曼树与哈夫曼编码

    哈夫曼树:结点中赋予一个某种意义的值,称为结点的权值,从根结点开始,到目标结点经过的边数,称为路径长度,路径长度乘以权值,称为带权路径长度; 例如:根结点代表着快递集散点,一个叶子结点权值是5,在业务逻辑中代表着重量是5斤的货物📦,路径长度是3,

    2024年02月05日
    浏览(49)
  • 哈夫曼树、哈夫曼编码和字典树

    目录 哈夫曼树 树的带权路径长度(wpl) 哈夫曼编码 代码实现哈夫曼树 封装哈夫曼树的节点 构建哈夫曼树 字典树 执行流程 代码实现字典树 封装字典树的节点 构建字典树         哈夫曼树(Huffman Tree)是一种带权路径长度最短的二叉树。哈夫曼树常常用于数据压缩,其压

    2023年04月09日
    浏览(50)
  • 数据结构——哈夫曼树与哈夫曼编码

    1.1 基本概念 路径 :指从根结点到该结点的分支序列。 路径长度 :指根结点到该结点所经过的分支数目。 结点的带权路径长度 :从树根到某一结点的路径长度与该结点的权的乘积。 树的带权路径长度(WPL) :树中从根到所有叶子结点的各个带权路径长度之和。 哈夫曼树 是由

    2024年02月05日
    浏览(46)
  • 数据结构之哈夫曼树和哈夫曼编码

    切入正题之前,我们先了解几个概念: 路径:从树的一个结点到另一个结点分支所构成的路线 路径长度:路径上的分支数目 树的路径长度:从根结点出发到每个结点的路径长度之和 带权路径长度:该结点到根结点的路径长度乘以该结点的权值 树的带权路径长度:树中所有

    2024年02月11日
    浏览(46)
  • 数据结构之哈夫曼树与哈夫曼编码

    编码是信息处理的基础(重新表示信息)。 普通的编码是等长编码,例如7位的ASCIL编码,对出现频率不同的字符都使用相同的编码长度。 但其在传输和存储等情况下编码效率不高 。 可使用不等长编码,来压缩编码:高频字符编码长度更短,低频字符编码长度更长。   [例

    2023年04月15日
    浏览(64)
  • 哈夫曼树及哈夫曼编码(考试常考版)

    哈夫曼树的基本概念 哈夫曼树的定义是对一组具有确定权值的叶子节点,选出最小带权路径长度的二叉树为哈夫曼树(WPL最小),也称最优二叉树 哈夫曼算法的实现 注意:哈夫曼树在构造时选择两个最小的权值点,默认小的在左边大的在右边,但实际上并没有硬性规定,可以

    2024年02月11日
    浏览(57)
  • 数据结构课程实验五:哈夫曼树与哈夫曼编码

    实验日期:2022-12-20   目录 一、实验目的 1、掌握哈夫曼树的建立 2、掌握哈夫曼编码方式 二、实验内容

    2024年02月05日
    浏览(50)
  • 【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码

    超详细讲解哈夫曼树(Huffman Tree)以及哈夫曼编码的构造原理、方法,并用代码实现。 路径 :从树中一个结点到另一个结点之间的 分支 构成这两个结点间的路径。 结点的路径长度 :两结点间路径上的 分支数 。 树的路径长度: 从树根到每一个结点的路径长度之和。记作: TL  权

    2024年02月06日
    浏览(53)
  • 哈夫曼编码

    一、 哈夫曼编码介绍 1:什么样的前缀码能使得电文的总长最短? 2、哈夫曼编码案例 3、哈夫曼编码优势 4、哈夫曼编码示例

    2024年02月16日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包