• 位操作-给定一个二进制数,在“1”的个数保持不变的前提下,获取最近的略大数


    首先考虑后一个数是什么样子的,看下边这个例子:

    1 1 0 1 0 0 0 0 0 0
    9 8 7 6 5 4 3 2 1 0

    如上表所示,如果我们想在保持1的个数不变的前提下,得到略大的数:

    我们会发现,

    1).给定一个数n,和两个位置i和j;假设将位i从0变到1,位j从1变到0,如果i再j的左侧,则变大

    2).有一个0翻转至1,则必须有一个1翻转至0;

    3).如果想让数变大,但是不至于太大,那么我们需要翻转最右侧的0,但是其右侧必须还要有1,换句话说,翻转最右侧但是不是拖尾的0,就上述表格中的数据而言,我们需要反转的是7所在的位置的0;

    接下来是详细步骤:

    步骤一:

    翻转最右侧,但是非拖尾的0

    首先根据获取到的P的位置(带翻转的0的位置),将其变为1;

    步骤二:

    将P右侧的所有位变为0

    具体做法:

    a=a<<p;//除去P为1,其余位均为0;

    b=a-1;//将P位置之后的全部都设置成1;

    mask=~b;//将P之前的所有位置均设置为1,其余变成0;

    n&=mask;

    上述等效为:

    n&=~((1<<p)-1);

    步骤三:

    进行回填 将检测到的P位置之后的1的个数c1进行回填c1-1个1;

    具体做法是:

    a=1<<(c1-1);//将位c1-1设置成1,其余设置成0;

    b=a-1;

    n|=b;

    简写为:

    n|=(1<<(c1-1)-1);

    整体的代码实现为:

     1 int getNext(int n){
     2     int c=n;
     3     int c0=0;
     4     int c1=0;
     5     while(((c&1)==0)&&(c!=0)){
     6         c0++;//获取位尾0的个数
     7         c>>=1;
     8     }
     9     while((c&1)==1){
    10         c1++;//获取位尾1的个数
    11         c>>=1;
    12     }
    13     if(c0+c1==31||c0+c1==0){
    14         return -1;
    15     }
    16     int p=c0+c1;
    17     n|=(1<<p);
    18     n&=~((1<<p)-1);
    19     n|=(1<<(c1-1))-1;
    20     return n;    
    21    }
  • 相关阅读:
    GNU make manual 翻译(四十一)
    GNU make manual 翻译(三十五)
    GNU make manual 翻译(三十三)
    GNU make manual 翻译(三十八)
    GNU make manual 翻译(四十二)
    GNU make manual 翻译(三十四)
    艾瑞咨询:即时通讯面临多种安全威胁 狼人:
    世界头号黑客称奥巴马超级加密黑莓手机可被攻破 狼人:
    微软悬赏25万美元捉拿Conficker蠕虫作者 狼人:
    信息周刊:随意设置电脑密码存在安全隐患 狼人:
  • 原文地址:https://www.cnblogs.com/lujun1949/p/5717223.html
Copyright © 2020-2023  润新知