內容與設計思想
按照教材方式建立數據成員變量.設有離散無記憶信源X,P(X).二進制費諾編碼爲:1.將信源符號按概率從大到小的順序排列2.將信源分成兩組――按兩組概率之差爲最小分.3.上面一組編碼爲0,下面一組編碼爲1,一直分到一組只有一個信源爲止.4.將一個信源分組得到的0和1全部連接起來,組成該信源的碼字,信源即得到自己的費諾編碼.
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);
}