格雷码

格雷码 - 格雷码

(Gray code),又叫循环二进制码反射二进制码 

在数字系统中只能识别0和1,各种数据要转换为二进制代码才能进行处理,格雷码是一种准权码(大小为2^(n+1)-1,符号+、-交替),采用绝对编码方式,典型格雷码是一种具有反射特性和循环特性的单步自补码,它的循环、单步特性消除了随机取数时出现重大误差的可能,它的反射、自补特性使得求反非常方便。格雷码属于可靠性编码,是一种错误最小化的编码方式,因为,自然二进制码可以直接由数/模转换器转换成模拟信号,但某些情况,例如从十进制的3转换成4时二进制码的每一位都要变,使数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点,它是一种数字排序系统,其中的所有相邻整数在它们的数字表示中只有一个数字不同。它在任意两个相邻的数之间转换时,只有一个数位发生变化。它大大地减少了由一个状态到下一个状态时逻辑的混淆。另外由于最大数与最小数之间也仅一个数不同,故通常又叫格雷反射码循环码。下表为几种自然二进制码与格雷码的对照表:

格雷码 - 表


┌────┬──────┬───┬────┬──────┬────┐
│十进制数│自然二进制数│格雷码│十进制数│自然二进制数│ 格雷码 │
├────┼──────┼───┼────┼──────┼────┤
│0       │0000        │0000  │8       │1000        │1100    │
├────┼──────┼───┼────┼──────┼────┤
│1       │0001        │0001  │9       │1001        │1101    │
├────┼──────┼───┼────┼──────┼────┤
│2       │0010        │0011  │10      │1010        │1111    │
├────┼──────┼───┼────┼──────┼────┤
│3       │0011        │0010  │11      │1011        │1110    │
├────┼──────┼───┼────┼──────┼────┤
│4       │0100        │0110  │12      │1100        │1010    │
├────┼──────┼───┼────┼──────┼────┤
│5       │0101        │0111  │13      │1101        │1011    │
├────┼──────┼───┼────┼──────┼────┤
│6       │0110        │0101  │14      │1110        │1001    │
├────┼──────┼───┼────┼──────┼────┤
│7       │0111        │0100  │15      │1111        │1000    │
└────┴──────┴───┴────┴──────┴────┘

一般的,普通二进制码与格雷码可以按以下方法互相转换:

二进制码->格雷码(编码):从最右边一位起,依次将每一位与左边一位异或(XOR),作为对应格雷码该位的值,最左边一位不变(相当于左边是0);

格雷码-〉二进制码(解码):从左边第二位起,将每位与左边一位解码后的值异或,作为该位解码后的值(最左边一位依然不变).

数学(计算机)描述:

原码:p【0~n】;格雷码:c【0~n】(n∈N);编码:c=G(p);解码:p=F(c);书写时从左向右标号依次减小.
编码:c=p XOR p【i+1】(i∈N,0≤i≤n-1),c【n】=p【n】;
解码:p【n】=c【n】,p=c XOR p【i+1】(i∈N,0≤i≤n-1).

Gray Code是由贝尔实验室的Frank Gray在20世纪40年代提出的(是1880年由法国工程师Jean-Maurice-Emlle
Baudot发明的),用来在使用PCM(Pusle Code Modulation)方法传送讯号时避免出错,并于1953年3月17日取得美国专利。由定义可知,Gray Code的编码方式不是唯一的,这里讨论的是最常用的一种

 

二进制格雷码 与自然二进制码的互换 :
1、自然二进制码转换成二进制格雷码
    自然二进制码转换成二进制格雷码,其法则是保留自然二进制码的最高位作为格雷码的最高位,而次高位格雷码为二进制码的高位与次高位相异或,而格雷码的其余各位与次高位的求法相类似;比如
    9   1001 (最高位为 1 ,次高位为0 ,第三位为 0,第四位为1) 的格雷码步骤如下 :
    格雷码的最高位为 自然二进制码的最高位:1
    格雷码的次高位为 :自然二进制码的最高位与次高位相异或: 1 | 0 = 1
    格雷码的第3位为: 自然二进制码的次高位 与第3位相异或 : 0 | 0 = 0
    格雷码的第4位为: 自然二进制码的第3位 与第4位相异或  : 0 | 1 = 1
    所以 自然二进制码 1001  的二进制格雷码为 :1101
   
2、二进制格雷码转换为自然二进制码
   二进制格雷码转换成自然二进制码,其法则是 保留格雷码的坐高为作为自然二进制码的最高位,而次高位自然二进制码为高位自然二进制码与次高位二进制格雷码相异或,而自然二进制码的其余各位与次高位自然二进制码的求法相类似;比如:
   格雷码: 1101(最高位为1, 次高位为1, 第3位为0,第4位为1)
   自然二进制码的最高位为 二进制格雷码的最高位:1 
   自然二进制码的次高位为自然二进制码的高位 与格雷码的次高位相异或:1 | 1 = 0
   自然二进制码的第3位为 自然二进制码的次高位 与格雷码的第3位相异或:0 | 0 = 0
   自然二进制码的第4位为 自然二进制码的第3位 与格雷码的第4位相异或 :0 | 1 = 1
  
   所以 二进制格雷码 1101 的自然二进制码为: 1001
   

