递归生成二进制反射格雷码:
需求:
我们使用递归的方式来生成二进制的反射格雷码。
什么是格雷码?
典型的二进制格雷码(Binary Gray Code)简称格雷码,因1953年公开的弗兰克·格雷(Frank Gray,18870913-19690523)专利“Pulse Code Communication”而得名,当初是为了通信,现在则常用于模拟-数字转换和位置-数字转换中。法国电讯工程师波特(Jean-Maurice-Émile Baudot,18450911-19030328)在1880年曾用过的波特码相当于它的一种变形。1941年George Stibitz设计的一种8元二进制机械计数器正好符合格雷码计数器的计数规律。
格雷码(Gray code)曾用过Grey Code、葛莱码、葛兰码、格莱码、戈莱码、循环码、二进制反射码、最小差错码等名字,它们有的是错误的,有的易与其它名称混淆,建议不再使用它们。
粘自百度百科(手动狗头)
总之,格雷码应用在各个场合,我们要做的就是生成它,它的特点就是相邻的两个数之间,只能有一位是不同的,这个需要我们进行一点儿点儿小小的脑筋。
基于下面的伪代码:
- 看到这伪代码我都傻了,因为一点儿也不好看,方法连个返回值都不给,还要自己设计,太操蛋了。
因为我用的是Java,所以对于这个问题设计的返回值是List< String >。具体代码如下
/**
* @program:算法库
* @description:二进制反射格雷码的生成类
*/
public class BinaryReflectedGrayCode {
public List<String> BRGC(int n){
List<String> L1;
if(n==1){
L1 = new ArrayList<String>();
L1.add("0");
L1.add("1");
return L1;
}else{
L1 = new ArrayList<String>(BRGC(n-1));
List<String> L2 = new ArrayList<>();
int len = L1.size();
for (int i = 0; i < len; i++) {
L2.add("1"+L1.get(len-i-1));
}
for(int i=0;i<len;i++){
String s = L1.get(i);
s = "0"+s;
L1.remove(i);
L1.add(i,s);
}
int len2 = L2.size();
for (int i = 0; i < len2; i++) {
L1.add(L2.get(i));
}
return L1;
}
}
}
具体的步骤是:
- 因为是一个递归算法,所以我们要先规定递归的终点,也就是我们的初始条件,当n==1的时候,我们返回0和1两个结果
- 后面就根据伪代码给的提示,一步一步操作即可。
这里在反转这个List表单的时候,可以使用Collections.reverse(参数),进行操作,但是这个方法的返回值就void,所以最后还是返回到我们的参数中去。
而在后续的步骤中,我们传进去的操作还有用,所以我们不可以将其做一个替换,那样操作的开销太大了。
public static void reverse(List<?> list) {
int size = list.size();
if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j);
} else {
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size);
for (int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
}
}
}
- 这里附上Java源码中对于这个方法的实现,还是对其底层进行了交换,所以我们没办法将其这样使用。
故这里实现交换的是使用的循环,直接将其循环遍历之后,保存在我们的L2的集合中,再对L1其中的元素进行更新,这里的这个更新,应该是没有库函数可以使用,于是我们按照更新的常规操作来写,先移除再赋值,这一个操作之后,就完成了我们需要做的事情
最后就是将我们的L1和L2进行合并即可,这里就遍历L2,将L2添加到L1当中。
可能,大概,也许是比较简单的一种方案了。