在一组数的编码中,若任意两个相邻的代码只有一个二进制数不同,则称这种编码为格雷码(Gary Code),请编写一个函数,使用递归的方法生成N位的格雷码。给定一个整数n,请返回n位的格雷码,顺序为从0开始。
测试样例:
输入:1
返回:“0”,“1”。
(1)首先给出二进制--->格雷码的转换:
此方法从对应的n位二进制字中直接得到n位格雷码字,步骤如下:
(1)对n位二进制的码字,从右向左,以0到n- 1编号
(2)如果二进制码字的第 i 位和第i + 1位相同,则对应的格雷码第 i 位为0,否则为1(当i + 1 = n时,二进制码的第n位被认为是0,即第n - 1位不变)
例如:
二进制码0101,为4位数,所以其所转化为格雷也必为4位数,因此可取转成之二进制位码第五位为0,即0 b3 b2 b1 b0。
根据上面的方法可得出0101对应的格雷码为0111。
(2)格雷码--->二进制码(解码)
从左边第二位起,将每位与左边一位解码后的值异或,作为该位解码后的值(最左边一位依然不变)。依次异或,直到最低位。依次异或转换后的值(二进制数)就是格雷码转换后的二进制码的值。
例如:格雷码1010
(a)最左边的1不变,则二进制位 1 b2 b1 b0
(b)b2 = 1 异或 0 = 1,则二进制为 1 1 b1 b0
(c)b1 = 1 异或 1 = 0,则二进制为 1 1 0 b0
(d)b0 = 0 异或 0 = 1,则二进制为 1 1 0 0
下面给出我自己编写的转换程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 100
//获取整数的二进制码
void getbinary(int x,char *s)
{
if(x == 0){
*s = 0 + '0';
return;
}
if(x){
*s = x % 2 + 48;
x = x / 2;
getbinary(x,s + 1);
}
}
//获取整数的格雷码
//
// B = 0 b3 b2 b1 b0
// \ / \ / \ / \ /
// G = g3 g2 g1 g0
//
//
void getgray_code(int x)
{
int n = x >> 1;
int len1,len2,i;
char s1[N] = {0};
char s2[N] = {0};
getbinary(x,s1);
getbinary(n,s2);
len1 = strlen(s1);
len2 = strlen(s2);
for(i = len2 - 1;i >= 0;i--){
s1[i] = ((s1[i] - '0') ^ (s2[i] - '0')) + 48;
}
for(i = len1 - 1;i >= 0;i--){
printf("%c ",s1[i]);
}
printf("\n");
}
int main(int argc,char **argv)
{
int n;
int len;
int i ;
char s[N] = {0};
while(1){
printf("请输入一个整数n:(-1 代表退出)\n");
scanf("%d",&n);
if(n == -1){
printf("error!\n");
exit(1);
}
#if 1
printf("binary code:\n");
getbinary(n,s);
len = strlen(s);
for(i = len - 1;i >= 0;i--){
printf("%c ",s[i]);
}
printf("\n");
#endif
printf("gray code:\n");
getgray_code(n);
}
return 0;
}
我们先来看执行的结果:
该程序将二进制码和格雷码都进行了打印,在程序中用到字符数组来进行存储。。。
下面给出另一种解法:该思路就是整数n的格雷码等于整数n - 1的格雷码前一部分加“0”,后一部分加上“1”.
具体的代码如下:
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
//格雷码
string * getgray(int n)
{
int count = 1 << n;
int len;
string *strArr = new string[count];
if(n == 0){
cout<<"格雷码转换n值大于0!!!"<<endl;
exit(1);
}
if(n == 1){
strArr[0] = "0";
strArr[1] = "1";
return strArr;
}else{
string *strArr1 = getgray(n - 1);
len = count / 2;
for(int i = 0;i< len;i++){
strArr[i] = "0" + strArr1[i];
}
for(int i = 0;i < len;i++){
strArr[count - i - 1] = "1" + strArr1[i];
}
return strArr;
}
}
int main(int argc,char**argv)
{
int n;
int len;
int i;
string *b;
while(1){
cout<<"请输入整数n:(-1 == quit)"<<endl;
cin>>n;
if(n == -1){
cout<<"error!"<<endl;
exit(1);
}
len = 1 << n;
b = getgray(n);
#if 0
for(int i = 0;i < len;i++){
cout<<b[i]<<endl;
}
#endif
cout<<b[n]<<endl;
b = NULL;
}
}
其执行结果如下:
这里使用到了C++中的string类,还要说明一下string对象进行加法时,比如:“0” + “1” = “01”,只是字符的连接,这一点比较重要!!!个人还是觉得第二种方法比较好。。。