数据压缩算法实现

  • 实验目的

    利用香农-费诺编码、霍夫曼编码、LZ编码、算术编码实现数据压缩

  • 实验原理

    1、香农-费诺编码
      首先,将信源符号以概率递减的次序排列进来,将排列好的信源符号划分为两大组,使两组的概率和近于相同,并各赋予一个二元码符号“0”和“1”。然后将每一大组的信源符号再分成两组,使同一组的两个小组的概率和近于相同,并又分别赋予一个二元码符号。依次下去,直至每一个小组只剩下一个信源符号为止。这样,信源符号所对应的码符号序列则为编得的码字。译码原理,按照编码的二叉树从树根开始,按译码序列进行逐个的向其叶子结点走,直到找到相应的信源符号为止。之后再把指示标记回调到树根,按照同样的方式进行下一序列的译码到序列结束。如果整个译码序列能够完整的译出则返回成功,否则则返回译码失败。

    2、霍夫曼编码
      霍夫曼编码属于码词长度可变的编码类,是霍夫曼在1952年提出的一种编码方法,即从下到上的编码方法。同其他码词长度可变的编码一样,可区别的不同码词的生成是基于不同符号出现的不同概率。生成霍夫曼编码算法基于一种称为“编码树”(coding tree)的技术。算法步骤如下:
      (1)初始化,根据符号概率的大小按由大到小顺序对符号进行排序;
      (2)把概率最小的两个符号组成一个新符号(节点),即新符号的概率等 于这两个符号概率之和;
      (3)重复第2步,直到形成一个符号为止(树),其概率最后等于1;
      (4)从编码树的根开始回溯到原始的符号,并将每一下分枝赋值为1,上 分枝赋值为0。

    3、LZ编码
      在LZ算法中,离散信源的输出序列分解成长度可变的分组,码段(phrases)。每当信源输出字符组在最后位置加上一个字符后,与前面的一有已有码段都不相同时,把它作为一种新的码段引入。将这些码段列入一个位置词典,用来记载有码段的位置。在对一个新的码段编码时只要指出字典中现有码段的位置,把新的字符附在后面即可。

    4、算术编码
      算术编码的编码对象是一则消息或一个字符序列,其编码思路是将消息或字符序列表示成0和1之间的一个间隔上的一个浮点小数。 在进行算术编码之前,需要对字符序列中每个字符的出现概率进行统计,根据各字符出现概率的大小,将每个字符映射到[0 ,1]区间上的某个子区间中。然后,在利用递归算法,将整个字符序列映射到[0,1]区间上的某个间隔中。在进行编码时,只需从该间隔中任选一个小数,将其转化为二进制数。 符号序列越长,编码表示他的间隔就越小,表示这个间隔所需的二进制位数就越多,编码输出的码字就越长。
      在进行编码过程中,随着信息的不断出现,子区间按下列规律减小:
      a.新子区间左端=前子区间左端+当前子区间左端×前子区间长度
      b.新子区间长度=前子区间长度×当前子区间长度

  • 实验内容

    1、对于给定的信源的概率分布,用香农-费诺编码实现压缩
    2、对于给定的信源的概率分布,用霍夫曼编码实现压缩
    3、对于给定的信源的概率分布,用LZ编码实现压缩
    4、对于给定的信源的概率分布,用算术编码实现压缩

  • 实验过程

    1、香农-费诺编码

function c=shannon(p)
[p,index]=sort(p)   
p=fliplr(p)    
n=length(p)   
pa=0    
for i=2:n       
    pa(i)= pa(i-1)+p(i-1)
end   
k=ceil(-log2(p))    
c=cell(1,n)    
for i=1:n        
    c{i}=''
    tmp=pa(i)       
    for j=1:k(i)    
        tmp=tmp*2           
        if tmp>=1   
            tmp=tmp-1
            c{i}(j)='1'
        else               
            c{i}(j)='0'
        end
    end
end     
c = fliplr(c)  
c(index)=c

2、霍夫曼编码

function c=huffman(p)
n=size(p,2)
if n==1
    c=cell(1,1)
    c{1}=''
    return
end
[p1,i1]=min(p)
index=[(1:i1-1),(i1+1:n)]
p=p(index)
n=n-1
[p2,i2]=min(p)
index2=[(1:i2-1),(i2+1:n)]
p=p(index2);
i2=index(i2)
index=index(index2)
p(n)=p1+p2
c=huffman(p)
c{n+1}=strcat(c{n},'1')
c{n}=strcat(c{n},'0')
index=[index,i1,i2]
c(index)=c

3、LZ编码

