Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4447092
  • 博文数量: 1214
  • 博客积分: 13195
  • 博客等级: 上将
  • 技术积分: 9105
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-19 14:41
个人简介

C++,python,热爱算法和机器学习

文章分类

全部博文(1214)

文章存档

2021年(13)

2020年(49)

2019年(14)

2018年(27)

2017年(69)

2016年(100)

2015年(106)

2014年(240)

2013年(5)

2012年(193)

2011年(155)

2010年(93)

2009年(62)

2008年(51)

2007年(37)

分类:

2011-03-07 14:12:31

文章来源:http://hi.baidu.com/zyzbm/blog/item/fac9f96e8f1f0bd881cb4a9e.html

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

  在数字系统中只能识别01,各种数据要转换为二进制代码才能进行处理,格雷码是一种无权码,采用绝对编码方式,典型格雷码是一种具有反射特性和循环特性的单步自补码,它的循环、单步特性消除了随机取数时出现重大误差的可能,它的反射、自补特性使得求反非常方便。格雷码属于可靠性编码,是一种错误最小化的编码方式,因为,自然二进制码可以直接由数/模转换器转换成模拟信号,但某些情况,例如从十进制的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) int a; a = ;
格雷码-〉二进制码(解码):从左边第二位起,将每位与左边一位解码后的值异或,作为该位解码后的值(最左边一位依然不变).
数学(计算机)描述:
原码:p[0~n]格雷码c[0~n](nN);编码:c=G(p);解码:p=F(c);书写时从左向右标号依次减小.
编码:c=p XOR p[i+1](iN,0≤i≤n-1)c[n]=p[n]
解码:p[n]=c[n]p=c XOR p[i+1](iN,0≤i≤n-1).

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


----------------------------------------------------------------------------------------------------------------------------------------------------------
說明
Gray Code是一個數列集合,每個數使用二進位來表示,假設使用n位元來表示每個數好了,任兩個數之間只有一個位元值不同,例如以下為3位元的Gray Code:
000 001 011 010 110 111 101 100

由定義可以知道,Gray Code的順序並不是唯一的,例如將上面的數列反過來寫,也是一組Gray Code:
100 101 111 110 010 011 001 000

Gray Code是由貝爾實驗室的Frank Gray在1940年代提出的,用來在使用PCM(Pusle Code Modulation)方法傳送訊號時避免出錯,並於1953年三月十七日取得美國專利。

解法
由於Gray Code相鄰兩數之間只改變一個位元,所以可觀 察Gray Code從1變0或從0變1時的位置,假設有4位元的Gray Code如下:
0000 0001 0011 0010 0110 0111 0101 0100
1100 1101 1111 1110 1010 1011 1001 1000

觀察奇數項的變化時,我們發現無論它是第幾個Gray Code,永遠只改變最右邊的位元,如果是1就改為0,如果是0就改為1。

觀察偶數項的變化時,我們發現所改變的位元,是由右邊算來第一個1的左邊位元。

以上兩個變化規則是固定的,無論位元數為何;所以只要判斷位元的位置是奇數還是偶數,就可以決定要改變哪一個位元的值,為了程式撰寫方便,將陣列索引 0當作最右邊的值,而在列印結果時,是由索引數字大的開始反向列印。

將2位元的Gray Code當作平面座標來看,可以構成一個四邊形,您可以發現從任一頂點出發,繞四邊形周長繞一圈,所經過的頂點座標就是一組Gray Code,所以您可以得到四組Gray Code。

同樣的將3位元的Gray Code當作平面座標來看的話,可以構成一個正立方體,如果您可以從任一頂點出發,將所有的邊長走過,並不重複經過頂點的話,所經過的頂點座標順序之組合也就是一組Gray Code。 

