LZW 压缩算法的C++实现

来源:互联网 发布:js的闭包是什么 编辑:程序博客网 时间:2024/05/24 04:34

最近老师布置了一个上机作业,实现LZW 。刚好最近对STL掌握的还不错,写起来就比较容易,又一次体会到了C++模版库的强大,要不然代码量就*2了。

不知道老师的要求是对ASCCI码所有的字符进行压缩编码还是只对输入字符串的进行编码,不过算法都一样,我是对根据输入的串进行构造字典表,如果直接对256个字符进行构造,那更简单了。

结下来就先说一说LZW的算法,它属于无损压缩的一种,尤其对输入重复的串压缩的越彻底。

基础思想:

利用字符的重用性,每当输出一个编码,就讲一个新的string 存放到字典表中

算法流程:

1.初始化,将所有的单字符放入字典表中(这里的字符是指输入字符串中不重复的字符)

2.读入一个输入给前缀串,赋值给W

3.读入一个输入字符,赋值给K

判断:

  if 没有这样的K(指输入的字符串结束了),就输出最后一个W代表的码字,break;

if WK(指将WK两个字符串合并成一个)存在于字典表

{W=WK;repeat3;}

if WK不再字典表

{输出W代表的码字,WK加进字典表;W=K;repeat3;}

具体可以看看下面的示例:

输入串ABABB

构造初始字典表并同时进行编号(即流程中所说的码字):

A1B2

接下来第一个流程

W=A

K=B 

判断WK=AB不在字典表中,输出W代表的码字A--1,WK=AB加入字典表,W=K=B,repeat3

A1B2AB3

第二个流程:

W=B

K=A 

判断WK=BA不在字典表中,输出W代表的码字B--2,WK=BA加入字典表,W=K=A,repeat3

A1B2AB3BA4

第三个流程:

W=A

K=B

判断WK=AB在字典表中,W=WK=AB,repeat3

第四个流程:

W=AB

K=B

判断WK=ABB不再字典表中,输出W代表的码字AB--3,WK=ABB加入字典表,W=K=B,repeat3

A1B2AB3BA4ABB5第五个流程:

W=B

K='\0' 输入穷尽,输出W代表的码字B--2


综上最后的压缩后的编码为 1232. 

我这个可能是按照流程走的一遍比较麻烦,不过如果大家有耐心的话走一遍就全部明白了


解码就是压缩的逆过程,根据输入的编码流从字典表中找字符,简单。

实现代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <map>#include <algorithm>#include <vector>using namespace std;long len=0;//原字符串的长度long loc=0;//去重之后字符串的长度map<string,long> dictionary;vector <long> result;#define MAX 100;void LZWcode(string a,string s){    //memset(&result,0,sizeof(int));    string W,K;    for(long i=0;i<loc;i++)    {        string s1;        s1=s[i];//将单个字符转换为字符串        dictionary[s1]=i+1;    }    W=a[0];    loc+=1;    for(int i=0;i<len-1;i++)    {        K=a[i+1];        string firstT=W;        string secontT=W;        if(dictionary.count(firstT.append(K))!=0)//map的函数count(n),返回的是map容器中出现n的次数            W=firstT;        else        {            result.push_back(dictionary[W]);            dictionary[secontT.append(K)]=loc++;            W=K;        }    }    if(!W.empty())        result.push_back(dictionary[W]);    for(int i=0;i<result.size();i++)        cout<<result[i];}void LZWdecode(int *s,int n){    string nS;    for(int i=0;i<n;i++)        for(map<string,long>::iterator it=dictionary.begin(); it!=dictionary.end();it++)            if(it->second==s[i])            {                cout<<it->first<<" ";            }    for(map<string,long>::iterator it=dictionary.begin(); it!=dictionary.end();it++)//输出压缩编码的字典表        cout<<it->first<<" "<<it->second<<endl;}int main(int argc, char const *argv[]){    cout<<"本程序的解码是根据输入的编码字符进行的解码,并不是全256 的字符"<<endl;    cout<<"选择序号:"<<endl;    cout<<"1.压缩编码   2.解码"<<endl;    int n;    while(scanf("%d",&n)!=EOF)    {        switch(n)        {            case 1:            {                char s[100],a[100];                cout<<"输入一串字符:"<<endl;                cin>>s;                len=strlen(s);                for(int i=0;i<len;i++)                    a[i]=s[i];                sort(s,s+len);//排序                loc=unique(s,s+len)-s;//去重                LZWcode(a,s);                break;            }            case 2:            {                cout<<"输入解码数组的长度:"<<endl;                int changdu;                cin>>changdu;                cout<<"输入解码数串(每个数串以空格隔开):"<<endl;                int s[changdu];                for(int i=0;i<changdu;i++)                    cin>>s[i];                LZWdecode(s, changdu);                break;            }            default:                cout<<"你的输入不正确,请从重新开始"<<endl;        }        if(n==2)        {            auto iter=result.begin();   // 每次正确输入结束后对结果进行清零            while(iter!=result.end())                result.erase(iter++);        }    }    return 0;}


0 0