快速获得多个min(max)元素C ++的数据结构

时间:2016-08-04 02:19:21

标签: c++ boost stl

我试图将一些元素存储到容器中,并希望根据某些条件有效地获取它。

简单来说,假设:

  1. 记录如下:(身份证,年龄,工资)
  2. 对于每个插入并删除它返回最小年龄的工资总和
  3. 喜欢以下

           ID  Age Wage(k)
    insert 1   23  95   // returns 23,95
    insert 2   21  75   // returns 21,75
    insert 3   27  85   // returns 21,75
    insert 4   21  65   // returns 21,140
    delete ID=2         // returns 21,65
    

    我能想到几种解决方案:

    1。矢量(boost :: circular_buffer?)

    e.g. [(23,1,95), (21,2,75), (27,3,85), (21,4,65)]
    Insert: O(1)
    Delete (can use a bit to mark deleted) O(n)
    GetMinSum: O(n)
    

    2。排序矢量

    e.g. [(21,2,75), (21,4,65), (23,1,95), (27,3,85)]
    Insert: O(n)
    Delete (can use a bit to mark deleted) O(n)
    GetMinSum: O(1)
    

    3。地图(RB树)

    std::map<age, vector<record>>
    [(21)->[(2,75),(1,65)], (23)->[(1,95)], (27)->[(3,85)]]
    GetMinSum: O(1)
    Insert: O(logN)
    Delete: O(n)
    

    有什么建议吗?

2 个答案:

答案 0 :(得分:1)

应该可以使用O(1)std::map中实施步骤2的计算部分:

std::map<int, int> sum_of_wages_by_age;
  1. 地图的关键是Age

  2. 地图的价值是给定年龄的所有工资的总和。

  3. 鉴于迭代std::map的键必须以严格的弱顺序迭代,最低的Age将始终是地图中的第一个键。因此,最低年龄的工资总和将只是:

    auto p=sum_of_wages_by_age.begin();
    
    return p == sum_of_wages_by_age.end() ? 0: // Edge case, empty map
              p->second;
    

    我的回答只关注跟踪此地图的内容,以便以这种方式快速返回最低年龄的工资总和。这与您自己存储<Id, Wage, Age>记录的方式完全不同。这是一个单独的问题。由您来决定是否要将它们存储在矢量或其他内容中。无论您如何存储它们,sum_of_wages_by_age的唯一目的是能够快速返回正确的数字。手头的主题只关心能够以这种方式有效地返回最低年龄的工资总和。

    为了使这种方法起作用,上述地图需要在插入和删除记录时保持更新。这可以按如下方式完成。

    添加新的<ID, Age, Wage>记录。

    除了存储此记录外,还需要将工资添加到地图中:

    sum_of_wages_by_age[age] += wage;
    

    删除现有的<ID, Age, Wage>记录

    这个更令人兴奋。

    auto p=sum_of_wages_by_age.find(age);
    
    if ( (p->second -= wage) == 0)
        sum_of_wages_by_age.erase(p);
    

    你想要整洁。删除给定年龄的最后一条记录后,您现在要从此地图中完全删除该年龄段的条目。如果你不关心这个,你可以简单地做

    sum_of_wages_by_age[age] -= wage;
    

    请注意,由于之前添加的记录必须已添加,因此您可以保证地图上会显示该年龄的条目。当然,只有wage不能为零或为负数时,这才有效。但这是一个安全的假设。如你所知,有一项法律规定最低工资必须是什么。

    买者

    以上示例使用int s来获取工资。如果您需要使用floatdouble s,则在重复添加和减少期间会出现舍入误差。如果这是一个问题,研究如何正确处理舍入错误将是您的家庭作业。

答案 1 :(得分:1)

确实没有符合您要求的标准容器,但不应该很难编写自己的适配器类。

该类可以包含实际数据的向量,指针的向量或具有当前最小年龄的结构的引用,当前最小年龄本身作为堆栈,以及包含age-&gt; sum映射的映射。 / p>

  • 添加数据:

    添加新结构时,比较当前最小年龄(年龄堆栈的顶部),如果它大于当前最小值,则将其添加到数据向量并更新年龄 - >总和映射中的总和

    如果年龄等于当前的最低年龄,请添加数据并更新年龄 - >总和地图。

    如果新添加的数据的年龄小于当前最小值,请将其添加到数据向量,将新年龄推送到堆栈,并将新条目添加到age-&gt; sum map。

  • 删除数据:

    对于所有数据,将其从向量中移除,并更新age-&gt; sum map。

    如果年龄等于当前的最小年龄,并且年龄 - >总和映射中的总和已达到零,则弹出年龄堆栈。新总和是年龄 - >总和地图中新年龄的总和。

通过使用您不断更新的地图以及最低年龄的堆栈,您无需重新计算总和,因为它们始终是最新的。