使用递归算法编写的费诺编码

内容与设计思想

按照教材方式建立数据成员变量.设有离散无记忆信源X,P(X).二进制费诺编码为:1.将信源符号按概率从大到小的顺序排列2.将信源分成两组――按两组概率之差为最小分.3.上面一组编码为0,下面一组编码为1,一直分到一组只有一个信源为止.4.将一个信源分组得到的01全部连接起来,组成该信源的码字,信源即得到自己的费诺编码.

程序共分为编码,排序,解码三大部分.
首先建立信源的数据存储类
class DATA
,设有公共成员
6
个:
char Xi;//
信源符号,
float PXi;//
信源概率,
char key[11];//
码字,
DATA *next,*qian,*r;//
地址.信源输入采用链表,这样可以输入任意个信源.
1
排序.排序函数
DATA* sort(DATA* pp)
采用递归方式,当递归至最后项为
pp->next==NULL
时结束.函数对输入的
DATA*
型指针进行筛选操作,每次函数运行都从
DATA*
型链表中抽一个最小的出来,当递归运行到最后一个
DATA*
型数据时,所剩就为最大的数据了,这时开始重组这些数据,依次进行
p->qian,p->next
的链表头尾地址存入,构造出一个从大到小排列的链表列.返回一个指向新链表头的
DATA*
型指针,函数运行完毕.
2
编码.编码函数
void a(DATA* pp)
采用递归方式,当递归至最后项为
pp->next==NULL
时结束.这里设了
4
个变量:
float y=1;

k++;//
递归自增值,用于字符数组定位,
DATA *head1=pp,*head2;

int o=1;
.用来作函数迭代的内部变量.函数处理方式是对传入函数的链表进行分组,用
while
循环计算分成上下两组的概率之差,按两组概率之差为最小分组.分好组后,对上面的组赋"
0
"值,对下面的组赋"
1
"值,并记录下这两个组的头地址
head1

head2
,分别传给
a
函数,
a(head1); a(head2);
也就编码函数本身,进行递归运算.函数递归运算完毕将使每个信源得到自己的编码,但
next
指针被破坏了,为了使链表能继续使用,所以在
DATA
类中设了
r
(右)成员.

3解码.解码函数void b(DATA* p,char *jie)采用递归方式,当递归至最后项为‘/0’时结束,即jie[temp]==’/0′.每次函数运行时都定义了2个变量:DATA *temp2=new DATA;DATA *temphead=temp2;//记录头地址.并temp++temp为静态变量);记录函数运行的次数.函数每运行一次,对待解码的字符数组的字符位置就前进一位,便于递归时对字符数据的操作.当函数第一次运行,待解码的第一个字符会有与之相同的码字信源符号,记录下所有与之相同的码字信源符号的地址,组成一个新的链表,赋给解码函数void b(DATA* p,char *jie)本身,递归调用.如此查找,记录,递归下去,最终将得到一个地址,此时停止对比,这个地址的码字值即为待解码的信源符号,输出这个信源符号――if(temp3==1) {cout<<temp2-> qian->Xi; lzy=temp+1;b(head,jie); },一个符号解出.再解码剩下的数据else b(temphead,jie);,直到待解码数据对比完毕.这时只要待解码数据没有错误输入,也解码完毕,函数结束.

 

