Matlab实现Huffman编码

一、实验目的:

(1)了解信源变长码的编码方法;
(2)掌握哈夫曼编码方法;
(3)掌握MATLAB的编程。                                                         

二、实验仪器:

Matlab2015a

三、实验原理:                                                           

二元霍夫曼编码步骤如下:

1.将信源符号按概率从大到小的顺序排列,令

2.给两个概率最小的信源符号Sn-1和Sn ,各分配一个码元“0”和“1”,并将这两个信源符号合并成一个新符号,并用这两个最小的概率之和作为新符号的概率,结果得到一个只包含(n-1)个信源符号的新信源。称为信源的第一次缩减信源,用S1表示。

3.将缩减信源的符号仍按概率从大到小顺序排列,重复步骤2,得到只含(n-2)个符号的缩减信源S2

4.重复上述步骤,直至缩减信源只剩两个符号为止,此时所剩两个符号的概率之和必为1。然后从最后一级缩减信源开始,依编码路径向前返回,就得到各信源符号所对应的码字。

四、实验步骤:                                                                                                               

1.先利用Matlab编写函数;

2.再根据函数将实验要求生成实验结果;

3.根据实验内容填写实验报告;                                                          

五、实验内容及数据整理:  

用Matlab软件编程实现Huffman编码

                                                                                                       

 六、实验结果及讨论                                                          

 第一种方法:

clear;clc;close all

p=input('请输入数据( 例如[0.3,0.2,0.1] ):\n');%提示输入界面

n=length(p);           %N取输入行向量P的长度,即需要编码元素个数

for i=1:n

  if p(i)<0            %判断输入P矩阵各元素是否全为大于零的有效概率值;

  fprintf('\n错误:概率值不能小于0!\n');

  p=input('请重新输入数据:');

  end

end



if abs(sum(p)-1)>0.00001     %IF语句判断输入矩阵的概率和是否为合理值1

    fprintf('\n霍夫曼码中概率总和不能大于1!\n');

    p=input('请重新输入数据:');

end

Pr=sort(p,'descend');%将输入的信源符号降序排序

q=Pr;

a=zeros(n-1,n); %生成一个n-1行 n列的数组,用来记录每行最小两概率叠加后概率排列次序

for i=1:n-1     %第一个FOR循环确定概率大小值的排列,得到a数组

    [q,l]=sort(q);

    a(i,:)=[l(1:n-i+1),zeros(1,i-1)];

    q=[q(1)+q(2),q(3:n),1];

end

for i=1:n-1    %第二个FOR循环生成一个N-1行、N2(N×N)列数组C,每行可看作N个段,每段长为N,记录一个码字(每个码字的长度不会超过N)

    c(i,1:n*n)=blanks(n*n);

end

c(n-1,n)='0';  %给C矩阵的N-1行的第一个段赋值0

c(n-1,2*n)='1';%第二个段赋值1。(这两个码字对应编码中最后相加为一的两个概率)



for i=2:n-1   %主要的程序,循环N-2次

c(n-i,1:n-1)=c(n-i+1,n*(find(a(n-i+1,:)==1))-(n-2):n*(find(a(n-i+1,:)==1)));

c(n-i,n)='0';  %根据之前的规则,在分支的第一个元素最后补0

c(n-i,n+1:2*n-1)=c(n-i,1:n-1);

c(n-i,2*n)='1'; %根据之前的规则,在分支的第一个元素最后补1

           %决定矩阵C从倒数第二行开始到第一行的每段的码字值。

           %每一行值都从下一行值得到,找到在下一行码字中相加本行最小两个概率得到的概率的对应码字,

           %本行两个最小概率对应码字分别为此码字最后加“0”,加“1”

for j=1:i-1

    c(n-i,(j+1)*n+1:(j+2)*n)=c(n-i+1,n*(find(a(n-i+1,:)==j+1)-1)+1:n*find(a(n-i+1,:)==j+1));

end

end     %完成huffman码字的分配

  %FOR循环找到其余的本行在下一行对应的码字,该码字保持不变。循环结  

 %束后,C矩阵第一行的N段对应输入N个概率所对应符号的码字。该码字     %按码字长短排列

