代码之家  ›  专栏  ›  技术社区  ›  cppBeginner

恒定时间级联计算可能吗?

  •  1
  • cppBeginner  · 技术社区  · 7 年前

    这是一个关于计算机技术局限性的教育目的问题。
    我的想法是,下面的程序是不可能创建的。

    假设我必须开发一个累积的统计数据结构。
    以下是规格:-

    • 用户可以 update(i,value) data[i] 在里面 O(1)
    • 用户可以查询 getAccu(i) data[0]+data[1]+...+data[i] 在里面 O(1) (平均情况)。
    • 我不能以任何方式假设这两个函数的调用顺序。

    这是我的密码( coliru demo ).
    但不符合上述要求:-

    #include <iostream>
    #include <vector>
    int data[5]={0,1,2,3,4};
    int accu[5]={0,1,3,6,10};
    /** assume that index always >=1 */
    void update(int index,int value){  //O(n) i.e. O(array length)
        data[index]=value;
        for(int n=index-1;n<5;n++){
            accu[n]=accu[n-1]+data[n];
        }
    }
    int getAccu(int index){            //O(1)
        return accu[index];
    }
    int main(){
        update(2,12);
        //note: data = 0,1,12,3,4
        //      accu = 0,1,13,16,20
        std::cout<<getAccu(3)<<std::endl; //16
        //update() ... getAccu()... update() ...
    }
    

    不受内存大小和数据结构类型的限制,
    这两种功能都可以实现吗 update(index,value) getAccu(index) ?

    抱歉,这个话题太晦涩了。我找不到更合适的了。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Marc Glisse    7 年前

    在固定时间内做每件事似乎都很乐观。如果你不介意的话 O(log n) 由于复杂性,您可以维护一个平衡的二叉树,该二叉树在每个节点中存储根在该节点上的子树的总数。

    当您更新一个值时,只需要更新从根到该元素的路径中的log n小计。

    计算累加器只需从根中定位右节点,并在每次向右移动时添加左小计。

    您可以在固定时间内将它们添加到待更新项目的列表中,而不是急切地进行更新,然后当您得到一个查询并且该列表不为空时,您可以在 log n 或者,如果有许多更新,则仅更新中的值 O(1) O(n) ,但只有当您在两个查询之间获得许多更新时,才值得这么麻烦。