C语言格雷码相关

  这几天做了几家公司的模拟在线测评题,均有关于格雷码的相关知识,有好一部分要运用到二进制与位运算,这些我都不太熟,今天趁格雷码把这些知识都记录一下。

格雷码的生成

  相邻格雷码之间只有一位不同,这是为了防止转换时多位同时变化而造成的延时的影响。具体定义如下。

在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。在数字系统中,常要求代码按一定顺序变化。例如,按自然数递增计数,若采用8421码,则数0111变到1000时四位均要变化,而在实际电路中,4位的变化不可能绝对同时发生,则计数中可能出现短暂的其它代码(1100、1111等)。在特定情况下可能导致电路状态错误或输入错误。使用格雷码可以避免这种错误。格雷码有多种编码形式。

  如果要产生n位元的格雷码,那么格雷码的个数为2^n。当初这里看错了以为是2n,后来重新设计了一个函数计算2^n,才把问题解决。

  设计方法:
  第一步:产生 0, 1 两个字符串。
  第二步:在第一步的基础上,每一个字符串都加上0和1,但是每次只能加一个,所以得做两次。这样就变成了 00,01,11,10 (注意对称)。
  第三步:在第二步的基础上,再给每个字符串都加上0和1,同样,每次只能加一个,这样就变成了 000,001,011,010,110,111,101,100。
  好了,这样就把3位元格雷码生成好了。
  如果要生成4位元格雷码,我们只需要在3位元格雷码上再加一层0,1就可以了: 0000,0001,0011,0010,0110,0111,0101,0100,1100,1101,1110,1010,0111,1001,1000.
  也就是说,n位元格雷码是基于n-1位元格雷码产生的。
  下面是代码,利用递归来生成n位格雷码。

#include 
#include 

#define MAX_LEN 256

char GrayCode[MAX_LEN][MAX_LEN];

//2 ^ n
int pow(int m)
{
    int i, sum = 2;
    if(1 == m)
    {
        return 2;
    }
    for(i = 1; i < m; i++)
    {
        sum *= 2;
    }
    return sum;
}

char** GrayCodeCreate(int n)
{
    int i, j;

    if(1 > n)
    {
        printf("Wrong!\n");
        return **GrayCode;
    }
    else if(1 == n)
    {
        //printf("%d ", strlen(GrayCode[0]));
        GrayCode[0][0] = '0';
        GrayCode[1][0] = '1';
        //printf("%d ", strlen(GrayCode[0]));
        return **GrayCode;
    }

    GrayCodeCreate(n - 1);

    for(i = pow(n) / 2 - 1, j = pow(n) / 2; i >= 0, j < pow(n); i--, j++)
    {
        strcpy(GrayCode[j], GrayCode[i]);
    }
    for(i = 0, j = pow(n) / 2; i < pow(n) / 2, j < pow(n); i++, j++)
    {
        GrayCode[i][strlen(GrayCode[i])] = '0';
        GrayCode[j][strlen(GrayCode[j])] = '1';
    }
    return **GrayCode;
}

int main()
{
    int i, j, n;
    scanf("%d", &n);
    //printf("%d ", pow(n));
    GrayCodeCreate(n);
    for(i = 0; i < pow(n); i++)
    {
        for(j = strlen(GrayCode[i]) - 1; j >= 0; j--)
        {
            putchar(GrayCode[i][j]);
        }
        printf("\n");
    }
    return 0;
}

判断是否可以以格雷码的方式排列

  给出两个8位二进制代码,判断这两个代码可否以格雷码的方式连续排列。换个问法就是这两个二进制代码是否只有一位的区别。
  通过这题顺便了解了一下C语言里是如何输出二进制的,也同时复习了一下位运算的相关用法。首先对两串二进制代码用异或运算^,得到一个新的二进制代码,再对新的代码用(1 << i)的方式逐位用与运算&。
  这里有个小地方需要注意一下,与运算以后的结果不可直接输出,应该判断结果是否为0,不为0输出1,否则输出0。
  具体代码如下:

#include 
#include 

int ShowInBinary(char term)
{
    int i;
    int j;
    for(i = 7; i >= 0; i--)
    {
        j = (term & (1 << i));
        if(j)
        {
            printf("1");
        }
        else
        {
            printf("0");
        }
    }
    printf("\n");
    return 0;
}

int IsGrayOrNot(char term1, char term2)
{
    char ch = term1 ^ term2;
    int i, j, count = 0;

    for(i = 7; i >= 0; i--)
    {
        j = ch & (1 << i);
        if(1 == j)
        {
            count++;
        }
    }
    if(count) return 1;
    //ShowInBinary(ch);

    return 0;
}

int main()
{
    char term1 = 0x9d;
    char term2 = 0x9e;

    printf("%d", IsGrayOrNot(term1, term2));
    //ShowInBinary(term1);
    //ShowInBinary(term2);
    return 0;
}

你可能感兴趣的:(C语言)