for i=1:n

    h(i,1:n)=c(1,n*(find(a(1,:)==i)-1)+1:find(a(1,:)==i)*n);

    ll(i)=length(find(abs(h(i,:))~=32));   %计算每一个huffman编码的长度

end      %第五个FOR循环根据M矩阵第一行记录的概率排序位置分配给每个概率对应符号的码字。

average_len=sum(Pr.*ll); %计算平均码长

HX=sum(Pr.*(-log2(Pr))); %计算信源熵

yita=HX/average_len;     %计算编码效率

r=1-yita;                %计算冗余度

disp(['信号符号S: ',num2str(1:n)]);

fprintf('\n信源符号出现的概率为:\n');

disp(Pr);

fprintf('\nHuffman编码结果为:\n');

disp(h);

fprintf('\n编码的平均码长为:');

disp(average_len);

fprintf('\n信源熵为:');

disp(HX);

fprintf('\n编码效率为:');

disp(yita);

fprintf('\n冗余度为:');

disp(r);

第二种方法:

function [ u, c, e, f] = Untitled2( A )

%HUFF_CODEC 哈夫曼编码的MATLAB实现



%A   输入的原始频率分布,为行向量eg A=[1,2,3,4,5]

    A=sort(A,'descend');%按降序排列

    T=A;u=A;

    A=A/sum(A);

    [~,n]=size(A);



    %生成待编码矩阵,每列最后一个元素为特殊元素的位置

    B=zeros(n,n);

    for i=1:n

        B(i,1)=T(i);%生成编码表的第一列

    end

    r=B(i,1)+B(i-1,1);%最后两个元素相加

    T(n-1)=r;T(n)=0;

    T=sort(T,'descend');

    t=n-1;

    for j=2:n%生成编码表的其他各列

        for i=1:t

            B(i,j)=T(i);

        end

        if t>1

            K=find(T==r);

            B(n,j)=K(end);%从第二列开始,每列的最后一个元素记录特征元素在该列的位置

            r=(B(t-1,j)+B(t,j));%最后两个元素相加

            T(t-1)=r;

            T(t)=0;

            T=sort(T,'descend');

            t=t-1;

        else

            B(n,j)=1;

        end

    end



    %生成Huffman码字矩阵和排序后元素的码表向量

    m=3;s1=sym('[2,1]');s2=s1;%码表,用1表示0,2表示1,因为0会因为被省略导致无法记录

    %这里意思是从倒数第三列开始建表,因为最后一列和倒数第二列的情况我们可以直接推出。

    for i=n-2:-1:1

        p=B(n,i+1);%p是每列保存的特殊元素的位置,特殊元素指的是由上一列最后两个数新合成的数

        if p==1

            s2(1:m-2)=s1(2:m-1);

        elseif p==m

            s2(1:m-2)=s1(1:m-2);

        elseif p==2

            s2(1)=s1(1);

            s2(2:m-2)=s1(3:m-1);

        else

            s2(1:p-1)=s1(1:p-1);

            s2(p+1:m-2)=s1(p+1:m-2);

        end

        s2(m-1)=[char(s1(p)),'2'];

        s2(m)=[char(s1(p)),'1'];

        m=m+1;

        s1=s2;

    end

    L=zeros(1,n);

    for i=1:n

        [~,r]=size(char(s2(i)));

        L(i)=r;

    end



    %将码表转换成0和1输出

    arr=zeros(1,n);

    arr(1:n)=s2(1:n);

    str=[];

    for i=1:n

        s=num2str(arr(i));

        s=strrep(s,'1','0');

        s=strrep(s,'2','1');

        if i==1

            str=s;

        else

            str=[str,' ',s];

        end

    end

    str=regexp(str,' ','split');



    %计算返回值

    c=str;

    e=sum(L.*A);%平均码长

    H1=log2(A);

    H=-A*(H1');%熵

    f=H/e;%编码效率

end

 

  • 54
    点赞
  • 322
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值