在C ++中合并范围

时间:2011-03-11 18:10:16

标签: c++ algorithm merge range

我有一个随机排序的唯一闭端范围列表R 0 ... R n-1 其中

  

R i = [r1 i ,r2 i ](r1 i < = r2 I

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

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

7 个答案:

答案 0 :(得分:26)

您需要做的是:

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

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

  3. 以下是示例代码:

        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);
    

答案 1 :(得分:12)

Boost.Icl可能对您有用。

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

  • interval_set - 将集合实现为一组间隔 - 合并相邻的间隔。
  • separate_interval_set - 将一个集合实现为一组间隔 - 将相邻的间隔分开
  • split_interval_set - 将一个集合实现为一组间隔 - 在插入重叠间隔时将其拆分

有一个example用于合并库的间隔:

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)

这里关于算法的复杂性:

Time Complexity of Addition

答案 2 :(得分:3)

一个简单的算法是:

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

答案 3 :(得分:3)

为O(n *的log(n)+ 2N):

  • 制作r1_i -> r2_i
  • 的映射
  • r1_i上的QuickSort,
  • 浏览列表以选择每个r1_i - 值最大r2_i - 值,
  • 使用r2_i - 值,您可以跳过小于r1_i的所有后续 r2_i

答案 4 :(得分:2)

jethro的回答包含错误。 它应该是

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

答案 5 :(得分:0)

我的算法不使用额外的空间,也是轻量级的。我使用过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'的结构。 快乐的编码:)

答案 6 :(得分:0)

我知道这是最初接受答案后的很长时间。但在 c ++ 11,我们现在可以按以下方式构造一个priority_queue`

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

在O(n)个比较中

请参阅https://en.cppreference.com/w/cpp/container/priority_queue/priority_queue 有关更多详细信息。

因此,我们可以在O(n)时间内创建对的priority_queue(最小堆)。获取O(1)中的最小间隔,并在O(log(n))时间中将其弹出。 因此,总体时间复杂度接近O(nlog(n)+ 2n)= O(nlogn)