算法 哈夫曼树和哈夫曼编码

ops/2025/2/6 9:04:41/

目录

前言

一,二进制转码

二,哈夫曼编码和哈夫曼树

 三,蓝桥杯 16 哈夫曼树

总结


前言

这个文章需要有一定的树的基础,没学过树的伙伴可以去看我博客树的文章

当我们要编码一个字符串转成二进制的时候,我们要怎么操作呢?今天我们就来踏进哈夫曼编码的大门学习怎么高效编码和转码,还有学习这个思想的算法题目


一,二进制转码

方法一:二进制编码

编码字符串:ABAACDC

利用二进制:A:0     B:1     C:10     D:11

那么我们就把这个字符串编码形式:0100101110

我们来分析一下这样子编码

这样转码就会有歧义。我们不难来分析一泼,其实你分析不难发现,这个前面是有相同的前缀的
我们上面圈出来就是有前缀相同的,所以我们就会出现这种歧义的情况

方法二:等长编码

利用等长编码:A:00     B:01     C:10     D:11

然后我们就把这个字符串编码形式:00010000101110

我们每次取走两个的话这样就不会有任何的错误,但是这个长度很长,不是最优的解 

 

二,哈夫曼编码和哈夫曼树

字符串:ABAACDC

A:3次     B:1次     C:2次     D:1次

我们就有了四个节点

然后我们就需要每次合并两个最下的节点

然后我们再在3,2,2里面寻找两个最小的节点进行合并,这里面有一个2是我们B和D合并的结果,然后就是寻找两个进行合并。那么就是下面这样的情况

然后我们就剩下了4和3了

以上的树的就构造好了,这也叫哈夫曼树,然后我们在这个图上面加上0和1就好了,就可以进行编码了

然后我们就可以编码
A:1     C:01     D:001     B:000
这个编码的值就是你从根部到对应的子叶节点,然后这个边的数字组合

我们编码就是1000110100101

这个是最短且没有歧义的

前缀问题:

ABCD都是为叶子节点,所以不会再A,B,C,D,这个对应的路上,所以就不会有前缀的情况

最短问题:

出现次数越多的字符,编码越短,因为在越上面
出现次数越少的字符,编码越长,因为在越下面

在权路径:

节点值*所经过的边数(表示走了多少趟数的总路径)

哈夫曼编码不唯一,但是最终的总长是一样的

 

 三,蓝桥杯 16 哈夫曼树

问题描述
  Huffman树在编码中有着广泛的应用。在这里,我们只关心Huffman树的构造过程。
  给出一列数{pi}={p0, p1, …, pn-1},用这列数构造Huffman树的过程如下:
  1. 找到{pi}中最小的两个数,设为pa和pb,将pa和pb从{pi}中删除掉,然后将它们的和加入到{pi}中。这个过程的费用记为pa + pb。
  2. 重复步骤1,直到{pi}中只剩下一个数。
  在上面的操作过程中,把所有的费用相加,就得到了构造Huffman树的总费用。
  本题任务:对于给定的一个数列,现在请你求出用该数列构造Huffman树的总费用。
  例如,对于数列{pi}={5, 3, 8, 2, 9},Huffman树的构造过程如下:
  1. 找到{5, 3, 8, 2, 9}中最小的两个数,分别是2和3,从{pi}中删除它们并将和5加入,得到{5, 8, 9, 5},费用为5。
  2. 找到{5, 8, 9, 5}中最小的两个数,分别是5和5,从{pi}中删除它们并将和10加入,得到{8, 9, 10},费用为10。
  3. 找到{8, 9, 10}中最小的两个数,分别是8和9,从{pi}中删除它们并将和17加入,得到{10, 17},费用为17。
  4. 找到{10, 17}中最小的两个数,分别是10和17,从{pi}中删除它们并将和27加入,得到{27},费用为27。
  5. 现在,数列中只剩下一个数27,构造过程结束,总费用为5+10+17+27=59。
输入格式
  输入的第一行包含一个正整数n(n<=100)。
  接下来是n个正整数,表示p0, p1, …, pn-1,每个数不超过1000。
输出格式
  输出用这些数构造Huffman树的总费用。

输入样例:

在这里给出一组输入。例如:

5
5 3 8 2 9

输出样例:

在这里给出相应的输出。例如:

59

代码:

