唯一可译编码
引言
信源编码的设计准则是,设计完成的编码必须是唯一可译码才能够被使用。根据唯一可译码的定义:任意有限长的码元序列,只能被唯一地分割成一个个的码字,便被称为唯一可译码。希望在得到一组编码之后,能够判断所设计出来的是否是唯一可译码。唯一可译码存在性的判别,可以通过Kraft不等式给出唯一可译码存在的充分必要条件,即: D进制码字集合C=(C1, C2, ., Cn },码集中每-C i(i=1, 2, ., n)都是一个D进制符号串。设C1, C2, . Cn对应的码长分别是L1, L 2, , Ln ,则存在唯一可译码的充要条件是 :
显然,克劳夫特不等式只涉及唯一可译码的存在问题而不涉及具体的码。它强调的是存在,但这并不是唯一可译码判断的充要条件。也就是说,唯一可译码一定满足克拉夫特不等式,但是反之,满足克拉夫特不等式的码不一定是唯一可译码。
算法原理
目前,常用的判别唯一可译码的方法有两种:一种是根据异前缀码来进行判断的方法,另一种是由A. A. Sardinas和
G. W. patterson于1957年提出的算法。本文具体阐述第二种。
根据唯一可译码的定义可知,当且仅当有限长的码符号序列能译成两种不同的码字序列,则此码一定不是唯一可译变长码。假设图一中情况发生,有限长码符号序列译成了两种不同的码字序列(Ai)和(Bi),其中Ai,和Bi,都是码字(Ai, Bi属于C)。
由图一可知,当图中情况发生时, B1一定是A1的前缀,而A1被B1截去前面部分后的尾随后缀一定是另一码字B2的前级;又B2的尾随后缀又是其他码字的前缀。最后,码符号序列的尾部一定是某个码字。
图一:
由此可得,唯一可译码的判断方法是:
将码C中所有码字可能的尾随后缀组成一个集合F,当且仅当集合F中没有包含任一码字,则可判断此码C为唯一可译变长码。
如何构成集合F,可以按如下步骤进行:
首先,观察码C中最短的码字是否是其他码字的前缀。若是,将其所有可能的尾随后缀排列出。就是将其他码字序列中截取与最短码字相同前缀部分,余下的序列为尾随后缀。而这些尾随后缀又可能是某些码字的前缀,或者最短码字又仍是这些尾随后级的前缀,再将由这些尾随后缀产生的新的尾随后缀列出。然后再观察这些新的尾随后缀是否是某些码字的前缀,或观察有否其他码字的前缀或没有新的尾随后缀产生为止。这样首先获得是由最短的码字能引起额所有尾随后缀。接着,按照上述步骤依次将次短的码字…所有的可能产生的尾随后缀全部列出。由此得到的由码C的所有可能的尾随后缀组成的集合F。
需要注意的是,我们的判停条件有两个:新生成的f集合为空,没有新的的元素生成(是唯一可译码)或者集合中与C集合中的某个码字重复(不是唯一可译码)。
例题
直接上题。
现设码C={0,10,1100,1110,1011,1101},根据上述测试方法,来判断是否是唯一可译码。
程序代码
#include<stdio.h>
#include<string.h >
char c[100][50];
char f[300][50];
int N, sum = 0; // N为输入码字的个数, sum为尼随后缀集合中码字的个数
int flag; //判断是否唯一可译标查位
void patterson(char c[],char d[]) //检测尾随后缀
{
int i, j, k;
for (i = 0;; i++)
{
if (c[i] == '\0' && d[i] == '\0') //字符一样跳出
break;
if (c[i] == '\0') //d比c长,将d的尾随后缀放入f中
{
for (j = i; d[j] != '\0'; j++)f[sum][j - i] = d[j];
f[sum][j - i] = '\0';
for (k = 0; k < sum; k++)
{
if (strcmp(f[sum], f[k]) == 0) //查看当前生成的尾随后缀在f集合中是否存在
{
sum--; sum--; break;
}
}
sum++;
break;
}
if (d[i] == '\0') //c比d长,将c的wei'sui后缀放入f中
{
for (j = i; c[j] != '\0'; j++)f[sum][j - i] = c[j];
f[sum][j - i] = '\0';
for (k = 0; k < sum; k++)
{
if (strcmp(f[sum], f[k]) == 0) //查看当前生成的尾随后缀在f集合中是否存在
{
sum--; break;
}
}
sum++;
break;
}
if (c[i] != d[i])
break;
}
}
int main()
{
int i, j;
printf("请输入码字的个数(小于100):"); //输入码得个数
scanf_s("%d", &N,10);
while (N > 100)
{
printf("输入码字得个数过大,请输入小于100的数\n");
printf("请输入码字的个数(小于100):");
scanf_s("%d", &N,10);
}
flag = 0;
printf("请分别输入码字(每个码字长度小于50个字符):\n");
for (i = 0; i < N; i++)
{
scanf_s("%s", &c[i],51);
}
for(i=0;i<N-1;i++) //判断如果码本身是否重复
for (j = i + 1; j < N; j++)
{
if (strcmp(c[i], c[j]) == 0)
{
flag = 1; break;
}
}
if (flag == 1)
printf("这不是唯一可译码。\n");
else
{
for (i = 0; i < N ; i++) //根据原始编码生成的尾随后缀集合s[1]放入f中
{
for (j = i + 1; j < N; j++)
patterson(c[i], c[j]);
}
for (i = 0;; i++)
{
int s = 0;
for (j = 0; j < N; j++)
{
if (i == sum)
{
s = 1; break;
}
else patterson(f[i], c[j]);
}
if (s == 1)break;
}
for (i = 0; i < sum; i++) //判断p里面的字符串是否与s中的重复,重复则不是唯一的
{
for (j = 0; j < N; j++)
{
if (strcmp(f[i], c[j]) == 0)
{
flag = 1;
break;
}
}
}
if (flag == 1)
printf("这不是唯一可译码的。\n");
else
printf("这是唯一可译码。\n");
}
printf("尾随后缀集合为:");
for (i = 0; i <= sum; i++)
printf("\n%s", f[i]);
}
样例
例如10,0,100。这三个码字,程序输出结果:
再如6个码字:{0,10,1100,1110,1011,1101}。
参考:https://wenku.baidu.com/view/dca90b56ad02de80d4d840ef.html#
信息论——基础理论与应用
更多推荐
所有评论(0)