【问题标题】:How can I get the position of bits我怎样才能得到位的位置
【发布时间】:2015-08-06 10:21:35
【问题描述】:

我有一个十进制数,我需要将其转换为二进制,然后在该二进制表示中找到一个的位置。

输入是5,二进制是101,输出应该是

1
3

下面是我的代码,它只提供2 的输出,而不是我想以二进制表示形式提供一个人的位置。我怎样才能获得从 1 开始的设置位的位置?

public static void main(String args[]) throws Exception {
    System.out.println(countBits(5));
}

private static int countBits(int number) {
    boolean flag = false;

    if (number < 0) {
        flag = true;
        number = ~number;
    }
    int result = 0;
    while (number != 0) {
        result += number & 1;
        number = number >> 1;
    }
    return flag ? (32 - result) : result;
}

【问题讨论】:

  • 注意:检查number 是否为负的代码不是必需的。如果您使用&gt;&gt;&gt; 运算符而不是&gt;&gt;,则零将在左侧移入(而不是将1 移入负数),因此number 最终将是0 而result 将始终是正确计数。
  • 如果您尝试返回 1 位的位置,则需要使用 &gt;&gt;&gt;。如果你尝试专门处理负数,你的工作会复杂很多。

标签: java algorithm binary bit-manipulation


【解决方案1】:

您的想法是让countBits 返回结果,而不是在方法中放置System.out.println,这通常是最好的方法。如果您希望它返回位位置列表,则类似的方法是让您的方法返回一个数组或某种列表,例如:

private static List<Integer> bitPositions(int number) {

正如我在我的 cmets 中提到的,如果您使用 &gt;&gt;&gt; 并摆脱用于检查负数的特殊代码,您的生活会变得更轻松。这样做,并调整你已经拥有的代码,会给你类似的东西

private static List<Integer> bitPositions(int number) {
    List<Integer> positions = new ArrayList<>();
    int position = 1;
    while (number != 0) {
        if (number & 1 != 0) {
            positions.add(position);
        }
        position++;
        number = number >>> 1;
    }
    return positions;
}

现在调用者可以做它想做的打印位置了。如果你在上面使用System.out.println,输出将是[1, 3]。如果您希望每个输出在单独的行上:

for (Integer position : bitPositions(5)) {
     System.out.println(position);
}

在任何情况下,关于如何打印位置(或您想对它们做什么)的决定与计算位置的逻辑是分开的,因为该方法返回整个列表并且没有它的拥有println

(顺便说一下,正如亚历克斯所说,最常见的是将低位位视为“位 0”而不是“位 1”,尽管我看过硬件手册称低位位“位 31”和高位位“位 0”。称其为“位 0”的好处是位置 N 的 1 位代表值 2N,使事情变得简单。我的代码示例按照您在问题中的要求将其称为“位 1”;但如果您想将其更改为 0,只需更改 position 的初始值。)

【讨论】:

  • 感谢您的帮助。你能解释一下为什么我们想将任何十进制数转换为二进制时使用按位运算符吗?这有什么合乎逻辑的理由吗?实际上,我很困惑为什么按位运算符会出现。以及为什么我们在这里特别使用&gt;&gt;&gt;
  • 数字的二进制表示位。您要求以二进制表示形式获取 1 的位置;这与询问 1 位在哪里完全相同。这就是我们使用位运算符的原因。此外,该方法不是将十进制数“转换”为二进制数。 number 已经以二进制形式存储在计算机中;十进制到二进制的转换发生在很久以前,当时编译器在您的 main 方法中看到数字 5 并将其转换为二进制。
  • 至于&gt;&gt;&gt;,我想你明白为什么负数是个问题,这就是你专门处理它们的原因。我猜你不会?当一个数字为负数时,最左边的位为 1。当最左边的位为 1 时,&gt;&gt; 运算符将在其移位时在左边插入另一个 1。如果您正在计算 1 的数量或寻找 1 位,那么这个额外的 1 会让您感到困惑。 &gt;&gt;&gt; 不这样做。它总是在左边插入一个 0。
  • 7 号逻辑失败
  • @BleedCode 请解释:(1)你在谈论什么逻辑[这是用bitPositions方法,还是别的什么?],(2)你期望什么输出,什么做了你明白了。
【解决方案2】:

二进制表示:你的数字,就像现代(非量子)计算机上的任何东西一样,已经是内存中的二进制表示,作为给定大小的位序列。

位操作 您可以使用位移位、位掩码、'AND'、'OR'、'NOT' 和 'XOR'bitwise operations 来操作它们并在单个位的级别上获取有关它们的信息。

你的例子

对于您的示例编号 5 (101),您提到您的预期输出将是 1, 3。这有点奇怪,因为一般来说一个会从 0 开始计数,例如对于 5 作为byte(8 位数字):

     76543210  <-- bit index
5    00000101

所以我希望输出为 02,因为这些位索引处的位已设置 (1)。

您的示例实现显示了函数的代码

private static int countBits(int number)

它的名称和签名暗示任何实现的以下行为:

  • 它采用整数值number 并返回单个输出值。
  • 旨在计算输入number中设置了多少位。

即它与您描述的预期功能完全不匹配。

解决方案

您可以结合使用“位移”(&gt;&gt;) 和AND (&amp;) 操作来解决您的问题。

int index = 0; // start at bit index 0

while (inputNumber != 0) { // If the number is 0, no bits are set

    // check if the bit at the current index 0 is set
    if ((inputNumber & 1) == 1)         
        System.out.println(index);  // it is, print its bit index.

    // advance to the next bit position to check
    inputNumber = inputNumber >> 1; // shift all bits one position to the right
    index = index + 1;              // so we are now looking at the next index.
}

如果我们为您的示例输入数字“5”运行此命令,我们将看到以下内容:

iteration   input  76543210     index    result
1           5      00000101     0        1 => bit set.
2           2      00000010     1        0 => bit not set.
3           1      00000001     2        1 => bit set.
4           0      00000000     3        Stop, because inputNumber is 0    

【讨论】:

    【解决方案3】:

    您需要跟踪您所处的位置,当number &amp; 1 的结果为 1 时,打印出该位置。它看起来像:

    ...
    int position = 1;
    while (number != 0) {
        if((number & 1)==1)
            System.out.println(position);
        result += number & 1;
        position += 1;
        number = number >> 1;
    }
    ...
    

    【讨论】:

      【解决方案4】:

      有一种方法可以使用按位运算来解决您的问题。
      Integer.toBinaryString(int number) 将整数转换为由零和一组成的字符串。这在您的情况下很方便,因为您可以改为:

      public static void main(String args[]) throws Exception {
          countBits(5);
      }
      
      public static void countBits(int x) {
        String binaryStr = Integer.toBinaryString(x);
        int length = binaryStr.length();
        for(int i=0; i<length; i++) {
          if(binaryStr.charAt(i)=='1')
            System.out.println(length-1);
        }
      }
      

      它绕过了您可能尝试做的事情(学习 Java 中的按位运算),但在我看来使代码看起来更清晰。

      【讨论】:

        【解决方案5】:

        Integer.lowestOneBit 和 Integer.numberOfTrailingZeros 的组合立即给出最低 1-Bit 的位置,如果数字为 0,则返回 32。

        因此,下面的代码按升序返回数字number的1-Bits的位置:

        public static List<Integer> BitOccurencesAscending(int number)
        {
            LinkedList<Integer> out = new LinkedList<>();
            int x = number;
            while(number>0)
            {
                x = Integer.lowestOneBit(number);
                number -= x;
                x = Integer.numberOfTrailingZeros(x);
                out.add(x);
            }
            return out;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-11-08
          • 1970-01-01
          • 2023-01-05
          • 1970-01-01
          • 2018-03-16
          相关资源
          最近更新 更多