實作C    Java    Python    Scala
  •  C
  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. #define MAXBIT 20
  4. #define TRUE 1
  5. #define CHANGE_BIT(x) x = ((x) == '0' ? '1' : '0')
  6. #define NEXT(x) x = (1 - (x))

  7. int main(void) {
  8.     char digit[MAXBIT];
  9.     int bits;
  10.     printf("輸入位元數:");
  11.     scanf("%d", &bits);

  12.     int i;
  13.     for(i = 0; i < bits; i++) {
  14.         digit[i] = '0';
  15.         printf("0");
  16.     }

  17.     printf("\n");

  18.     int odd = TRUE;

  19.     while(1) {
  20.         if(odd)
  21.             CHANGE_BIT(digit[0]);
  22.         else {
  23.             // 計算第一個1的位置
  24.             int j;
  25.             for(j = 0; j < bits && digit[j] == '0'; j++) ;
  26.             if(j == bits - 1) // 最後一個Gray Code
  27.                  break;
  28.             CHANGE_BIT(digit[j + 1]);
  29.         }
  30.         int j;
  31.         for(j = bits - 1; j >= 0; j--)
  32.             printf("%c", digit[j]);

  33.         printf("\n");
  34.         NEXT(odd);
  35.     }
  36.     return 0;
  37. }

  •  Java
  1. import java.util.*;
  2. public class GrayCode implements Iterable<char[]>, Iterator<char[]> {
  3.     private char[] digit;
  4.     private boolean first = true;
  5.     private boolean odd = true;
  6.     
  7.     public GrayCode(int length) {
  8.         digit = new char[length];
  9.         for(int i = 0; i < length; i++) {
  10.             digit[i] = '0';
  11.         }
  12.     }
  13.     
  14.     public Iterator<char[]> iterator() {
  15.         return this;
  16.     }
  17.     
  18.     public boolean hasNext() {
  19.         return count() != digit.length - 1;
  20.     }
  21.     
  22.     public char[] next() {
  23.         if(first)
  24.             first = false;
  25.         else {
  26.             if(odd) charge(0);
  27.             else if(hasNext()) charge(count() + 1); // 最後一個 Gray Code
  28.             odd = ! odd;
  29.         }
  30.         return reverse();
  31.     }
  32.     
  33.     public void remove() {
  34.         throw new RuntimeException("Unsupported operation");
  35.     }
  36.     
  37.     private int count() {
  38.         int count;
  39.         // 計算第一個1的位置
  40.         for(count = 0;
  41.             (count < digit.length) && (digit[count] == '0');
  42.              count++) ;
  43.         return count;
  44.     }
  45.     
  46.     private void charge(int i) {
  47.         digit[i] = ((digit[i] == '0') ? '1' : '0');
  48.     }
  49.     
  50.     private char[] reverse() {
  51.         char[] tmp = new char[digit.length];
  52.         int i = digit.length - 1;
  53.         for(char c : digit) {
  54.             tmp[i] = c;
  55.             i--;
  56.         }
  57.         return tmp;
  58.     }
  59.     
  60.     public static void main(String[] args) {
  61.         for(char[] digit : new GrayCode(4)) {
  62.             for(char c: digit)
  63.                 System.out.print(c);
  64.             System.out.println();
  65.         }
  66.     }
  67. }
  • Python
TypeError: instance has no next() method
  1. class GrayCode:
  2.     def __init__(self, length):
  3.         self.__digit = ['0'] * length
  4.         self.__first = True
  5.         self.__odd = True
  6.         
  7.     def __iter__(self):
  8.         return self
  9.         
  10.     def __next__(self):
  11.         if not self.__hasNext():
  12.             raise StopIteration

  13.         if self.__first:
  14.             self.__first = False
  15.         else:
  16.             if self.__odd:
  17.                 self.__charge(0)
  18.             else:
  19.                 if self.__hasNext():
  20.                     self.__charge(self.__count() + 1)
  21.             self.__odd = not self.__odd
  22.         return self.__reverse()

  23.     def __hasNext(self):
  24.         return self.__count() != len(self.__digit) - 1

  25.     def __charge(self, i):
  26.         if self.__digit[i] == '0':
  27.             self.__digit[i] = '1'
  28.         else:
  29.             self.__digit[i] = '0'

  30.     def __count(self):
  31.         count = 0
  32.         while(count < len(self.__digit) and self.__digit[count] == '0'):
  33.             count += 1
  34.         return count

  35.     def __reverse(self):
  36.         tmp = []
  37.         for i in range(len(self.__digit) - 1, -1, -1):
  38.             tmp.append(self.__digit[i])
  39.         return tmp
  40.         
  41. for digit in GrayCode(4):
  42.     for i in range(0, len(digit)):
  43.         print(digit[i],)
  44.     print()
  • Scala
  1. class GrayCode(length: Int) extends Iterator[Array[Char]] {
  2.     private var first = true
  3.     private var odd = true
  4.     private val digit = (for(i <- 0 until length) yield '0').toArray
  5.     
  6.     private def count() = {
  7.         var c = 0
  8.         while(c < digit.length && digit(c) == '0') {
  9.             c += 1
  10.         }
  11.         c
  12.     }
  13.     
  14.     private def charge(i: Int) {
  15.         digit(i) = if(digit(i) == '0') '1' else '0'
  16.     }
  17.     
  18.     def hasNext() = {
  19.         count != digit.length - 1
  20.     }
  21.     
  22.     def next() = {
  23.         if(first) {
  24.             first = false
  25.         }
  26.         else {
  27.             if(odd) charge(0)
  28.             else if(hasNext()) charge(count + 1)
  29.             odd = !odd
  30.         }
  31.         digit.reverse
  32.     }
  33. }

  34. for(digit <- new GrayCode(4)) {
  35.     digit.foreach(print)
  36.     println()
  37. }
阅读(1371) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~