格雷码(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
博文参考于:格雷码的实现