格雷码应用意义及编解码

news2024/11/25 15:19:01

文章目录

      • 1. 格雷码的应用意义
      • 2. 由自然数编码获得格雷码
        • 2.1 对称法实现
        • 2.2 公式法实现
      • 3. 由格雷码解码获得自然数


1. 格雷码的应用意义

学过晶体管知识的朋友们都知道,数据位跳变就相当于硬件电路中的晶体管翻转。许多位同时跳变就相当于多个晶体管同时翻转,会导致电路中出现很大的尖峰电流脉冲,从而导致数据不稳定

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

其重要特征是一个数变为相邻的另一个数时,只有一个数据位发生跳变,由于这种特点,就可以避免电路中出现亚稳态而导致数据错误。简而言之,格雷码的一位改变特征减小了电路出错概率,实际很多场合也用到了格雷码。

四位格雷码如下图所示:

更多内容,可见百度百科「格雷码」。



2. 由自然数编码获得格雷码

leetCode当中关于格雷码的生成有:89. 格雷编码、1238. 循环码排列


2.1 对称法实现

当是 0 0 0位格雷码时,格雷码序列即为 [ 0 ] [0] [0]

如果我们获取了 n − 1 n-1 n1位格雷码序列,并记为 G n − 1 G_{n-1} Gn1,可以使用它构造获得 n n n位格雷码序列 G n G_n Gn。具体方法如下:

  • G n − 1 G_{n-1} Gn1复制一份并进行反转,记为 G n − 1 T G_{n-1}^T Gn1T
  • G n − 1 T G_{n-1}^T Gn1T中每个元素的第 n − 1 n-1 n1个二进制位均从 0 0 0变为 1 1 1,得到 ( G n − 1 T ) ′ (G_{n-1}^T)' (Gn1T)。这里最低的二进制位为第 0 0 0个二进制位;
  • G n − 1 G_{n-1} Gn1 ( G n − 1 T ) ′ (G_{n-1}^T)' (Gn1T)进行拼接,得到 G n G_n Gn