#include “iostream.h”
#include “math.h”
//
class DATA//数据类,采用双向表
{
public://初始化PXi=1是为了在排序迭代时方便
DATA(){next=NULL;qian=NULL;r=NULL;PXi=1;key[0]=’/0′;key[1]=’/0′;key[2]=’/0′;key[3]=’/0′;key[4]=’/0′;key[5]=’/0′;key[6]=’/0′;key[7]=’/0′;key[8]=’/0′;key[9]=’/0′;key[10]=’/0′;}
char Xi;//信源符号
float PXi;//信源概率
char key[11];//码字
DATA *next,*qian,*r;//地址
};
DATA *head=new DATA,*p=head;//mainini
int k=(-1);//编码函数用
void a(DATA* pp);//编码函数声明
DATA* sort(DATA* pp);//排序函数声明
DATA *HEAD=new DATA,*tt=HEAD,*T;//排序函数用
void b(DATA* p,char *jie);//解码函数声明
int temp=-1,lzy;//解码函数用.lzy用来使p->key[]中的数组位置回到第0位
//
void main()
{//输入数据
float l;
char L;
 while(1)
 {cout<<“输入信源符号:以*结束输入”<<endl;//输入
 cin>>L;
 if(L==’*’) break;
 cout<<“输入信源概率:”<<endl;
 cin>>l;
 p->Xi=L;
 p->PXi=l;
 p->next=new DATA;
 p->next->qian=p;//对新开类赋值
 p->r=p->next;
 p=p->next;
 }
//排序
T=sort(head);//因为sort要改变tt,故需要一个中间变量
tt->next=T;//由于迭代产生的链表格式不规范,以下句用来整理sort函数的返回结果
tt->next->qian=tt;
tt=tt->next;
tt->next=new DATA;
tt->next->qian=tt;//对新开类赋值
tt=tt->next;
HEAD->next->next->qian=NULL;
HEAD=HEAD->next->next;
cout<<“对输入信源排序结果如下:”<<endl;
for(p=HEAD;p->next!=NULL;p=p->next)//排序输出
cout<<“xi:”<<p->Xi<<“pxi:”<<p->PXi<<endl;
//编码
cout<<“对输入信源编码结果如下:”<<endl;
a(HEAD);//编码
//解码
char jie[100];//解码用变量
cout<<“请输入需解码数据:”<<endl;
cin>>jie;
b(head,jie);
}
//编码.k
void a(DATA* pp)//定义递归函数
{float y=1;//y定义为1是因为概率最多为1
k++;//递归自增值,用于字符数组定位
DATA *head1=pp,*head2;
int o=1;
 while(1)//分01组
 {
 float l=0,z=0;
  for(int i=1;i<=o;i++)
  {
  if(pp->next==NULL) break;
  l=l+pp->PXi;
  pp=pp->next;
  }
 head2=pp->qian;//从这里分01段
  for(;pp->next!=NULL;pp=pp->next) z=z+pp->PXi;
  if(y>fabs(l-z))//判断两组值之差是否最小
  {
  y=fabs(l-z);
  pp=head1;
  o++;
  continue;
  }
  else if(z==0&&i<=2)//z=0i<1表示只有一个概率了
  {cout<<“xi:”<<head1->Xi<<“pxi:”<<head1->key<<endl;
  break;
  }
  for(DATA* u=head1;u->next!=head2->next;u=u->next) u->key[k]=’0′;//为字符串赋值
  for(DATA* h=head2;h->next!=NULL;h=h->next) h->key[k]=’1′;
 head2->qian->next=new DATA;//分段:标记head2为上一段结束位置
 head2->qian->next->qian=head2->qian;//ini
 a(head1);//递归
 a(head2);
 break;
 }
k–;//迭代还原到上一个数组位置
}
//排序.HEAD,tt,T
DATA* sort(DATA* pp)//函数递归后头变到HEAD->next->next.返回值得到最后个head2没有与tt相连,需另设.得不到结尾为空的(next=MULL)地址
{
DATA *head1=pp,*head2=pp;
if(pp->next==NULL) return pp;//当pp是最后一个直时
 for(;pp->next!=NULL;pp=pp->next)
 {
 if(1-pp->PXi>=1-head2->PXi) //两个以上的值时,由于最后一个pxi为1,所以每次都会有个最小值
 head2=pp; 
 }
 if(head2->qian==NULL)//当pp是第一个直时
 {
 head2->next->qian=NULL;
 head1=head1->next;
 }
 else //当pp是最后一个值及中间的值时
 {head2->qian->next=head2->next;
 head2->next->qian=head2->qian;
 }
tt->next=sort(head1);//递归,先得第一个,再得下一个
tt->next->qian=tt;
tt=tt->next;
return head2;
}
//解码.temp,lzy,head
void b(DATA* p,char *jie)
{DATA *temp2=new DATA;
DATA *temphead=temp2;//记录头地址
temp++;
if(jie[temp]==’/0′) return;
int temp3=0;
 while(p->r!=NULL)//;do找与解码数据相同的pxi项,并提取地址到重新构造的链表中
 {
  if(p->key[temp-lzy]==jie[temp])
  {
  temp2->Xi=p->Xi;
  int i=(-1);
   do
   {i++;
   temp2->key[i]=p->key[i];
   }while(p->key[i]!=’/0′);
  temp2->r=new DATA;
  temp2->r->qian=temp2;
  temp2=temp2->r;//对新开类赋值
  temp3++;
  }
 p=p->r;//
 }
 if(temp3==1)
 {cout<<temp2->qian->Xi;
 lzy=temp+1;//回位
 b(head,jie);
 }
else b(temphead,jie);
}

    原文作者:递归算法
    原文地址: https://blog.csdn.net/lzyblog/article/details/1396743
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