c++ - `(i & (i + 1)) - 1` 是什么意思? (在芬威克树中)

标签 c++ algorithm data-structures bit-manipulation bitwise-operators

在学习 Fenwick Trees 时,我发现了这个实现:
来源:https://algorithmist.com/wiki/Fenwick_tree

class Fenwick_Tree_Sum
{
    vector<int> tree;
    Fenwick_Tree_Sum(const vector<int>& Arg)//Arg is our array on which we are going to work
    {
        tree.resize(Arg.size());
        
        for(int i = 0 ; i<tree.size(); i++)
            increase(i, Arg[i]);
        
    }

    // Increases value of i-th element by ''delta''.
    void increase(int i, int delta)
    {
        for (; i < (int)tree.size(); i |= i + 1)
            tree[i] += delta;
    }

    // Returns sum of elements with indexes left..right, inclusive; (zero-based);
    int getsum(int left, int right)
    {
        return sum(right) - sum(left-1); //when left equals 0 the function hopefully returns 0
    }

    int sum(int ind)
    {
        int sum = 0;
        while (ind>=0)
        {
            sum += tree[ind];
            ind &= ind + 1;
            ind--;
        }
        return sum;
    }
};
我可以看到 i |= i + 1ind &= ind + 1; ind--在代码中。
我知道i |= i + 1只是设置下一个未设置的位。
但是,(i & (i + 1)) - 1 是什么意思?其实呢?
这里有些例子:
-------------------------------------
         i        | (i & (i + 1)) - 1
-------------------------------------
  0 - 0000000000  |  -1 - 1111111111
  1 - 0000000001  |  -1 - 1111111111
  2 - 0000000010  |   1 - 0000000001
  3 - 0000000011  |  -1 - 1111111111
  4 - 0000000100  |   3 - 0000000011
  5 - 0000000101  |   3 - 0000000011
  6 - 0000000110  |   5 - 0000000101
  7 - 0000000111  |  -1 - 1111111111
  8 - 0000001000  |   7 - 0000000111
  9 - 0000001001  |   7 - 0000000111
 10 - 0000001010  |   9 - 0000001001
 11 - 0000001011  |   7 - 0000000111
 12 - 0000001100  |  11 - 0000001011
 13 - 0000001101  |  11 - 0000001011
 14 - 0000001110  |  13 - 0000001101
 15 - 0000001111  |  -1 - 1111111111
 16 - 0000010000  |  15 - 0000001111
 17 - 0000010001  |  15 - 0000001111
 18 - 0000010010  |  17 - 0000010001
 19 - 0000010011  |  15 - 0000001111
 20 - 0000010100  |  19 - 0000010011
 21 - 0000010101  |  19 - 0000010011
 22 - 0000010110  |  21 - 0000010101
 23 - 0000010111  |  15 - 0000001111
 24 - 0000011000  |  23 - 0000010111
 25 - 0000011001  |  23 - 0000010111
 26 - 0000011010  |  25 - 0000011001
 27 - 0000011011  |  23 - 0000010111
 28 - 0000011100  |  27 - 0000011011
 29 - 0000011101  |  27 - 0000011011
 30 - 0000011110  |  29 - 0000011101

最佳答案

如果 i 的位模式就像 ...0111 , i+1 的位模式将是 ...1000 .因此,i & (i+1)意味着 i - (2^{number of trailing ones} - 1)并转换所有尾随 1 s 为零。例如,如果 i是偶数,i & (i+1)将等于 i .另一方面,-1意味着,将所有尾随零转换为 1 (包括上一步的所有尾随 1 为零)并转换连续的 1 s 为零。
通过做 -1下一步,i & (i+1)将减少 i2^{number of trailing 1's} i 的前一个值.
原因是什么?它有助于表明找到累积和的时间复杂度将为 O(log n)在最坏的情况下。
要找到这种计算背后的原因,您需要关注每个节点 i将负责计算索引 i(i - (1 << r)) + 1 .而“r 表示索引 i 中设置的最后一位。求索引i对应的总和,我们需要对来自 0 的所有相关值求和至 i .请注意,由于指定的属性,我们不需要对所有索引求和。因此,我们需要对指数 i 求和, i - (1 << r) , ... 等等。

关于c++ - `(i & (i + 1)) - 1` 是什么意思? (在芬威克树中),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64335228/

相关文章:

data-structures - 如何识别 Prolog 术语的浪费表示

math - 树的高度的定义是什么?

C 程序将一棵二叉搜索树复制到另一棵

c++ - 将 C++ 缓冲区公开为 Python 3 字节

c++ - 使用 shared_ptr 列表撤消/重做

string - 给定一个字符串 A 和一组字符串 S。需要找到一个最佳方法来找到 A 的前缀,该前缀不是 s 中任何字符串的前缀

c - 使用 mergesort 对链表进行排序

c++ - 使所有类方法调用同一个函数

c++ - 如果匹配特定类,则从基类对象的 vector 中删除对象

algorithm - 如何找到有向图的最大无环子图的2-近似解?