Подтвердить что ты не робот

Слияние диапазонов в С++

У меня есть список случайно упорядоченных уникальных замкнутых диапазонов R 0... R n-1, где

R i= [r1 i, r2 i] (r1 i <= r2 Iсуб > )

Впоследствии некоторые из диапазонов перекрываются (частично или полностью) и, следовательно, требуют слияния.

Мой вопрос в том, каковы лучшие в своем классе алгоритмы или методы, используемые для слияния таких диапазонов. Примеры таких алгоритмов или ссылок на библиотеки, которые выполняют такую ​​операцию слияния, были бы большими.

4b9b3361

Ответ 1

Что вам нужно сделать:

  • Сортировка элементов лексикографически, если клавиша диапазона [r_start, r_end]

  • Итерируйте отсортированный список и проверьте, не перекрывается ли текущий элемент со следующим. Если он расширяет текущий элемент, чтобы быть 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);

Ответ 2

Boost.Icl может быть вам полезен.

Библиотека предлагает несколько шаблонов, которые вы можете использовать в своей ситуации:

  • interval_set - реализует набор как набор интервалов - объединение смежных интервалов.
  • separate_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)

А вот о сложности их алгоритмов:

Сложность времени добавления

Ответ 3

Простым алгоритмом будет:

  • Сортировка диапазонов путем запуска значений
  • Итерации по диапазонам от начала до конца, и всякий раз, когда вы находите диапазон, который перекрывается со следующим, объедините их

Ответ 4

О (п * журнала (п) + 2n):

  • Сделайте отображение r1_i -> r2_i,
  • QuickSort на r1_i,
  • просмотрите список, чтобы выбрать для каждого r1_i -значения наибольшее значение r2_i,
  • с этим значением r2_i вы можете пропустить все последующие r1_i, которые меньше r2_i

Ответ 5

Ответ jethro содержит ошибку. Это должно быть

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

Ответ 6

Мой алгоритм не использует дополнительное пространство и также имеет легкий вес. Я использовал подход 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;
}

Интервал может быть открытым классом или структурой с "началом" данных и "концом". Счастливое кодирование:)