生成N位格雷码

时间:2022-07-26
本文章向大家介绍生成N位格雷码,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

格雷码的定义:相邻的编码,二进制只有1位不同,这样可以防止冲突,数字逻辑的。

第一种 ---------------------- 按生成规律

格雷码产生的规律是:第一步,改变最右边的位元值;第二步,改变右起第一个为1的位元的左边位元;第三步,第四步重复第一步和第二步,直到所有的格雷码产生完毕(换句话说,已经走了(2^n) - 1 步)。

用一个例子来说明:

假设产生3位元的格雷码,原始值位 000

第一步:改变最右边的位元值: 001

第二步:改变右起第一个为1的位元的左边位元: 011

第三步:改变最右边的位元值: 010

第四步:改变右起第一个为1的位元的左边位元: 110

第五步:改变最右边的位元值: 111

第六步:改变右起第一个为1的位元的左边位元: 101

第七步:改变最右边的位元值: 100

需要注意的是,代码的健壮性, unsigned int 的范围是 0~ 2^32-1 ..所以,要保证输出的 n 要小于32

// 对 字符串 第 i+1 个字符进行反转 0->1 1->0
void MyQuFan(char * num,int i){
    if( num[i] == '0'){
            num[i] = '1';
        }
        else{
            num[i] = '0';
        }
}

// 找到字符串中,右边起,第一个1的左边的那个索引
int FindLeft(char * num,int len){
    int r = len - 1;
    for( ; r >= 0; r--){
        if( num[r] == '1')
            break;
    }
    r--;
    return r;
}

// 生成 n 位 格雷码
void newMakeGray(int n ){
    clock_t st = clock();
    
    if( n <1 || n >32)
        return ;
    if( n == 1){
        cout << "0" << endl;
        cout << "1" << endl;
        return ;
    }
    unsigned int  l = (unsigned int)pow(2,n);

    char * num = new char[n+1];
    memset(num,'0',n+1);
    num[n] = 0;
    cout << num << endl;
    for( unsigned int i = 1; i<=l-1;i++){
        if( i & 1){
        //取反最右边的一个
        MyQuFan(num,n-1);
        }else{
        //找到最右边
        int left = FindLeft(num,n);
        MyQuFan(num,left);
        }

        cout << num << endl;
    }
    printf_cpudifftime(st);
}

第二种 ----------------------------按发现的规律

递归生成码表 --- 百度百科

这种方法基于格雷码是反射码的事实,利用递归的如下规则来构造:

  1. 1位格雷码有两个码字
  2. (n+1)位格雷码中的前2n个码字等于n位格雷码的码字,按顺序书写,加前缀0
  3. (n+1)位格雷码中的后2n个码字等于n位格雷码的码字,按逆序书写,加前缀1[3]

2位格雷码

3位格雷码

4位格雷码

00 01 11 10

000 001 011 010 110 111 101 100

0000 0001 0011 0010 0110 0111 0101 0100 1100 1101 1111 1110 1010 1011 1001 1000

这样的话,我们就可以写出递归方式。这里需要注意,因为,这里用的是字符串数组,那么,由于每个进程的堆空间是有限制的,一般不能超过1G,所以这里大概估摸了下,n要小于24.

// 生成存储 n 位的字符串数组
char ** GennerChar(int n ){
    //要这么多个
    unsigned int l = (unsigned int)pow(2,n);
    char ** p = new char*[l];
    for(unsigned int i = 0;i<l;i++){
        p[i] = new char[n+1];
        memset(p[i],0,n+1);
    }
    return p;
}

// 释放内存
void deleteChar(char** p,int n ){
    unsigned int l = (unsigned int)pow(2,n);
    for(unsigned int i = 0;i<l;i++){
        delete []p[i];
    }
    delete []p;
}

void show(char ** p,int n){
    unsigned int l = (int)pow(2,n);
    for(unsigned int i = 0;i<l;i++){
        cout << p[i] << endl;
    }
    deleteChar(p,n);
}

void Gray(char ** num , int len, int max){
     if ( len > max)
         return ;
     //计算出上一个有多少个,和现在应该有多少个
     unsigned int pl = (int)pow(2,len-1);
     unsigned int nl = (int)pow(2,len);
     char ** n = NULL;
     try{
         n = GennerChar(len);
     }catch(bad_alloc& e){
         cout << e.what() << endl;
         deleteChar(num,len-1);
     }

     // 在前面的基础上,加0 和 1
     for( int i = 0;i < 2;i++){
         for(unsigned int j = 0;j<pl;j++){
             unsigned int cur = i*pl+j;
             //逆序
             if( i == 1){
                n[cur][0] = '1';
                strcat(n[cur],num[pl-j-1]);
       }
             //顺序
             else{
                 n[cur][0] = '0';
                 strcat(n[cur],num[j]);
             }
         }
     }
     deleteChar(num,len-1);

     if( len == max){
        show(n,len);
        return ;
     }
     Gray(n,len+1,max);
}

void MakeGray(int n ){
    if( n < 0 || n >= 24)
        return ;
    if( 1 == n){
        cout << "0" << endl;
        cout << "1" << endl;
    }
    char ** num = GennerChar(1);
    strcpy(num[0],"0");
    strcpy(num[1],"1");
    Gray(num,2,n);
}