1.概要
信源编码是一种信息编码技术,旨在提高通信系统的有效性,通过压缩信息的冗余度来实现。在编码理论指导下,先后出现了许多性能优良的编码方法,根据信源的性质进行分类,则有信源统计特性已知或未知、无失真或限定失真、无记忆或有记忆信源的编码;按编码方法进行分类,可分为分组码或非分组码、等长码或变长码等。然而最常见的是讨论统计特性已知条件下,离散、平稳、无失真信源的编码,消除这类信源剩余度的主要方法有统计匹配编码和解除相关性编码。例如,香农码、哈夫曼码属于不等长度分组码,算术编码属于非分组码,预测编码和变换编码是以解除相关性为主的编码。在此简要介绍常见信源编码中香浓编码与哈夫曼编码,以及利用MATLAB二者的方法。
2.香浓编码
香农编码是一种基于概率的编码方法,由克劳德·香农在1948年首次提出。其核心思想是利用符号出现概率的不均匀性来最小化平均编码长度。具有以下特点:
- 属于不等长编码,通常将经常出现的消息变成短码,不经常出现的消息编成长码。
- 编码所得的码字没有相同的,所以是非奇异码,也没有一个码字是其他码字的前缀,所以是即时码,也是唯一可译码。
具体步骤如下:
1. 将信源符号按概率从大到小顺序排列。
2. 计算第 i 个符号对应的码字的码长(向上取整),码长计算公式为:
3. 计算第 i 个符号的累加概率。
4. 将累加概率变换成二进制小数,取小数点后相应位数作为第 i 个符号的码字。
下面是用matlab实现香浓编码
clear all
clc
% 输入离散信源的概率分布
p = input('请输入离散信源概率分布,例如[0.5,0.5]:\n');
% 获取概率分布的长度
N = length(p);
% 计算每个符号的理论最短码长(向上取整)
L = ceil(-log2(p));
% 对概率进行降序排序,并记录原始索引
[p_SortDescend,reflect] = sort(p,'descend');
% 初始化累积概率数组和码字数组
P = zeros(1,N);
CODE = strings(1,N);
for i=1:N
% 初始化当前符号的码字(长度为该符号的理论最短码长)
code = zeros(1,L(reflect(i)));
% 对于第一个符号,累积概率为0,码字为空(实际上在这里被初始化为全0数组)
if i==1
P(1)=0;
CODE(reflect(i)) = num2str(code);
else
% 计算当前符号之前的所有符号的累积概率
P(i) = sum(p_SortDescend(1:i-1));
end
p_count = P(i)*2;
for m=1:L(reflect(i))
if p_count >= 1 % 根据p_count的值决定码字的每一位
code(m) = 1;
p_count = p_count-1;
else
code(m) = 0;
end
p_count = p_count*2;
end
% 将生成的码字转换为字符串并保存到CODE数组中
CODE(reflect(i)) = num2str(code);
end
% 计算信源熵
H = sum(-p.*log2(p));
% 计算平均码长
L_ave = sum(L.*p);
% 计算编码效率
yita = H/L_ave;
fprintf('\n运行结果:\n');
disp(['信号符号: ',num2str(1:N)]);
disp(['对应概率: ',num2str(p)]);
fprintf('对应码字:');disp(CODE);
disp(['平均码长:',num2str(L_ave)]);
disp(['编码效率:',num2str(yita)]);
运算结果为:
[0.2,0.3,0.1,0.1,0.18,0.12]
信号符号: 1 2 3 4 5 6
对应概率: 0.2 0.3 0.1 0.1 0.18 0.12
对应码字: "0 1 0" "0 0" "1 1 0 0" "1 1 1 0" "1 0 0" "1 0 1 0"
平均码长:3.02
编码效率:0.81531
不过,香农编码在实际应用中存在一定局限性,其效率不高,实用性相对不大。一般情况下,按照香农编码方法编出来的码,其平均码长不是最短的,即不是紧致码(最佳码)。只有当信源符号的概率分布使特定不等式左边的等号成立时,编码效率才达到最高。但香农编码对其他编码方法具有很好的理论指导意义,为后续数据压缩技术的发展提供了重要基础。
3.哈夫曼编码
哈夫曼编码是一种广泛使用的数据压缩算法,它基于字符出现的频率来构建一种最优前缀码。这种编码方法由David A. Huffman在1952年提出,并被广泛应用于各种数据压缩系统中,包括文件压缩、图像压缩和网络数据传输等领域。其基本原理是基于二叉树的编码思想,所有可能的输入符号在哈夫曼树上对应一个节点,节点的位置就是该符号的哈夫曼编码。为了构造出唯一可译码,这些节点都是哈夫曼树上的终级节点,不再延伸,不会出现前缀码。具体编码方法如下:
-
将信源符号按概率递减的方式进行排列
;
-
从队尾给m个最小的概率进行m元标号,如二进制下将两个概率最小的符号,分别配为0和1两个码元,并将这两个概率相加作为一个新字母的概率,与未分配的二进制符号的字母一起重新排队,重复此步骤直至概率和为1;
-
从最后一级开始,向前返回得到各个信源符号所对应的码元序列,即相应的码字。
哈夫曼编码的一种matlab实现如下:
function huffman(P)
%输入:P信源概率矩阵
N=length(P);
Q=P;
Index=zeros(N-1,N);
for i=1:N-1
[Q,L]=sort(Q); %将P中的元素按升序排序后,元素放到Q中,对应的索引值存到L中
Index(i,:)=[L(1:N-i+1),zeros(1,i-1)];
G(i,:)=Q;%缩减信源得到的最终矩阵
%Index为N-1行、N列矩阵,用来记录每行最小两概率叠加后概率排列次序,元素不足的地方补0
%参考doc sort
Q=[Q(1)+Q(2),Q(3:N),1]; %将Q中概率最小的两个元素合并,元素不足的地方补1
end
%根据以上建立的Index矩阵,进行回溯,获取信源编码
for i=1:N-1
Char(i,:)=blanks(N*N);
end
%从码树的树根向树叶回溯,即从G矩阵的最后一行按与Index中的索引位置的对应关系向其第一行进行编码
Char(N-1,N)='0';%G中的N-1行即最后一行第一个元素赋为0,存到Char中N-1行的N列位置
Char(N-1,2*N)='1';%G中的N-1行即最后一行第二个元素赋为1,存到Char中N-1行的2*N列位置
%以下从G的倒数第二行开始向前编码
for i=2:N-1
Char(N-i,1:N-1)=Char(N-i+1,N*(find(Index(N-i+1,:)==1)) -(N-2):N*(find(Index(N-i+1,:)==1)));
%将Index后一行中索引为1的编码码字填入到当前行的第一个编码位置
Char(N-i,N)='0'; %然后在当前行的第一个编码位置末尾填入'0'
Char(N-i,N+1:2*N-1)=Char(N-i,1:N-1); %将G后一行中索引为1的编码码字填入到当前行的第二个编码位置
Char(N-i,2*N)='1'; %然后在当前行的第二个编码位置末尾填入'1'
for j=1:i-1
%内循环作用:将Index后一行中索引不为1处的编码按照左右顺序填入当前行的
%第3个位置开始的地方,最后计算到Index的首行为止
Char(N-i,(j+1)*N+1:(j+2)*N)=Char(N-i+1,N*(find(Index(N-i+1,:)==j+1)-1)+1:N*find(Index(N-i+1,:)==j+1));
end
end
%Char中第一行的编码结果就是所需的Huffman 编码输出,通过Index中第一行索引将编
% 码对应到相应概率的信源符号上。
for i=1:N
h(i,1:N)=Char(1,N*(find(Index(1,:)==i)-1)+1:find(Index(1,:)==i)*N);
%根据Index第一行索引将Char中第一行编码值还原为输入概率矩阵中的顺序填入Result
ll(i)=length(find(abs(h(i,:))~=32));
end
l=sum(P.*ll);
H=0;
for i=1:length(P)
H=H-P(i)*log(P(i))/log(2);
end
eff=H/l;%编码效率
disp('信息源的平均信息量:');
disp(H);
disp('霍夫曼编码的平均码长:');
disp(l);
disp('所对应的编码:');
disp(h);
disp('编码效率:'),
disp(eff)
运算样例
p=[0.20,0.19,0.18,0.17,0.15,0.10,0.01];
huffman(p)
信息源的平均信息量:
2.6104
霍夫曼编码的平均码长:
2.7213
所对应的编码:
10
11
000
001
010
0110
0111
编码效率:
0.9596
我们可以看出哈夫曼编码的一大优点是可以通过为高频字符分配较短的编码,为低频字符分配较长的编码,有效地减少数据的平均编码长度,提高编码效率。但是知道注意的是,如果新合成的概率与原序列概率相同,新合成概率应该置于高处,这样可以获得更少的码方差。
4.总结
香农编码和哈夫曼编码都是用于实现数据压缩
相似之处:
- 两者都属于可变字长编码,会根据信源符号出现的概率来分配不同长度的码字,将经常出现的消息编为短码,不常出现的消息编为长码,以提高编码效率。
不同点:
- 编码方法:香农编码是依据信源符号的累计概率分布函数来分配码字;哈夫曼编码则通过构建哈夫曼树来确定码字,完全依据字符出现的概率构造平均长度最短的异字头码字。
- 编码效率:在多数情况下,哈夫曼编码得到的平均码长更短,是最佳码,编码效率优于香农编码。香农编码严格意义上来说不是最佳码,其平均码长通常不是最短的,但当信源符号的概率分布满足特定条件时,香农编码效率可达到最高。
- 实现难度:哈夫曼编码的具体步骤相对复杂,需要构建哈夫曼树;香农编码的步骤则较为直接,但可能需要更多的计算来确定累加概率和转换二进制小数。
- 特点:哈夫曼码具有三个特点,一是保证了概率大的符号对应短码,短码得到充分利用;二是每次缩减信源的最后两个码字总是最后一位码元不同,前面各位码元相同(二元编码情况);三是每次缩减信源的最长两个码字有相同的码长。而香农编码的理论意义较为重要,对其他编码方法有较好的理论指导意义。
- 应用场景:哈夫曼编码在实际通信中应用广泛,如文件传真、语音处理和图像处理等,能使数据压缩和传输达到最小;香农编码则更多地用于理论研究和对其他编码方法的指导。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.youkuaiyun.com/lily_ahu/article/details/131787889