格雷码的定义:相邻的编码,二进制只有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); }

 

相关文章:

  • 2021-06-30
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-10-29
  • 2021-06-21
  • 2022-03-02
猜你喜欢
  • 2021-09-12
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-01-01
  • 2022-12-23
相关资源
相似解决方案