• 格雷码(Gray Code)与8421二进制码之间的转换算法 (LeetCode89)


    1. 格雷码简介

    格雷码跟8421码一样,也是一种对数字进行二进制编码的方法,只是编码方法跟常见的8421二进制编码方法不一样。

    格雷码序列中,相邻的两个数字的二进制编码只有一位是不一样的,这种编码方式常用于较复杂的电路中。大家都知道二进制的 0/1 代表了电路的 开/关 ,例如n位的二进制编码,有很多情况下电路需要遍历 0 ~ 2^n 的情况,在电路实现中就是用n位的电路的开关依次转换来实现。

    由于8421二进制编码的 0 ~ 2^n 的序列,相邻的两个数的二进制相差会出现多位不一样,因此电路在遍历时就需要同事变更多位电路开关,而这种操作是需要时间的,在这个过程中就有可能出现中间的状态,从而出现错误的编码。
    例如:
    n = 3 的 8421 编码

    i8421编码
    0000
    1001
    2010
    3011
    4100
    5101
    6110
    7111

    相邻两个数之间的二进制编码相差的不止1位,就会出现上面说的情况。而格雷码编码中,相邻的两个数的二进制编码只有1位是不一样的,因此在物理电路的变换中只涉及到一位电路的开关操作,即操作是原子的,不会出现中间过程,也就不会出现错误编码了,因此在某些场景的电路信号中被广泛运用。

    2. 格雷码与8421二进制码之间的转换

    n = 3 为例,8421码与格雷码之间的对应关系如下:

    格雷码也是以全0开头的

    i8421编码格雷码
    0000000
    1001001
    2010011
    3011010
    4100110
    5101111
    6110101
    7111100

    2.1 8421码 ==> 格雷码

    算法
    1、8421码最左边一位不变,保留下来成为格雷码的最左边一位;
    2、从左边第二位开始,将8421码的每一位与它左边的一位相 异或 得到对应位的格雷码;

    代码实现

    public static int toGrayCode(int i) {
    	return i ^ (i >> 1);
    }
    
    • 1
    • 2
    • 3

    ii - 1 异或,也即将 i 的每一位与它的左边一位相异或。右移操作左边是补的0,0与任何数异或等于其本身,因此最左边一位被保留了。

    2.2 格雷码 ==> 8421码

    算法
    1、格雷码的最左边一位保持不变,保留下来成为8421码的最左边一位;
    2、从左边第二位开始,将8421码的每一位与前一位计算得到的8421码 异或 得到当前的8421码;

    解释

    8421码转格雷码是通过 i ^ (i - 1) 实现的,要想将格雷码转换为8421码,我们知道,异或运算有如下性质:
    (a ^ b) ^ b = a ^ (b ^ b) = a

    因此,可以得到 (i ^ (i >> 1)) ^ (i >> 1) = i ^ ((i >> 1) ^ (i >> 1)) = i
    所以在上面的算法中在计算当前位的8421码时,需要将当前位的格雷码与上一位计算得到的8421码异或。

    代码实现

    public static int toBinaryCode(int grayCode, int n) {
        String grayCodeStr = Integer.toBinaryString(grayCode);
        if (grayCodeStr.length() < n) {
            // 补齐0,使得二进制编码有n位
            int bitCnt = grayCodeStr.length();
            for (int i = bitCnt; i < n; i++) {
                grayCodeStr = "0" + grayCodeStr;
            }
        }
        StringBuilder binary = new StringBuilder();
        binary.append(grayCodeStr.charAt(0)); //最左边一位不变
        for (int i = 1; i < n; i++) {
            char cur = grayCodeStr.charAt(i);
            char preBinary = binary.charAt(i - 1);
            int tmp = (cur - '0') ^ (preBinary - '0');
            if (tmp == 0) binary.append('0');
            else binary.append('1');
        }
        return Integer.parseInt(binary.toString(), 2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.3 测试

    public class Demo {
        public static void main(String[] args) {
            int n = 3;
            int powN = (int) Math.pow(2, n);
            int[] grayCode = new int[powN];
            System.out.println("========= Binary to GrayCode ==========");
            for (int i = 0; i < powN; i++) {
                grayCode[i] = toGrayCode(i);
                System.out.print(grayCode[i] + " ");
            }
            System.out.println();
            System.out.println("========= GrayCode to Binary ==========");
            for (int i = 0; i < powN; i++) {
                int binary = toBinaryCode(grayCode[i], n);
                System.out.print(binary + " ");
            }
            System.out.println();
        }
    
        public static int toGrayCode(int i) {
            return i ^ (i >> 1);
        }
    
        public static int toBinaryCode(int grayCode, int n) {
            String grayCodeStr = Integer.toBinaryString(grayCode);
            if (grayCodeStr.length() < n) {
                // 补齐0,使得二进制编码有n位
                int bitCnt = grayCodeStr.length();
                for (int i = bitCnt; i < n; i++) {
                    grayCodeStr = "0" + grayCodeStr;
                }
            }
            StringBuilder binary = new StringBuilder();
            binary.append(grayCodeStr.charAt(0)); //最左边一位不变
            for (int i = 1; i < n; i++) {
                char cur = grayCodeStr.charAt(i);
                char preBinary = binary.charAt(i - 1);
                int tmp = (cur - '0') ^ (preBinary - '0');
                if (tmp == 0) binary.append('0');
                else binary.append('1');
            }
            return Integer.parseInt(binary.toString(), 2);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在这里插入图片描述

    可以看到二进制与格雷码之间是可以正确转换的。


    参考文献

    [1] https://baike.baidu.com/item/%E6%A0%BC%E9%9B%B7%E7%A0%81/6510858?fr=aladdin#5
    [2] https://leetcode.com/problems/gray-code/

  • 相关阅读:
    矩阵的QR分解
    Three.js 进阶之旅:物理效果-3D乒乓球小游戏 🏓
    数据结构 - 二叉树
    分布式系列之分布式计算框架Flink深度解析
    初识网络原理
    探索安全与灵活性的边界,波卡账户抽象与多签管理的创新之路
    c语言open函数追加模式的疑问
    webpack-bundle-analyzer 插件配置
    【毕设选题推荐】机器人工程专业毕设选题推荐
    cf #825 Div.2(A~C2)
  • 原文地址:https://blog.csdn.net/qq_27198345/article/details/126080478