证明如下:

  • 由于 G n − 1 G_{n-1} Gn1 [ 0 , 2 ( − 1 ) [0, 2^{(-1}) [0,2(1)的排列,那么其中每个元素的第 n − 1 n-1 n1个二进制位都是 0 0 0。进而, ( G n − 1 T ) ′ (G_{n-1}^T)' (Gn1T) [ 2 n − 1 , 2 n ) [2^{n-1}, 2^{n}) [2n1,2n)的排列,所以 G n = G n − 1 + ( G n − 1 T ) ′ G_n=G_{n-1}+(G_{n-1}^T)' Gn=Gn1+(Gn1T)就是 [ 0 , 2 n ) [0,2^n) [0,2n)的排列;
  • 对于 G n − 1 G_{n-1} Gn1 ( G n − 1 T ) ′ (G_{n-1}^T)' (Gn1T)的内部,每对相邻整数的二进制恰好有一位不同。对于 G n − 1 G_{n-1} Gn1最后一个数和 ( G n − 1 T ) ′ (G_{n-1}^T)' (Gn1T)第一个数,它们只有第 n − 1 n-1 n1个二进制位不同。对于 G n − 1 G_{n-1} Gn1第一个数和 ( G n − 1 T ) ′ (G_{n-1}^T)' (Gn1T)最后一个数,它们也仅有第 n − 1 n-1 n1个二进制位不同。

因此, G n G_n Gn就是满足要求的 n n n位格雷码序列。对应的cpp代码为:

class Solution {
public:
    vector<int> grayCode(int n) {
        vector<int> ans;
        ans.push_back(0);
        for (int i = 1; i <=n; ++i) {
            int t = ans.size();
            for (int j = t-1; j >= 0; --j) {
                //ans.push_back(ans[j] + (1 << (i-1)));
                //这里+,|运算等效,因为0|A=A,且这里是按位或
                ans.push_back(ans[j] | (1 << (i-1)));
            }
        }
        return ans;
    }
};

2.2 公式法实现

也可以由公式直接求出,第 i ( i ≥ 0 ) i(i\ge0) i(i0)个格雷码为: g i = i ⊕ ⌊ i 2 ⌋ g_i=i\oplus\lfloor\frac{i}{2}\rfloor gi=i2i

其中 ⊕ \oplus 表示按位异或运算,正确性证明如下:

  • i i i为偶数时, i i i i + 1 i+1 i+1只有最低的一个二进制位不同,而 ⌊ i 2 ⌋ \lfloor\frac{i}{2}\rfloor 2i ⌊ i + 1 2 ⌋ \lfloor\frac{i+1}{2}\rfloor 2i+1相等,进而异或之后 g i g_i gi g i + 1 g_{i+1} gi+1也只有最低的一个二进制位不同;
  • i i i为奇数时,我们记 i i i的二进制表示为 ( ⋯ 01 ⋯ 11 ) 2 (⋯01⋯11)_2 (0111)2 i + 1 i+1 i+1 的二进制表示为 ( ⋯ 10 ⋯ 00 ) 2 (⋯10⋯00)_2 (1000)2,即:
    • i i i i + 1 i+1 i+1的二进制表示的若干个最高位是相同的;
    • i i i i + 1 i+1 i+1的二进制表示的从高到低的第一个不同的二进制位, i i i中的二进制为 0 0 0 i + 1 i+1 i+1中的二进制位则为 1 1 1,在此之后, i i i中的二进制均为 0 0 0 i + 1 i+1 i+1中的二进制位均为 1 1 1
    • 那么 ⌊ i 2 ⌋ \lfloor\frac{i}{2}\rfloor 2i ⌊ i + 1 2 ⌋ \lfloor\frac{i+1}{2}\rfloor 2i+1的二进制表示分别为 ( ⋯ 01 ⋯ 1 ) 2 (⋯01⋯1)_2 (011)2 ( ⋯ 10 ⋯ 0 ) 2 (⋯10⋯0)_2 (100)2,进而有: g i = ( ⋯ 01 ⋯ 11 ) 2 ⊕ ( ⋯ 10 ⋯ 0 ) 2 = ( ⋯ 010 ⋯ 0 ) 2 g_i=(⋯01⋯11)_2\oplus(⋯10⋯0)_2=(⋯010⋯0)_2 gi=(0111)2(100)2=(0100)2,以及: g i + 1 = ( ⋯ 10 ⋯ 00 ) 2 ⊕ ( ⋯ 10 ⋯ 0 ) 2 = ( ⋯ 110 ⋯ 0 ) 2 g_{i+1}=(⋯10⋯00)_2\oplus(⋯10⋯0)_2=(⋯110⋯0)_2 gi+1=(1000)2(100)2=(1100)2,也只有一个二进制位不同。
    • 注意到,当我们在表示 i + 1 i+1 i+1时,使用的的是 ( ⋯ 10 ⋯ 00 ) 2 (⋯10⋯00)_2 (1000)2 ,默认了其二进制表示的低位至少有两个 0 0 0。事实上,当 i + 1 i+1 i+1 2 2 2的倍数而不是 4 4 4的倍数时,结论相同。
class Solution {
public:
    vector<int> grayCode(int n) {
        vector<int> ret(1 << n);
        for (int i = 0; i < ret.size(); ++i) 
            ret[i] = (i >> 1) ^ i;
        return ret;
    }
};

也即二进制到格雷码转换的固定规律为:

  • 格雷码中的最高有效位(最左边)等同于二进制数中相应的最高有效位;
  • 从左到右,加上每一对相邻的二进制编码位,从而得到下一个格雷码位,舍去进位。


3. 由格雷码解码获得自然数

格雷码到二进制转换的固定规律为:

  • 二进制码的最高有效位(最左边)等同于格雷码中相应的最高有效位。
  • 将所产生的每个二进制码位加下一个相邻位置的格雷码位,从而得到下一个二进制位。舍去进位。
/*解码模板 */
#include<math.h>		// log对数函数需要用到的头文件
#include <iostream>
using namespace std;
 
int gray_decode(int num) {
	int head;
	if (!num) return 0;
	head = 1 << int(log(num) / log(2));	//C++没有直接以2为底的对数,我们创造一个以2为底的对数
   return head + gray_decode((num^head) ^ (head>>1));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/365299.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】STL之空间配置器 | STL总结

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;什么是空…

全球首个云渗透测试认证专家课程发布!腾讯安全领衔编制

2月20日&#xff0c;国际云安全联盟CSA发布了“云渗透测试认证专家CCPTP”课程体系&#xff0c;这是全球首个云渗透测试能力培养课程及人才认证项目&#xff0c;有效地弥补了云渗透测试认知的差距和技能人才培养的空白。腾讯安全在该项目中担任核心课程编撰单位。CSA是全球中立…

【双指针问题】LeetCode344、345、 844、283问题详解及代码实现

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

曼恩斯特在创业板注册生效:拟募资约5亿元,彭建林夫妇为实控人

2月21日&#xff0c;深圳证券交易所披露的信息显示&#xff0c;深圳市曼恩斯特科技股份有限公司&#xff08;下称“曼恩斯特”&#xff09;的注册生效。据贝多财经了解&#xff0c;曼恩斯特于2021年6月30日在创业板递交招股书&#xff0c;2022年6月15日获得上市委会议通过&…

老戏骨李立群真敢说,互联网吐槽郝蕾演技太差

说起老戏骨李立群&#xff0c;可能很多人都想不起来&#xff0c;他究竟出演过什么影视作品&#xff0c;不过这依然不能阻挡他的走红。李立群的走红非常偶然&#xff0c;因为在大陆拍戏多年&#xff0c;他已经在上海买房定居&#xff0c;当然偶尔也会去台北省亲。 在上海疫情爆发…

【C++】3.类和对象(中)

1.类的6个默认成员函数 一个类什么都没有不是空类 我们没有写相关函数 但编译器会自动生成6个默认函数 2.构造函数 1概念 构造函数是一个特殊的成员函数&#xff0c;名字与类名相同,创建类类型对象时由编译器自动调用&#xff0c;保证每个数据成员都有一个合适的初始值&…

微服务架构中的多级缓存设计还有人不懂?

今天我们来聊聊缓存这个话题&#xff0c;看看在微服务环境下如何设计有效的多级缓存架构。主要涉及三方面内容&#xff1a; Web 应用的客户端缓存&#xff1b;应用层静态资源缓存&#xff1b;服务层多级缓存。 首先&#xff0c;咱们先讲解微服务架构的多级缓存设计。 微服务…

ElasticSearch 学习笔记总结(一)

文章目录一、 数据的 分类二、 ElasticSearch 介绍三、 ElasticSearch 搭建四、正排索引 和 倒排索引五、ES HTTP 索引 操作六、ES HTTP 文档 操作七、ES HTTP 查询数据1. 条件查询2. 分页查询3. 排序查询4. 多条件查询5. 全文检索 完全匹配 高亮显示6. 聚合查询八、 ES HTTP 映…

2.22JVM

一.学习目标1)JVM内存区域划分2)JVM的类加载机制3)JVM的垃圾回收1.JVM执行流程程序在执行之前先要把Java代码转换为字节码(.class),JVM首先需要通过一定的方式类加载器把文件加载到运行时数据区,而字节码文件是JVM的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特…

【11-JVM面试专题-说说你知道的垃圾回收算法?垃圾回收器你知道吗?CMS、G1和ZGC垃圾回收器你有过了解吗?】

JVM面试专题-说说你知道的垃圾回收算法&#xff1f;垃圾回收器你知道吗&#xff1f;CMS、G1和ZGC垃圾回收器你有过了解吗&#xff1f; JVM面试专题-说说你知道的垃圾回收算法&#xff1f;垃圾回收器你知道吗&#xff1f;CMS、G1和ZGC垃圾回收器你有过了解吗&#xff1f;你掌握的…

Wincc Flexible smart V4触摸屏软件中批量导入PLC变量的具体方法示例(无需单个添加)

Wincc Flexible smart V4触摸屏软件中批量导入PLC变量的具体方法示例(无需单个添加) 具体操作步骤可参考以下例子中的内容: 打开STEP7-MicroWin smart软件,编辑自己的PLC程序(这里以一个简单的启保停程序为例), 如下图所示,打开Wincc Flexible smart V4触摸屏软件,新建…

双指针 (C/C++)

1. 双指针 双指针算法的核心思想&#xff1a;将暴力解法的时间复杂度&#xff0c;通常是O(N*N)&#xff0c;通过某种特殊的性质优化到O(N)。 做题思路&#xff1a;先想想暴力解法的思路&#xff0c;然后分析这道题的特殊性质&#xff0c;一般是单调性。然后得出双指针算法的思路…

微信协议网页版微信协议解析

最近在做个微信机器人&#xff0c;所以研究了网页版的微信协议及相关接口&#xff0c;在这里简单总结一下。从表面上看&#xff0c;对于网页版微信我们的使用流程是这样的&#xff1a;很简单&#xff0c;只有四步&#xff0c;但如果细化到内里细节的话&#xff0c;上面这简单四…

一文带你快速入门zabbix6.0的日常操作

文章目录前言一. zabbix基本操作入门1.1 登录和配置用户1.1.1 登录zabbix1.1.2 防爆力破解机制1.1.3 创建用户1.1.4 创建报警媒介1.1.5 设置 权限选项卡1.1.6 设置用户的访问主机权限1.2 新建主机1.2.1 添加主机1.2.2 关于添加的信息注释1.3 新增监控项1.3.1 添加监控项1.3.2 配…

若依系统如何集成qq邮件发送【超详细,建议收藏】

若依系统的部署博主就不在这儿阐述了&#xff0c;默认大家的电脑已经部署好了若依系统&#xff0c;这里直接开始集成邮件系统&#xff0c;首先我们得需要对qq邮箱进行配置&#xff1b;一套学不会你来打我&#x1f600;&#xff1b; 一、开启我们的qq邮箱发送邮件的配置 1、先进…

Qt音视频开发16-通用悬浮按钮工具栏的设计

一、前言 通用悬浮按钮工具栏这个功能经过了好几个版本的迭代&#xff0c;一开始设计的时候是写在视频控件widget窗体中&#xff0c;当时功能简单就放一排按钮在顶部悬浮widget中就好&#xff0c;随着用户需求的变化&#xff0c;用户需要自定义悬浮条的要求越发强烈&#xff0…

K_A12_031 基于STM32等单片机驱动TEMT6000环境光传感器 串口与OLED0.96双显示

K_A12_031 基于STM32等单片机驱动TEMT6000环境光传感器 串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RCTEMT6000环境光传感器模块1.2、STM32F103C8T6TEMT6000环境光…

ZCMU--5009: 龙虎斗

轩轩和开开正在玩一款叫《龙虎斗》的游戏&#xff0c;游戏的棋盘是一条线段&#xff0c;线段上有n个兵营(自左至右编号1~n)&#xff0c;相邻编号的兵营之间相隔1厘米&#xff0c;即棋盘为长度为n-1厘米的线段。i号兵营里有ci位工兵。 下面图1为n 6的示例: 轩轩在左侧&#xf…

如何通过IP找到地址?

在我们印象中&#xff0c;我们都知道可以通过 IP 地址找到某个人。但当我们细想一下&#xff0c;我们会发现其实 IP 地址与地理位置并不是直接相关的。那我们到底是如何通过 IP 地址找到地址的呢&#xff1f;答案是&#xff1a;通过自治系统&#xff08;Autonomous System&…

大势前瞻!文旅还是短视频,你弯道超车风口在这了

三年前&#xff0c;新冠疫情的影响波及整个各行各业行业&#xff0c;互联网寒冬&#xff0c;房地产崩盘&#xff0c;教培团灭&#xff0c;在这样的背景下&#xff0c;行业都进入了发展“冰雪期”。老话说大疫后必有大变&#xff0c;如今风雪融化&#xff0c;万物复苏&#xff0…