MATLAB实现huffman编码及译码
使用前将建立input.txt放在和该.m文件同一文件夹中运行即可
最后运行结果:
1.文本统计过后的信源空间
2.信源空间对应的柱状图
3.编码结果
4.译码结果
clc;
close all;
clear all;
%数据读取
txt=fopen('input.txt');
shuju=fscanf(txt,'%c');
%去重
selected_shuju=unique(shuju);
selected_shuju=selected_shuju';
%长度
len=length(selected_shuju);
%求出信源符号的个数
for i=1:len
count(i)=length(strfind(shuju,selected_shuju(i)));
end
p=count./sum(count);
n=length(p);
q=p;
%构建概率矩阵
m=zeros(n-1,n);
for i=1:n-1%合并n-1次
[q,e]=sort(q);%E是个行向量 值代表q中该位置的概率在原序列中的位置
m(i,:)=[e(1:n-i+1),zeros(1,i-1)];
%m的特点:第一行n个非零元素,逐行递减,n-1行2个非零元素
q=[q(1)+q(2),q(3:n),1];
end
%构建编码矩阵
for i=1:n-1
c(i,1:n*n)=blanks(n*n); %c矩阵特点 与m对应 每一个n块对应一个概率的符号 第一行有n个 n-1行有2个 其余为空
end
%开始编码 因为哈夫曼编码不唯一 自规定概率小的赋值1 概率大的赋值0
c(n-1,n)='1';
c(n-1,2*n)='0';
for i=2:n-1
%被合并的前两个需要分配0和1
index=find(m(n-i+1,:)==1);%下一行对应位置为1 则为该行较小的两个概率合并以后的总概率
c(n-i,1:n-1)=c(n-i+1,n*(index)-(n-2):n*index);%前缀是对应的合并后概率的编码值 注意:1:n-1的维度和取的前缀的维度要一致
c(n-i,n)='1';
c(n-i,n+1:2*n-1)=c(n-i,1:n-1); %合并为同一个概率 前缀相同
c(n-i,2*n)='0';
%未合并的 从每一行第三个开始编码 无需新分配0 1 直接继承上一个节点的编码
for j=1:i-1
index=find(m(n-i+1,:)==j+1);%从index=2开始到index=i结束 i=3 即n-3行 就是index从2到3
c(n-i,(j+1)*n+1:(j+2)*n)=c(n-i+1,n*(index-1)+1:n*index);
end
end
for i=1:n
index=find(m(1,:)==i);
h(i,1:n)=c(1,n*(index-1)+1:index*n); %将与输入概率对应的编码放入h中
is0=abs(h(i,:));%abs()将字符变为ASCII码 空为32
len(i)=length(find(is0~=32)); %非空符号的个数为码长
end
disp('编码结果');
[selected_shuju,h]
disp('平均码长');
e=sum(p.*len) %计算平均码长
xinxiliang=sum(p.*log2(1./p)); %计算平均信息量
disp('平均信息量');
disp([num2str(xinxiliang),'bit/sym']);
disp('编码效率');
eta=(sum(p.*log2(1./p)))./e %计算编码效率
%将结果写入文件中
txt2=fopen('tongji_result.txt','w+','n','GB2312');
fwrite(txt2,"symbols: ");
fprintf(txt2,'\n');
for i=1:length(selected_shuju)
fwrite(txt2,selected_shuju(i));
fwrite(txt2,': ');
fwrite(txt2,num2str(p(i)));
fprintf(txt2,'\n');
end
fprintf(txt2,'\n');
fwrite(txt2,"Huffman_Result: ");
fprintf(txt2,'\n');
for i=1:length(selected_shuju)
fwrite(txt2,[selected_shuju(i)]);
fwrite(txt2,': ');
for j=1:length(h)
fwrite(txt2,h(i,j));
end
fprintf(txt2,'\n');
end
fwrite(txt2,'averge_lenth: ');
fwrite(txt2,num2str(sum(p.*len)));
fprintf(txt2,'\n');
fwrite(txt2,'averge_bit: ');
fwrite(txt2,[num2str(xinxiliang),'bit/sym']);
fprintf(txt2,'\n');
fwrite(txt2,'eta: ');
fwrite(txt2,num2str(eta));
fclose(txt2);
%文本编码和译码
%文本编码结果
txt333=fopen('bianma_result.txt','w+');
RESULT=[selected_shuju,h];
for i=1:length(shuju)
for j=1:length(selected_shuju)
if shuju(i)==selected_shuju(j)
for o=1:length(h)
if h(j,o)~=' '
fwrite(txt333,h(j,o));
end
end
fwrite(txt333,' ');
end
end
end
fclose(txt333);
%文本译码
txt444=fopen('yima_result.txt','w+');
txt333=fopen('bianma_result.txt','r');
bianma_code=fscanf(txt333,'%c');
s='';
plll=0
%开始译码:
for i=1:length(bianma_code)
if bianma_code(i)==' '
flag=1;
for j=1:length(h)
flag=1;
for m=1:length(h)
if(h(j,m)==' ')
plll=plll+1;
continue;
end
if(length(h)-plll~=length(s))
flag=0;
break;
end
for o=m:length(h)%比较每个字符串是否对应相等
if h(j,o)~=s(o-plll)
flag=0;
end
end
end
plll=0;
if(flag==1)
fwrite(txt444,selected_shuju(j));
end
end
s='';
end
if(bianma_code(i)~=' ')
s=[s,bianma_code(i)];
end
end
fclose(txt444);
fclose(txt333);
%数据可视化
x=1:length(selected_shuju);
bar(x,p)
set(gca,'XTick',1:length(selected_shuju))
%下面是x轴的刻度值
set(gca,'XTickLabel',selected_shuju(1:1:end))
title('信源符号——概率图');
xlabel('信源符号');
ylabel('概率');
这篇文章,是又一个故事的结束...
lazy's story is continuing.