引言
信源编码的设计准则是,设计完成的编码必须是唯一可译码才能够被使用。根据唯一可译码的定义:任意有限长的码元序列,只能被唯一地分割成一个个的码字,便被称为唯一可译码。希望在得到一组编码之后,能够判断所设计出来的是否是唯一可译码。唯一可译码存在性的判别,可以通过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},根据上述测试方法,来判断是否是唯一可译码。
程序代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | #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#
信息论——基础理论与应用