#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;int main(){vector<int>number;vector<int>temp;int n=0;cin>>n;//添加元素到容器里面for(int i=0;i<n;i++){int num=0;cin>>num;number.push_back(num);}//进行排序while(!number.empty()){sort(number.begin(),number.end());int operand1=*number.begin();int operand2=0;number.erase(number.begin());//弹出对应元素if(!number.empty()){operand2=*number.begin();number.erase(number.begin());}int sumoperand=operand1+operand2;temp.push_back(sumoperand);if(!number.empty()){number.push_back(sumoperand);}}int sum=0;for(int i=0;i<temp.size();i++){sum=sum+temp[i];}cout<<sum<<endl;
}

 这个是自己写的,如果有更好地过程,可以在评论区指教

思路:

1,先创建两个容器,一个用来存放数字,一个用来存放两个数字相加和

2,先把数字放到容器里面

3,利用sort()函数进行排序,升序

4,然后不断地抽取这个容器前面两个元素进行相加

5,把相加地元素放到第二个元素里面,然后如果第一个容器为空,说明第一个容器没有可以加地了,就不放了,如果有就继续放

6,最后不断地加这个容器里面地每一个元素就好了,这个循环的次数为这个容器的大小就好了


总结

哈夫曼树的构造就是不断地把最小地合并得出一个数字,然后再从这些数字寻找两个最小的数字求和,不断地把数弄没有为止,注意每次求和要带上那个两个地求和地数字,编码就是再边上赋予0和1就好了


http://www.ppmy.cn/ops/156111.html

相关文章

【回溯+剪枝】电话号码的字母组合 括号生成

文章目录 17. 电话号码的字母组合解题思路&#xff1a;回溯 哈希表22. 括号生成解题思路&#xff1a;回溯 剪枝 17. 电话号码的字母组合 17. 电话号码的字母组合 ​ 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 …

寻路算法:A*算法。

在2D应用场景中&#xff0c;会出现寻找最短路径的情况。可以运用的算法很多&#xff0c;广度优先算法&#xff0c;曼哈顿算法等等。虽然可以最终访问到。但是为了节省性能&#xff0c;推荐使用A*算法。 1.图示 2.基本原理 遍历一个点周围的点。看看那个点的寻路消耗最小。再以…

31.Word:科技论文的译文审交稿【31】

目录 NO1.2.3​ NO4.5.6 NO7.8样式应用和修改&多级列表​ NO9奇偶页页眉 NO10自动编号&交叉引用 NO11.12 NO1.2.3 另存为/F12&#xff1a;考生文件夹只保留译文内容、格式设置、修订批注&#xff0c;删除其他&#xff1a;删除表格的左列→删除第一行将表格转化成…

解锁C/C++:链表数据结构的奇幻之旅

目录 一、引言二、链表基础概念2.1 链表是什么2.2 链表的类型三、C 语言实现链表3.1 定义链表节点3.2 创建链表3.3 链表操作3.3.1 遍历链表3.3.2 插入节点3.3.3 删除节点3.3.4 查找节点3.4 完整示例代码四、C++ 实现链表4.1 定义链表节点类4.2 创建链表4.3 链表操作4.3.1 遍历链…

双亲委派(jvm)

1.双亲委派 在 Java 中&#xff0c;双薪委派通常是指双亲委派模型&#xff0c;它是 Java 类加载器的一种工作模式&#xff0c;用于确保类加载的安全性和一致性。以下是其相关介绍&#xff1a; 定义与作用 定义&#xff1a;双亲委派模型要求除了顶层的启动类加载器外&#xf…

Java常见的技术场景面试题

一、单点登录这块怎么实现的&#xff1f; 单点登录概述 单点登录&#xff1a;Single Sign On&#xff08;简称SSO&#xff09;,只需要登录一次&#xff0c;就可以访问所有信任的应用系统 在以前的时候&#xff0c;一般我们就单系统&#xff0c;所有的功能都在同一个系统上。…

C#面试常考随笔15:C#的GC原理是什么?

基本概念 托管堆:在 C# 中,对象的内存分配主要发生在托管堆上。当创建一个对象时,CLR 会在托管堆上为其分配一块连续的内存空间。引用计数:引用计数是一种简单的内存管理方法,它通过记录每个对象被引用的次数来判断对象是否可以被回收。当引用计数为 0 时,对象就可以被回…

STM32 TIM编码器接口测速

编码器接口简介&#xff1a; Encoder Interface 编码器接口 编码器接口可接收增量&#xff08;正交&#xff09;编码器的信号&#xff0c;根据编码器旋转产生的正交信号脉冲&#xff0c;自动控制CNT自增或自减&#xff0c;从而指示编码器的位置、旋转方向和旋转速度 每个高级定…