合并 C++ 中的范围

发布于 2024-10-21 15:48:59 字数 276 浏览 7 评论 0原文

我有一个随机排序的唯一封闭范围 R0...Rn-1 列表,其中

Ri = [r1i, r2i] (r1i <= r2)

随后一些范围重叠(部分或完全),因此需要合并。

我的问题是,用于合并此类范围的最佳算法或技术是什么。此类算法的示例或执行此类合并操作的库的链接会很棒。

I have a list of randomly ordered unique closed-end ranges R0...Rn-1 where

Ri = [r1i, r2i] (r1i <= r2i)

Subsequently some of the ranges overlap (partially or completely) and hence require merging.

My question is, what are the best-of-breed algorithms or techniques used for merging such ranges. Examples of such algorithms or links to libraries that perform such a merging operation would be great.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

鸠魁 2024-10-28 15:48:59

您需要做的是:

  1. 按字典顺序对范围键为 [r_start,r_end] 的项目进行排序

  2. 迭代排序列表并检查当前项目是否与下一个重叠。如果它确实将当前项目扩展为r[i].start,r[i+1].end,并转到下一个项目。如果不重叠,则将当前项目添加到结果列表中并移至下一个项目。

这是示例代码:

    vector<pair<int, int> > ranges;
    vector<pair<int, int> > result;
    sort(ranges.begin(),ranges.end());
    vector<pair<int, int> >::iterator it = ranges.begin();
    pair<int,int> current = *(it)++;
    while (it != ranges.end()){
       if (current.second > it->first){ // you might want to change it to >=
           current.second = std::max(current.second, it->second); 
       } else {
           result.push_back(current);
           current = *(it);
       }
       it++;
    }
    result.push_back(current);

What you need to do is:

  1. Sort items lexicographically where range key is [r_start,r_end]

  2. Iterate the sorted list and check if current item overlaps with next. If it does extend current item to be r[i].start,r[i+1].end, and goto next item. If it doesn't overlap add current to result list and move to next item.

Here is sample code:

    vector<pair<int, int> > ranges;
    vector<pair<int, int> > result;
    sort(ranges.begin(),ranges.end());
    vector<pair<int, int> >::iterator it = ranges.begin();
    pair<int,int> current = *(it)++;
    while (it != ranges.end()){
       if (current.second > it->first){ // you might want to change it to >=
           current.second = std::max(current.second, it->second); 
       } else {
           result.push_back(current);
           current = *(it);
       }
       it++;
    }
    result.push_back(current);
人生戏 2024-10-28 15:48:59

Boost.Icl 可能是对你有用。

该库提供了一些您可以在您的情况下使用的模板:

  • Interval_set — 将一组实现为一组间隔 - 合并相邻的间隔。
  • split_interval_set — 将一组实现为一组间隔 - 将相邻的间隔分开
  • split_interval_set — 将一组实现为一组间隔 - 在插入时重叠间隔被分割

有一个 示例用于将间隔与库合并:

interval<Time>::type night_and_day(Time(monday,   20,00), Time(tuesday,  20,00));
interval<Time>::type day_and_night(Time(tuesday,   7,00), Time(wednesday, 7,00));
interval<Time>::type  next_morning(Time(wednesday, 7,00), Time(wednesday,10,00));
interval<Time>::type  next_evening(Time(wednesday,18,00), Time(wednesday,21,00));

// An interval set of type interval_set joins intervals that that overlap or touch each other.
interval_set<Time> joinedTimes;
joinedTimes.insert(night_and_day);
joinedTimes.insert(day_and_night); //overlapping in 'day' [07:00, 20.00)
joinedTimes.insert(next_morning);  //touching
joinedTimes.insert(next_evening);  //disjoint

cout << "Joined times  :" << joinedTimes << endl;

以及该算法的输出:

Joined times  :[mon:20:00,wed:10:00)[wed:18:00,wed:21:00)

以及这里关于他们算法的复杂性:

加法的时间复杂度< /a>

Boost.Icl might be of use for you.

The library offers a few templates that you may use in your situation:

  • interval_set — Implements a set as a set of intervals - merging adjoining intervals.
  • separate_interval_set — Implements a set as a set of intervals - leaving adjoining intervals separate
  • split_interval_set — implements a set as a set of intervals - on insertion overlapping intervals are split

There is an example for merging intervals with the library :

interval<Time>::type night_and_day(Time(monday,   20,00), Time(tuesday,  20,00));
interval<Time>::type day_and_night(Time(tuesday,   7,00), Time(wednesday, 7,00));
interval<Time>::type  next_morning(Time(wednesday, 7,00), Time(wednesday,10,00));
interval<Time>::type  next_evening(Time(wednesday,18,00), Time(wednesday,21,00));

