格雷码的生成

格雷码(Gray Code)

格雷码:在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码,另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。

Decimal Binary Gray Gray as decimal
0 000 000 0
1 001 001 1
2 010 011 3
3 011 010 2
4 100 110 6
5 101 111 7
6 110 101 5
7 111 100 4

那么当给你一个数n时,你怎么生成n位格雷码呢?


假设原始的值从0开始,格雷码产生的规律是:
1.改变最右边的位元值。
2.改变右起第一个为1的位元的左边位元。
3.重复1。
4.重复2。
直到所有的格雷码产生完毕。
eg:假设产生3位元的格雷码
原始值位 000
第一步:改变最右边的位元值: 001
第二步:改变右起第一个为1的位元的左边位元: 011
第三步:改变最右边的位元值: 010
第四步:改变右起第一个为1的位元的左边位元: 110
第五步:改变最右边的位元值: 111
第六步:改变右起第一个为1的位元的左边位元: 101
第七步:改变最右边的位元值: 100

vector<string> prograycode(int n)
{
    int num(1 << n);
    vector<string> graycode;
    string start(n, '0');
    graycode.push_back(start);
    num -= 1;
    int state = 0;
    while(num > 0)
    {
        switch(state)
        {
        case 0 :
            start = start.replace(n-1, 1, start[n-1] == '0' ? "1" : "0");
            graycode.push_back(start);
            state = 1;
            break;

        case 1:
            int pos = start.find_last_of('1') - 1;
            start = start.replace(pos, 1, start[pos] == '0' ? "1" : "0");
            graycode.push_back(start);
            state = 0;
            break;
        }
        num--;
    }
    return graycode;
}

上面的方法是最基础最原始的方法,但是实现过程较为繁琐。


另一种方法:假设已经存在了n-1位的格雷码序列,那么只需要在n-1位格雷码的前面加上“0”和“1”就可以生成n位的格雷码,因此,自然而然的想到使用递归来实现。

vector<string> proGraycode(int n)
{
    vector<string> graycode(1 << n);
    if(n == 1)
    {
        graycode[0] = "0";
        graycode[1] = "1";
        return graycode;
    }

    vector<string> last = proGraycode(n-1);

    for(int i = 0; i < (int)last.size(); ++i)
    {
        graycode[i] = "0" + last[i];
        graycode[graycode.size() - 1- i] = "1" + last[i];
    }

    return graycode;
}

补充:格雷码与二进制编码的相互转换。
G(i) = B(i) XOR B(i+1) 即格雷码的第i位等于二进制编码的第i位与第i+1位异或,G的最高位保持B的最高位不变
eg:二进制01101转换成格雷码为01011
0 1 1 0 1
xor * 0 1 1 0
———————— *表示该位不变
0 1 0 1 1


博文参考于:格雷码的实现

你可能感兴趣的:(算法分析)