function LZmain()
clc;
fid=fopen('source.txt','r');
seq=fread(fid);
fclose(fid);
seq=reshape(seq,1,length(seq));
if ~isempty(seq)
    [entropy]=Entropy(seq); 
    [dictionary codelength]=LZcode(seq);
    avglength=((codelength*length(dictionary))/length(seq));
    disp(strcat('Entropy = ',num2str(entropy)));
    disp(strcat('Code length = ',num2str(codelength))); 
    disp(strcat('Average length = ',num2str(avglength)));    
    display('Encoded Sequence : Look encode.txt.');
    enseq=LZencode(dictionary);
    fiden=fopen('encode.txt','w');
    en=fwrite(fiden,enseq);
    fclose(fiden);
    display('Decoded Sequence : Look decode.txt.');
    deseq=LZdecode(dictionary);
    fidde=fopen('decode.txt','w');
    de=fwrite(fidde,deseq);
    fclose(fiden);        
else
    display('Empty Sequence....');
end
end

function [dictionary codelength]=LZcode(seq)
l=length(seq);
dictionary(1).sym=seq(1);
k=2;
index=0;
str='';
for i=2:l
    str=[str seq(i)];    
    for j=1:(k-1)
        index=0;
        if strcmp(dictionary(j).sym,str)
            index=1;
            break;
        end
    end    
    if (index==0)
        dictionary(k).sym=str;
        k=k+1;
        str='';       
    end
end 
codelength=fix(log2(k-1))+1;
for i=1:(k-1)
    dictionary(i).code=dec2bin((i-1),codelength);   
end
end

function decode=LZdecode(dictionary)
ld=length(dictionary);
decode='';
for i=1:ld
    decode=[decode dictionary(i).sym];
end
end

function encode=LZencode(dictionary)
ld=length(dictionary);
encode='';
for i=1:ld
    encode=[encode dictionary(i).code];
end
end

function [entropy]=Entropy(seq)
alpha(1)=seq(1);
prob(1)=1;
l=length(seq);
k=2;
for i=2:l
    idx=find(alpha==seq(i));
    if isempty(idx)
        alpha(k)=seq(i);
        prob(k)=1;
        k=k+1;
    else
        prob(idx)=prob(idx)+1; 
    end
end
prob=prob./l;
entropy=-prob.*log2(prob);
entropy=sum(entropy(:));
end

4、算术编码

function arithmetic
S = input('请输入信源符号='); 
P = input('请输入信源概率向量P=');
str = input('输入编码的字符串=');
l = 0;
r = 1;
d = 1;
n = length(str);
n_S = length(P);
%**********处理第一个字符***********%
for i=1:n
    flag = 0;
    for k = 1:n_S 
        if str(i)==S(k) 
            m=k;
            flag =1;
            break;
        end
    end
    if flag ==0 
        error('非信源字符');         
    end  
    %*********当前单个字符的左、右端以及长度处理**************%
    pl = 0;
    pr = 0; 
    for j = 1:m-1 
        pl = pl + P(j);    %左端
    end 
    pr = pl+P(m);     %右端    
    pd = pr-pl;         %子区间长度  
    %*********新子区间的左、右边界以及长度处理**************%
    if i == 1            %首字符
        l = pl;
        r = pr;
        d = pd; 
    else              %算术编码规则
        l = l+d*pl;
        d = d*pd;
        r = l+d;
    end 
    strl = strcat('第',int2str(i),'个符号的间隔左右边界:');
    disp(strl);
    format long;
    disp(l);disp(r);
end
strl = strcat('符号的间隔左右边界:');
disp(strl);
format long;
disp(l);disp(r);
end 
  • 实验结果
>> clear; clc;
>> P=[0.3 0.25 0.16 0.14 0.1 0.05];
>> c1=shannon(P);
c1 =     '00'    '01'    '100'    '101'    '1101'    '11110'

>> c2=huffman(P);
c2=     '11'    '01'    '00'    '100'    '1011'    '1010'

>> clear; clc;
>> arithmetic
请输入信源符号='abcdef'
请输入信源概率向量P=[0.3 0.25 0.16 0.14 0.1 0.05]
输入编码的字符串='adbecf'1个符号的间隔左右边界:
   0
   0.3000000000000002个符号的间隔左右边界:
   0.213000000000000
   0.2550000000000003个符号的间隔左右边界:
   0.225600000000000
   0.2361000000000004个符号的间隔左右边界:
   0.234525000000000
   0.2355750000000005个符号的间隔左右边界:
   0.235102500000000
   0.2352705000000006个符号的间隔左右边界:
   0.235262100000000
   0.235270500000000
符号的间隔左右边界:
   0.235262100000000
   0.235270500000000

>> clear; clc;
>> LZmain
Entropy =5.8172
Code length =8
Average length =4.6126
Encoded Sequence : Look encode.txt.
Decoded Sequence : Look decode.txt.
  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值