// An interval set of type interval_set joins intervals that that overlap or touch each other.
interval_set<Time> joinedTimes;
joinedTimes.insert(night_and_day);
joinedTimes.insert(day_and_night); //overlapping in 'day' [07:00, 20.00)
joinedTimes.insert(next_morning);  //touching
joinedTimes.insert(next_evening);  //disjoint

cout << "Joined times  :" << joinedTimes << endl;

and the output of this algorithm:

Joined times  :[mon:20:00,wed:10:00)[wed:18:00,wed:21:00)

And here about complexity of their algorithms:

Time Complexity of Addition

强辩 2024-10-28 15:48:59

一个简单的算法是:

  • 按起始值对范围进行排序
  • 从头到尾迭代范围,每当发现与下一个范围重叠的范围时,将它们合并

A simple algorithm would be:

  • Sort the ranges by starting values
  • Iterate over the ranges from beginning to end, and whenever you find a range that overlaps with the next one, merge them
梦过后 2024-10-28 15:48:59

O(n*log(n)+2n):

  • 进行 r1_i -> 的映射r2_i,
  • r1_i 进行快速排序,
  • 遍历列表为每个 r1_i 值选择最大的 r2_i 值,
  • 使用该 r2_i 值,您可以跳过所有小于 r2_i后续 r1_i

O(n*log(n)+2n):

  • Make a mapping of r1_i -> r2_i,
  • QuickSort upon the r1_i's,
  • go through the list to select for each r1_i-value the largest r2_i-value,
  • with that r2_i-value you can skip over all subsequent r1_i's that are smaller than r2_i
海的爱人是光 2024-10-28 15:48:59

杰思罗的回答有一个错误。
应该是

if (current.second > it->first){
    current.second = std::max(current.second, it->second);        
} else { 

jethro's answer contains an error.
It should be

if (current.second > it->first){
    current.second = std::max(current.second, it->second);        
} else { 
风月客 2024-10-28 15:48:59

我的算法不使用额外的空间,而且也是轻量级的。我使用了2-pointer方法。 'i' 不断增加,而 'j' 跟踪当前正在更新的元素。
这是我的代码:

bool cmp(Interval a,Interval b)
 {
     return a.start<=b.start;
 }
vector<Interval> Solution::insert(vector<Interval> &intervals, Interval newInterval) {
    int i,j;
    sort(intervals.begin(),intervals.end(),cmp);
    i=1,j=0;
    while(i<intervals.size())
    {
        if(intervals[j].end>=intervals[i].start)  //if overlaps
        {
            intervals[j].end=max(intervals[i].end,intervals[j].end); //change
        }
        else
        {
            j++;
            intervals[j]=intervals[i];  //update it on the same list
        }
        i++;
    }
    intervals.erase(intervals.begin()+j+1,intervals.end());
    return intervals;
}

Interval 可以是具有数据成员“start”和“end”的公共类或结构。
快乐编码:)

My algorithm does not use extra space and is lightweight as well. I have used 2-pointer approach. 'i' keeps increasing while 'j' keeps track of the current element being updated.
Here is my code:

bool cmp(Interval a,Interval b)
 {
     return a.start<=b.start;
 }
vector<Interval> Solution::insert(vector<Interval> &intervals, Interval newInterval) {
    int i,j;
    sort(intervals.begin(),intervals.end(),cmp);
    i=1,j=0;
    while(i<intervals.size())
    {
        if(intervals[j].end>=intervals[i].start)  //if overlaps
        {
            intervals[j].end=max(intervals[i].end,intervals[j].end); //change
        }
        else
        {
            j++;
            intervals[j]=intervals[i];  //update it on the same list
        }
        i++;
    }
    intervals.erase(intervals.begin()+j+1,intervals.end());
    return intervals;
}

Interval can be a public class or structure with data members 'start' and 'end'.
Happy coding :)

独守阴晴ぅ圆缺 2024-10-28 15:48:59

我知道这距离最初接受的答案已经过去很长时间了。但在
c++11 中,我们现在可以通过以下方式

priority_queue( const Compare& compare, const Container& cont )

在 O(n) 比较中构造优先级队列。

请参阅 https://en.cppreference.com/w/cpp/container/优先队列/优先队列
了解更多详情。

因此我们可以在 O(n) 时间内创建一个优先级队列(最小堆)。在 O(1) 时间内获取最低间隔并在 O(log(n)) 时间内将其弹出。
所以总体时间复杂度接近 O(nlog(n) + 2n) = O(nlogn)

I know that this is a long time after the original accepted answer. But in
c++11, we can now construct a priority_queue in the following manner`

priority_queue( const Compare& compare, const Container& cont )

in O(n) comparisons.

Please see https://en.cppreference.com/w/cpp/container/priority_queue/priority_queue
for more details.

So we can create a priority_queue(min heap) of pairs in O(n) time. Get the lowest interval in O(1) and pop it in O(log(n)) time.
So the overall time complexity is close to O(nlog(n) + 2n) = O(nlogn)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文