数据压缩算法实现

来源:互联网 发布:c语言定义二维数组 编辑:程序博客网 时间:2024/05/22 10:47
  • 实验目的

    利用香农-费诺编码、霍夫曼编码、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    endend     c = fliplr(c)  c(index)=c

2、霍夫曼编码

function c=huffman(p)n=size(p,2)if n==1    c=cell(1,1)    c{1}=''    returnend[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+p2c=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....');endendfunction [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='';           endend codelength=fix(log2(k-1))+1;for i=1:(k-1)    dictionary(i).code=dec2bin((i-1),codelength);   endendfunction decode=LZdecode(dictionary)ld=length(dictionary);decode='';for i=1:ld    decode=[decode dictionary(i).sym];endendfunction encode=LZencode(dictionary)ld=length(dictionary);encode='';for i=1:ld    encode=[encode dictionary(i).code];endendfunction [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;     endendprob=prob./l;entropy=-prob.*log2(prob);entropy=sum(entropy(:));end

4、算术编码

function arithmeticS = 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);endstrl = 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;>> LZmainEntropy =5.8172Code length =8Average length =4.6126Encoded Sequence : Look encode.txt.Decoded Sequence : Look decode.txt.