import java.util.Scanner;

public class Gray {
 public static void main(String[] args) {
  while (true) {
   System.out.println("请输入:");
   Scanner scanner = new Scanner(System.in);
   int n = scanner.nextInt();
   int num = (int) Math.pow(2, n);// 根据输入的整数,计算出此Gray序列大小
   System.out.println(" ---" + num+ "---");
   String[] s1 = { "0", "1" };// 第一个Gray序列
   for (int i = 2; i <= n; i++) {// 循环根据第一个Gray序列,来一个一个的求
    int p = (int) Math.pow(2, i);// 到了第几个的时候,来计算出此Gray序列大小
    String[] si = new String[p];
    for (int j = 0; j < p; j++) {// 循环根据某个Gray序列,来一个一个的求此序列
     if (j < (p / 2)) {
      si[j] = "0" + s1[j];// 原始序列前面加上"0"
     } else {
      si[j] = "1" + s1[p - j - 1];// 原始序列反序,前面加上"1"
     }
    }
    s1 = si;// 把求得的si,附给s1,以便求下一个Gray序列
    System.out.println("---:" +  s1.length) ;
    for (int m = 0; m < s1.length; m++) {
     System.out.println(s1[m]);
    }
   }
   for (int i = 0; i < num; i++) {
    System.out.println(s1[i]);
   }
  }
 }
}

 

 

结果:

 

请输入:
5
 ---32---
---:4
00
01
11
10
---:8
000
001
011
010
110
111
101
100
---:16
0000
0001
0011
0010
0110
0111
0101
0100
1100
1101
1111
1110
1010
1011
1001
1000
---:32
00000
00001
00011
00010
00110
00111
00101
00100
01100
01101
01111
01110
01010
01011
01001
01000
11000
11001
11011
11010
11110
11111
11101
11100
10100
10101
10111
10110
10010
10011
10001
10000
00000
00001
00011
00010
00110
00111
00101
00100
01100
01101
01111
01110
01010
01011
01001
01000
11000
11001
11011
11010
11110
11111
11101
11100
10100
10101
10111
10110
10010
10011
10001
10000
请输入:

使用递归实现格雷码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class GrayCode {

 /**
  * @param args
  */
 public static void main(String[] args) throws IOException {

  while (true){
   System.out.println("请输入格雷码位数:") ;
   int num = getInt();
   String[] grayCode = grayCode(num) ;
   for (int i = 0; i < grayCode.length; i++){
    System.out.print(grayCode[i] + "  ") ;
    if ( (i + 1) % 8 == 0){
     System.out.println(" ") ;
    }
   }
   System.out.println("");
   System.out.println("");
  }
  

 }

 private static int getInt() throws IOException{
  InputStreamReader isr = new InputStreamReader(System.in) ;
  BufferedReader br = new BufferedReader(isr) ;
  String input = br.readLine() ;
  return Integer.parseInt(input) ;
 }

 /**
  *000  --0
  *001  --1
  *011  --2
  *010  --3
  *110  --4
  *111  --5
  *101  --6
  *100  --7
  *观察除了最左边第一位即
  *00   --0
  *01   --1
  *11   --2
  *10   --3
  *10   --4
  *11   --5
  *01   --6
  *00   --7
  *
  *0 - 7 相同 ,只是第一位为 0 、1
  *1 - 6 相同 ,只是第一位为 0 、1
  *格雷码(Gray Code)是一个数列集合,每个数使用二进位来表示,假设使用n位元来表示每个数字,任两个数之间只有一个位元值不同。
例如以下为3位元的格雷码: 000 001 011 010 110 111 101 100 。
如果要产生n位元的格雷码,那么格雷码的个数为2^n.


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


用一个例子来说明:
假设产生3位元的格雷码,原始值位 000
第一步:改变最右边的位元值: 001
第二步:改变右起第一个为1的位元的左边位元: 011
第三步:改变最右边的位元值: 010
第四步:改变右起第一个为1的位元的左边位元: 110
第五步:改变最右边的位元值: 111
第六步:改变右起第一个为1的位元的左边位元: 101
第七步:改变最右边的位元值: 100


如果按照这个规则来生成格雷码,是没有问题的,但是这样做太复杂了。如果仔细观察格雷码的结构,我们会有以下发现:
1、除了最高位(左边第一位),格雷码的位元完全上下对称(看下面列表)。比如第一个格雷码与最后一个格雷码对称(除了第一位),第二个格雷码与倒数第二个对称,以此类推。
2、最小的重复单元是 0 , 1。


000
001
011
010
110
111
101
100

 

所以,在实现的时候,我们完全可以利用递归,在每一层前面加上0或者1,然后就可以列出所有的格雷码。
比如:
第一步:产生 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位元格雷码产生的。

  * @param num
  * @return
  */
 public static String[] grayCode(int num) {

  String[] grayCode = new String[(int) Math.pow(2, num)];
  if (num == 1) {
   grayCode[0] = "0";
   grayCode[1] = "1";
  } else {
   String[] last = grayCode(num - 1);
   for (int i = 0; i < last.length; i++) {
    grayCode[i] = "0" + last[i];
    grayCode[grayCode.length - 1 - i] = "1" + last[i];
   }
  }
  return grayCode;
 }

}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值