唯一可译编码

引言

信源编码的设计准则是,设计完成的编码必须是唯一可译码才能够被使用。根据唯一可译码的定义:任意有限长的码元序列,只能被唯一地分割成一个个的码字,便被称为唯一可译码。希望在得到一组编码之后,能够判断所设计出来的是否是唯一可译码。唯一可译码存在性的判别,可以通过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#
信息论——基础理论与应用

  • 17
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值