說明
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。
實作
#include <stdio.h>
#include <stdlib.h>
#define MAXBIT 20
#define TRUE 1
#define CHANGE_BIT(x) x = ((x) == '0' ? '1' : '0')
#define NEXT(x) x = (1 - (x))
int main(void) {
char digit[MAXBIT];
int i, bits, odd;
printf("輸入位元數:");
scanf("%d", &bits);
for(i = 0; i < bits; i++) {
digit[i] = '0';
printf("0");
}
printf("\n");
odd = TRUE;
while(1) {
if(odd)
CHANGE_BIT(digit[0]);
else {
// 計算第一個1的位置
for(i = 0; i < bits && digit[i] == '0'; i++) ;
if(i == bits - 1) // 最後一個Gray Code
break;
CHANGE_BIT(digit[i+1]);
}
for(i = bits - 1; i >= 0; i--)
printf("%c", digit[i]);
printf("\n");
NEXT(odd);
}
return 0;
}
public class GrayCode {
private char[] digit;
private boolean first;
private boolean odd;
private int count;
public GrayCode(int length) {
digit = new char[length];
for(int i = 0; i < length; i++) {
digit[i] = '0';
}
first = true;
odd = true;
}
public boolean hasNext() {
// 計算第一個1的位置
for(count = 0;
(count < digit.length) && (digit[count] == '0');
count++) ;
return count != digit.length - 1;
}
public char[] next() {
if(first) {
first = false;
return digit;
}
if(odd)
chargeBit(digit, 0);
else {
// 最後一個Gray Code 嗎
if(hasNext())
chargeBit(digit, count+1);
}
odd = ((odd == true) ? false : true);
return digit;
}
private void chargeBit(char[] digit, int i) {
digit[i] = ((digit[i] == '0') ? '1' : '0');
}
public static void main(String[] args) {
GrayCode code = new GrayCode(4);
while(code.hasNext()) {
char[] digit = code.next();
for(int i = digit.length - 1; i >= 0; i--)
System.out.print(digit[i]);
System.out.println();
}
}
}