编码器设计

C++工程设计:字符编码器,实现对char型文本数据的编码,解码,压缩等操作。

一,结构设计:(箭头表示继承关系)

             

二,工具类设计:

CFileName,CHufmanheap,(Allocate)(为泛型空间配置器),(CBiset)(二进制,编码信号转换类),(CStack),CodeTree       HufmanTree,(客服端类)等。

三,框架说明:

CCode类  :

架构中的公共基类,内含字符编码表,可完成统计要编码字符数,销毁编码表等基本操作,不提供外部接口,只提供子类接口和子类端口。

CEncode类:

继承自CCode,内包含字符统计数组,可完成编码前的对文本的各字符出现的次数,文本的长度等基本操作,提供三个输入,一个输出和更改文件路径的外部接口。

CTranslate类:

            继承自CCode,完成读入编码表、按编码表对文本进行编码等操作。

CDecode类:

           继承自CCode,完成读入编码表和已编码的文本,确认该文本的编码方式等操作。

(CMorencode)类:

           继承自CEncode,完成文本的Mor编码,生成对应的编码表。

CHufmanencdoe类:

            继承自CEncode,完成文本的hufman编码,生成对应的编码表。

(CMordecode)和CHufmandecode类:

           继承自CDecode,完成对应的解码过程。

四,工具类说明:

CFilename类:

            文件名类,提供对文件名操作方法,分离文件名和文件路径,分离文件名与文件扩展名等操作。

CHufmanheap类:

            关于HufmanNode中数据频数的小顶堆,用于生成哈弗曼编码树,为CHufmanencode的内建类,禁止外界调用。

(CBiset)类:

            专门用于处理‘0’、‘1’二进制字符,如转换成bit的数据,方便文件的压缩处理,或者转化成输出信号,二进制编码处理类。

CodeTree,HufmanTree:

            为struct,HufmanTree继承自CodeTree,HufmanTree用于生成Hufman编码必须的过程,CodeTree用于解码。

(客服端类):

           封装了所有可能客服端操作,定义提供对应的消息信号。

五,主要数据结构:

堆栈,小顶堆,二叉树,单链表等

六,主要过程:

(1),编码过程(Hufmanencode,共三个外部接口):

编码过程,先调用CEncode类里的inputchar(有三个版本,一个是读入一个字符,一个是读入一段话,一个是按CEncode里的Filename所对应的文本读入文件),调用inputchar函数读入完成后,会自动调用count函数,将文本信息统计入_Numofchar表中,还有一个Filelength来统计文本长度里。第一步完成后,调用CHufmanencode类里的encode函数进行编码,encode函数调用CreateHufmanTree函数生成HufmanTree,再调用TreetoList函数生成对应字符编码到CCode::CodeList里面去,完成编码。最后由CEncode::Outputchar函数输出编码到.cde文件里。编码过程只提供这三个外部接口。

(2),对文本的translate:由CTranslate完成,分为读入编码,读入字符输出对应的编码,生成.huf文件。

(3),解码过程(Hufmandecode,提供三个外部接口):

             解码过程,先调用CDecode::inputchar(),按其Filename读入.cde文

             件,将其中信息储存到CodeList里,然后调用CHufamandecode::CreatecodeTree生成CodeTree,然后用Outputchar函数,对人Filename的.huf文件,按读入字符遍历CodeTree,输出字符。

七,关键步骤:

(1),生成哈弗曼树的过程:

HufmanTreeheap

 
           

 

 

                                                   

Q = (HufmanTree)malloc(sizeof(HufmanNode))

Q->p = P1->p + P2->p;

 

 

 

 

 


代码片段:

CreateNode();

while(true)

{

    P1 = heap.pop();

    if(heap.isempty()) break;

    P2 = heap.pop();

    Q = (HufmanTree)malloc(sizeof(HufmanNode));

    Q->pchar =(char)NULCODE;

    Q->code = NULL;

    Q->lchild = P1;

    Q->rchild = P2;

    Q->p = P1->p + P2->p;

    heap.push(h);

}

head= P1;

文字说明:

    生成哈弗曼树的过程是这样的,首先将读入的字符和字符频数生成hufman结点,并一一压入到小顶堆heap中。然后进入无限循环,利用小顶堆特性不论用户按什么顺序输入,pop输出的永远是堆中最小的项(比较由频数进行),进行两次pop操作,压出p1,p2,建立一个新节点Q,让这个结点代表的字符为NULCODE(内定义的宏),它的频数为p1->p+p2->p,lchild和rchild分别指向p1和p2,然后将Q压入小顶堆,重复上面的操作,当heap为空时,终止循环,最后出堆的结点即为HufmanTree的头结点。

(2),解码过程

示例:

首先根据读入编码表生成CodeTree,然后一个一个字符地读入.huf文件,读入过程伴随一个CodeNode指针lp运动,初始始为lp= head,如果读入为‘0’则       lp=lp->lchild,为‘1’则lp=lp->rchild,这时判断lp->pchar是否为NULCODE,如果不为,则输出lp->pchar且lp=head,用这个完成编码。如:图中树,读入”000”则输出’a’。

