格雷码应用意义及编解码
Posted KuoGavin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了格雷码应用意义及编解码相关的知识,希望对你有一定的参考价值。
文章目录
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 n−1位格雷码序列,并记为 G n − 1 G_n-1 Gn−1,可以使用它构造获得 n n n位格雷码序列 G n G_n Gn。具体方法如下:
- 将 G n − 1 G_n-1 Gn−1复制一份并进行反转,记为 G n − 1 T G_n-1^T Gn−1T;
- 将 G n − 1 T G_n-1^T Gn−1T中每个元素的第 n − 1 n-1 n−1个二进制位均从 0 0 0变为 1 1 1,得到 ( G n − 1 T ) ′ (G_n-1^T)' (Gn−1T)′。这里最低的二进制位为第 0 0 0个二进制位;
- 将 G n − 1 G_n-1 Gn−1和 ( G n − 1 T ) ′ (G_n-1^T)' (Gn−1T)′进行拼接,得到 G n G_n Gn。
证明如下:
- 由于 G n − 1 G_n-1 Gn−1是 [ 0 , 2 ( − 1 ) [0, 2^(-1) [0,2(−1)的排列,那么其中每个元素的第 n − 1 n-1 n−1个二进制位都是 0 0 0。进而, ( G n − 1 T ) ′ (G_n-1^T)' (Gn−1T)′是 [ 2 n − 1 , 2 n ) [2^n-1, 2^n) [2n−1,2n)的排列,所以 G n = G n − 1 + ( G n − 1 T ) ′ G_n=G_n-1+(G_n-1^T)' Gn=Gn−1+(Gn−1T)′就是 [ 0 , 2 n ) [0,2^n) [0,2n)的排列;
- 对于 G n − 1 G_n-1 Gn−1和 ( G n − 1 T ) ′ (G_n-1^T)' (Gn−1T)′的内部,每对相邻整数的二进制恰好有一位不同。对于 G n − 1 G_n-1 Gn−1最后一个数和 ( G n − 1 T ) ′ (G_n-1^T)' (Gn−1T)′第一个数,它们只有第 n − 1 n-1 n−1个二进制位不同。对于 G n − 1 G_n-1 Gn−1第一个数和 ( G n − 1 T ) ′ (G_n-1^T)' (Gn−1T)′最后一个数,它们也仅有第 n − 1 n-1 n−1个二进制位不同。
因此, 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(i≥0)个格雷码为: g i = i ⊕ ⌊ i 2 ⌋ g_i=i\\oplus\\lfloor\\fraci2\\rfloor gi=i⊕⌊2i⌋
其中 ⊕ \\oplus ⊕表示按位异或运算,正确性证明如下:
- 当 i i i为偶数时, i i i和 i + 1 i+1 i+1只有最低的一个二进制位不同,而 ⌊ i 2 ⌋ \\lfloor\\fraci2\\rfloor ⌊2i⌋和 ⌊ i + 1 2 ⌋ \\lfloor\\fraci+12\\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
(⋯01⋯11)2,
i
+
1
i+1
i+1 的二进制表示为
(
⋯
10
⋯
00
)
2
(⋯10⋯00)_2
(⋯10⋯00)2,即:
-
i
以上是关于格雷码应用意义及编解码的主要内容,如果未能解决你的问题,请参考以下文章
-
i