C语言名题精选百则:所有子集,字典子集,Gray子集

来源:互联网 发布:淘宝网客户关系管理 编辑:程序博客网 时间:2024/06/05 00:16

C语言名题百则 3.1 列出所有子集 (direct.c)

分析:每一个元素只有两种可能,在子集中和不在子集中。

#include <iostream>#include <cstdio>using namespace std;int p[20],top;int main(){    int n;    while(cin>>n){        for(int i=0;i<(1<<n);i++){            top=0;            for(int j=0;j<n;j++){                if(i&(1<<j)) p[top++]=j+1;            }            for(int j=0;j<top;j++){                printf("%3d",p[j]);            }            puts("");        }    }    return 0;}

C语言名题百则 3.2 列出所有子集——字典序列 (lexical.c)

分析:抓住字典序升序的规律。

#include <iostream>#include <cstdio>using namespace std;int p[25],n;void show(int top){    for(int i=1;i<=top;i++) printf("%3d",p[i]);    puts("");}int main(){    while(cin>>n){        printf("\n");        int top=0;        for(int i=1;i<(1<<n);i++){            if(p[top]<n){                p[top+1]=p[top]+1;                top++;                show(top);            }            else if(p[top]==n){                p[top-1]++;                top--;                show(top);            }        }    }    return 0;}

C语言名题百则 3.3 产生Gray码 (Graycode.c)


格雷码的特点:虽然自然二进制码可以直接由数/模转换器转换成模拟信号,但在某些情况,例如从十进制的3转换为4时二进制码的每一位都要变,能使数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点,它在相邻位间转换时,只有一位产生变化。
典型格雷码是一种具有反射特性和循环特性的单步自补码,它的循环、单步特性消除了随机取数时出现重大误差的可能,它的反射、自补特性使得求反非常方便。
二进制转成格雷码是编码较为方便的方式,参考博客:
http://blog.csdn.net/thearcticocean/article/details/48345811

现在又看这种生成格雷码的方法,不禁想问,它是怎样被发现的?

对照自然二进制数和格雷码可以发现,不看自然二进制和格雷码的最高位,它们剩下的部分进行异或运算所得到的结果刚好是二进制前n-1位。例如12对应的1100~1010,100^010=110。那么反推,十进制数字对应的格雷码的最高位和二进制最高位一样,剩下的部分就该是二进制后n-1位和前n-1位进行异或运算得到。即是二进制转成格雷码的方法。【异或运算的特点: if c=a^b  so  a=c^b  and b=a^c 】
异或运算的特点让我想起了那个加密解密的例子:
package pg;public class Main { public static void main(String[] args) {      char [] f={'皆','大','欢','喜'};      char sec='*';      for(int i=0;i<f.length;i++){       f[i]=(char)(f[i]^sec);      }      for(int i=0;i<f.length;i++){       System.out.printf("%c ", f[i]);      }      System.out.println("");      for(int i=0;i<f.length;i++){       f[i]=(char)(f[i]^sec);      }      for(int i=0;i<f.length;i++){       System.out.printf("%c ", f[i]);      } }}
output:
皬 复 欈 営
皆 大 欢 喜

扯远了,回到本问题上来:可以用二进制生成格雷码,然后输出格雷码对应的子集。
#include <cstdio>#include <iostream>using namespace std;int p[25],top;void show(int x){ top=0; while(x){  p[top++]=x%2;  x>>=1; } for(int i=top-1;i>=0;i--) cout<<p[i]; cout<<endl;}int main(){     int n,t;     while(cin>>n){      for(int i=0;i<(1<<n);i++){       t=i^(i>>1);       //show(t);       top=0;       for(int j=0;j<n;j++){        if(t&(1<<j)){         p[top++]=j+1;        }       }       for(int j=0;j<top;j++){        printf("%3d",p[j]);       }         puts("");      }     }     return 0;}


0 0