代码片段:

while((c=fgetc(fp1))!=EOF)

{

    p = Next(p,c);

    if((p->pchar)!=(char)NULCODE)

    {

       fputc(p->pchar,fp2);

       p = head;

    }

}

八,重要底层实现代码:

(1),内定义宏:

#define      MAX_CODE  128    //由于是char型字符,故最多为128个。

#define      NULCODE   0xff   //表示无字符,用于填充Hufman树和Code树。

#define      LEFT      true   //把向左定义为bool型的true。

#define      RIGHT     false  //把向右定义为bool型的false。

(2),heap堆实现机制:用数组表示二叉搜索树的结构实现

比较大小方式在HufmanNode里定义:

       int operator >(HufmanNode& a)

        {

           returnp>a.p;

        }

内定义数据:  

HufmanTreeNodeList[MAX_CODE];  //Hufman堆数组实现

          int top;                        //堆顶指针

Push操作:

       void CHufmanheap::push(HufmanTree a)

{

           top++;

           push_heap(a,top);   //转调用内部函数push_heap函数完成

}

Pop操作:

       HufmanTree CHufmanheap::pop()

{

           HufmanTreeresult = NodeList[1];

           adjust_heap();

           return result;  //返回堆定元素,并调用内部函数调整堆。

}

内部函数push_heap:

       void CHufmanheap::push_heap(HufmanTree a,int st)

{

           NodeList[st]= a;  //先将元素插入到st的位置

           HufmanTreevalue = a; //用于过程中的判断

           intholeIndex = st;  //当前节点的位置

           intparent = holeIndex / 2;  //找其父节点

//判断父节点是否满足小顶堆条件,不满足则交换其和当前节点

//位置,直到满足位置

           while(holeIndex> 1 && *NodeList[parent] > *value)

           {

              NodeList[holeIndex]= NodeList[parent];

              holeIndex= parent;

              parent= holeIndex / 2;

           }

           NodeList[holeIndex]= a;

}

内部函数adjust_heap:

voidCHufmanheap::adjust_heap()

{

        intholeIndex = 1;                //当前位置,从头节点开始调整

        intsecondChild = 2 * holeIndex + 1;   //找到右子节点

        HufmanTreevalue = NodeList[top];     

//递归填空直到满足小顶堆的条件

        while(secondChild<top)

        {

           if(*NodeList[secondChild]> *NodeList[secondChild -1])

           {

               secondChild--;

           }

           NodeList[holeIndex]= NodeList[secondChild];

           holeIndex= secondChild;

           secondChild= 2 * holeIndex + 1;

        }

        if(secondChild== top)

        {

           NodeList[holeIndex]= NodeList[secondChild - 1];

           holeIndex= secondChild - 1;

        }

           push_heap(value,holeIndex);//将末尾的值重新压入到合适的位置

        NodeList[top]= NULL;

        top--;

}

(3),CDecode读入编码后生成CodeTree的过程:

CreateTree函数:

voidCHufmanDecode::CreateTree()

{

        inti;

        for(i=0;i<MAX_CODE;i++)

        {

           if(CodeList[i])

           {

               CreateNode((char)i,CodeList[i]);

           }

        }

}

CreateNode函数:

voidCHufmanDecode::CreateNode(char a, char *p)

{

        char*q = p;

        CodeTreex,y;

        x =head;

        while(*(q+1))

        {

            if(*q == '0')

            {

               if(x->lchild)

               {

                  x = x->lchild;

               }

               else

               {

                   y = (CodeTree) malloc(sizeof(CodeNode));

                   y ->lchild =NULL;

                   y ->rchild =NULL;

                   y ->pchar =(char)NULCODE;

                   x ->lchild = y;

                   x = x->lchild;

               }

           }

           elseif(*q == '1')

           {

               if(x->rchild)

               {

                   x = x->rchild;

               }

               else

               {

                   y = (CodeTree) malloc(sizeof(CodeNode));

                   y ->lchild =NULL;

                   y ->rchild =NULL;

                   y ->pchar =(char)NULCODE;

                   x ->rchild = y;

                   x = x->rchild;

               }

           }

           q++;

        }

        y =(CodeTree) malloc(sizeof(CodeNode));

        y->lchild =NULL;

        y->rchild =NULL;

        y->pchar = a;

        if(*q=='0')

        {

            x ->lchild = y;

        }

        elseif(*q == '1')

        {

            x ->rchild = y;

        }

}

(4),工具类CFilename:

调整文件扩展名函数:

void CFilename::AdjFilename()

{

        char*p = Filename;

        while(*p)

        {

           if(*p=='.')

               break;

           p++;

        }

        if(*p)

        {

           *p= '\0';

        }

}

注:文中带括号的内容均为第一次完成后的改进,因其在实验要求之外故不作说明,其余类内部细节见源码附件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值