计算地图C ++中的重叠时间

时间:2014-03-11 10:29:48

标签: c++ time map overlapping

我有一张带有key = startTime和value = endTime的地图,如下所示:

map<uint32_t,uint32_t>time_map;

uint32_tunsigned __int32,但这与此无关。)

我想计算这些值中有多少重叠值(表示连接的startTime和它的endTime,实际上有多少重叠连接)。

哪种计算方法最快?是否有std::map内的任何函数/方法来解决这类问题?


编辑:就原始问题不清楚而言,我们的想法是计算任何给定时间点的重叠连接的最大数量。这意味着,给定这些时间:

start 100 - end 1000 / start 120 - end 200 / start 250 - end 400 / start 600 - end 800

答案是2(1分2分,1分3分,1分4分,但其他人没有其他人)

5 个答案:

答案 0 :(得分:1)

如果您将时间间隔视为1维line segments(而不是欧几里德平面中通常的2维线段),我认为您的问题是线段交集(http://en.wikipedia.org/wiki/Bentley-Ottmann_algorithm)之一。

在算法上,您可以使用计算几何中的一种扫描线算法来实现与天真方法相关的小于O(n ^ 2)的复杂度。上面的Bentley-Ottmann算法就是其中之一。从概念上讲,您可以从左到右保持扫描线扫描,记录您的扫描线进入或离开间隔。细节可以在任何好的计算几何教科书中找到。

我认为std::map不支持扫描线算法,您需要实现与之关联的必要数据结构。

答案 1 :(得分:1)

您可以使用Boost的日期/时间库。它有一个time_period类,它支持一个intersects方法,如examples所示。这样就不需要为这两个间隔重叠编写代码了吗?&#39;虽然您仍然需要决定如何遍历您的集合(避免O(n ^ 2)遍历似乎很难)。

编辑:您需要随时获得最大并发间隔数。 在这种情况下,Ting L对扫描线算法的建议似乎是最好的。按开始时间对间隔进行排序,并按顺序迭代它们。迭代时保持堆栈。对于每个新间隔,在新间隔开始之前弹出堆栈上已过期的任何间隔。跟踪堆栈的最大大小将为您提供最大并发间隔数(如果您需要知道它们的间隔时间,您将需要维护一个单独的容器&#39;当前最长的设置&#39;更新为您迭代)

答案 2 :(得分:1)

我会首先使用一个简单的方法,使用边桌;它将接近一个广泛的算法。

这个想法:

  • 按顺序迭代连接(按开始时间排序)
  • 保留一组当前涉及的连接

诀窍是有效地跟踪连接,特别是何时删除连接;优先级队列对此非常有用。

一些帮助:

struct Connection {
    uint32_t start;
    uint32_t end;
}; // struct Connection

// WATCH OUT:
// std::priority_queue only let you access the MAXIMUM element, so the predicate
// is the OPPOSITE of what we usually write...
struct OrderByEnd {
    bool operator()(Connection const& left, Connection const& right) const {
        if (left.end > right.end) { return true; }
        if (left.end < right.end) { return false; }
        return left.start > right.start;
    }
}; // struct OrderByEnd

using CurrentlyOverlappingType = std::priority_queue<Connection, std::deque<Connection>, OrderByEnd>;

然后,我们扫一扫:

size_t countMaxNumberOfOverlaps(std::map<uint32_t, uint32_t> const& connections) {
    if (connections.empty()) { return 0; }

    size_t max = 0;
    CurrentlyOverlappingType currentlyOverlapping;

    for (auto const& con: connections) {
        // Purge no longer overlapping connections
        while (not currentlyOverlapping.empty() and currentlyOverlapping.top().end < con.first) {
            currentlyOverlapping.pop();
        }

        // Debug:
        if (not currentlyOverlapping.empty()) {
            std::cout << "[" << con.first << ", " << con.second <<
                "] is overlapping with: " << currentlyOverlapping.size() << " connections\n";
        }

        // The current connection is necessarily overlapping with itself
        currentlyOverlapping.push(Connection{con.first, con.second});

        max = std::max(max, currentlyOverlapping.size());
    }

    return max;
} // countMaxNumberOfOverlaps

it works as expected

[120, 200] is overlapping with: 1 connections
[250, 400] is overlapping with: 1 connections
[600, 800] is overlapping with: 1 connections
Max number of overlaps: 2

复杂性难以理解。您必须扫描整个连接集,但在每一步中,工作量与当前重叠连接数成正比...

  • 最坏情况复杂:O(N * log(N))我会说(因为在优先级队列中插入是对数的)
  • 平均病例复杂度:O(N * log(O))其中O是重叠连接数

注意:在算法分析中,我认为清除部分的复杂性是分摊的常数;我们知道物品将被清除,因此我们可以考虑清除它们的插入成本。插入N个项目,将清除N个项目。作为清除过程的一部分执行的比较数量(我认为)也是摊销常数(所有项目的总数最多为2N),尽管它是直觉而不是计算。因此,清除的成本与在优先级队列中插入项目的成本相比相形见绌,每个项目的日志(O)。

答案 3 :(得分:0)

Map(std map)是按键排序的树。查看this链接。因此,如果你迭代,那么你将按照开始时间的顺序得到它。但是,除了检查特定的重叠时间之外,std :: map api还没有其他支持。

现在要检查重叠时间,你必须将经典迭代器方法作为最坏情况的方法。检查元素i的结束时间,始终小于iN的开始时间。

HTH!

答案 4 :(得分:0)

我认为问题的本质与集合和设置交叉点有关。您可以尝试STL set容器和set_intersection函数,它可以有效地找到两个排序序列的交集。 (实际上,set只是一个只包含键的地图(没有值)所以你可以使用地图,它们也可以排序。)

比如说,您可以将时间间隔表示为一对(开始,结束)并构建所有间隔相交集的交集。您可以定义自己的比较功能。 确切的逻辑将来自您的任务细节,这些细节尚不完全清楚。

(还有set_differenceset_unionset_symmetric_difference个函数。)