Gray码的生成

 
近期开始学习 TAOCP第4卷第2册,书中一开始就介绍了Gray二进制码,觉得非常有趣,就参照书中的算法写一个小程序来生成Gray码。
开始之前,我们先来看看什么是 Gray二进制码。Gray二进制码是以一种简单和规则的方式来排列所有2^n个n位的二进制串,即每次仅改变一个二进制位。例如,对于n=4,Gray二进制码是:
0000, 0001, 0011, 0010, 0110, 0111, 0101, 0100,
1100, 1101, 1111, 1110, 1010, 1011, 1001, 1000
书上说,在进行模拟信息与数字信息之间的相互转换时, Gray二进制码非常有用,但具体如何使用我也不太清楚。我们只是来看看,对于任意给定的n,如何生成相应的Gray二进制码。
书中给出了一个最简单的生成 Gray二进制码的规则。如果Γn表示n位二进制串的Gray二进制码,则我们可以通过以下两个规则来递归地定义Γn:
Γ 0 = ε
Γ n +1 = 0Γn,1Γn R
这里ε表示空串, 0Γn表示把0加到Γn序列中的每个串前面所得到的序列,Γn R表示把Γ n序列反序,1Γn R则表示把 1加到Γn R序列中的每个串前面所得到的序列。由于Γ n的最后一个串等于Γn R的头一个串,所以显然可知,如果Γ n满足Gray码的性质,则Γn+1也恰好满足。
由于每次只改变一个二进制位,所以如果我们从全 0串开始计算Gray码,则肯定得到的第1,3,5,7,……个串有偶数个位为1,而第2,4,6,8,……个串则有奇数个位为1。经过一番推论,书中给出了一个生成Gray二进制码的算法:
从全 0串开始,第一个串为全0串;如果当前串有偶数个位为1,则下一个串为将当前串最低位反转所得;如果当前串有奇数个位为1,则找出当前串中为1的最低位,将该位的高一位反转即可得到下一个串;循环以上步骤直至n位二进制串溢出。
相应的程序代码如下:
 
#include <iostream>
#include <cstdlib>
 
using namespace std;
 
void Gray(int n)
{
    unsigned long g = 0;
    unsigned long max = (unsigned long)(1L) << n;
    do
    {
        cout << g << " ";
        g ^= 1;
        cout << g << " ";
        g ^= (g ^ (g-1)) + 1;
    }
    while (g < max);
}
 
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cerr << "Usage: " << argv[0] << " <n>/n";
        return 1;
    }
    int n = atoi(argv[1]);
    if (n < 1 || n > 30)
    {
        cerr << n << " is too big or too small/n";
        return 2;
    }
 
    Gray(n);
   
    return 0;
}
 
由于用的是 32位机器,所以我把n限制为30以内。main()函数无须多说,主要的算法在于Gray()函数。变量g为每次输出的Gray码,从0开始循环,变量max用于检测g是否溢出;每次循环产生两个Gray码,第一个有偶数位1,第二个有奇数位1。从偶数位1的串到奇数位1的串很简单,g ^= 1; 即是将最低位反转。从奇数位1的串以偶数位1的串的生成则有点技巧了。
g ^= (g ^ (g-1)) + 1;
我来解释一下。首先,假设 g中为1的最低位是第i位,即g的第i位为1,而所有比第i位低的位全为0;那么g-1可以将g的第i位变为0,而所有比第i位低的位全部由0变为1;这样g与g-1相比,第i位以上的所有位(不含第i位)全部相同,第i位以下的所有位(含第i位)全部相异,所以g ^ (g-1)得到的结果是:第i位以上的所有位(不含第i位)全部为0,第i位以下的所有位(含第i位)全部为1;这个数加1,就得到了除了第i+1位为1其它所有位为0的串;让g与这个串异或,即是将g的第i+1位反转。
是不是说得有点复杂呢?我们用一个例子来说明一下,就会容易明白了。假设现在的 g为1110,则g-1为1101,两者异或得到0011,加1得到0100,将此数与g异或最终得到1010。恰恰是把g中为1的最低位的高一位反转。
我们对此程序输入 n=4,运行得到以下结果:
0 1 3 2 6 7 5 4 12 13 15 14 10 11 9 8
由于不是二进制表示,所以看起来有点乱。如果你将它们转为二进制,就可以看到输出的结果是正确的,与本文前面给出的 Gray二进制码例子是相符的。
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值