Finding next bigger number with same number of set bits

邮差的信 提交于 2020-02-02 07:41:27

问题


I'm working on a problem where I'm given a number n, I have to find the next larger element with same number of set bits. While searching on Internet, I found an interesting piece of code which does this in few lines of code (BIT MAGIC) here:

unsigned nexthi_same_count_ones(unsigned a) {
  /* works for any word length */
  unsigned c = (a & -a);
  unsigned r = a+c;
  return (((r ^ a) >> 2) / c) | r);
}

But I want to understand the underlying logic about the algorithm that it will work always. All the boundary cases will be handled properly.

Can someone please explain the logic in simple steps.

Thanks


回答1:


In the next higher number, the leftmost 1 of the rightmost run of 1s exchanges place with the 0 to its left, while the remaining 1s move to the far right.

  • The code isolates lowest 1,
  • adds it to a (making carries ripple through to the next higher 0, inverting all those bits)
  • The ex-or gets the least significant run of ones, extended one position to the left.
  • Shifting it right two positions takes its left boundary one position right of the original one (leaving place for that one 0 from the high position),
  • dividing by the lowest 1 makes room for as many 0-bits more as there were on the right end of a.



回答2:


Let say we have a bit pattern such as

111100111 - representing 487 in decimal

to generate the next highest integer whilst preserving the number of 0's and 1's as in the input we need to find the first 0 bit from the right of the input that is followed by 1, and we need to toggle this bit to a 1. We then need to reduce the number of 1's on the right of this flip point by 1 to compensate for the bit we switched from a 0 to 1.

our new bit pattern will become 111101011 - 491 in decimal (we have preserved the no of bits set and not set as per the input)

int getNextNumber(int input)
{
    int flipPosition=0;
    int trailingZeros=0;
    int trailingOnes=0;
    int copy = input;

    //count trailing zeros
    while(copy != 0 && (copy&1) == 0 )
    {
        ++trailingZeros;

        //test next bit
        copy = copy >> 1;
    }

    //count trailing ones
    while(copy != 0 && (copy&1) == 1 )
    {
        ++trailingOnes;

        //test next bit
        copy = copy >> 1;
    }

    //if we have no 1's we cannot form another patter with the same number of 1's
    //which will increment the input, or if we have leading consecutive
    //zero's followed by consecutive 1's up to the maximum bit size of a int
    //we cannot increase the input whilst preserving the no of 0's and
    //1's in the original bit pattern
    if(trailingZeros + trailingOnes  == 0 || trailingZeros + trailingOnes == 31)
        return -1;

    //flip first 0 followed by a 1 found from the right of the bit pattern
    flipPosition = trailingZeros + trailingOnes+1;
    input |= 1<<(trailingZeros+trailingOnes);

    //clear fields to the right of the flip position
    int mask = ~0 << (trailingZeros+trailingOnes);
    input &= mask;

    //insert a bit pattern to the right of the flop position that will contain
    //one less 1 to compensate for the bit we switched from 0 to 1
    int insert = flipPosition-1;
    input |= insert;

    return input;
}


来源:https://stackoverflow.com/questions/26594951/finding-next-bigger-number-with-same-number-of-set-bits

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!