Найти пересечение диапазона чисел

каков наилучший способ узнать, пересекаются ли два диапазона чисел?

мой диапазон 3023-7430, теперь я хочу проверить, какой из следующих диапазонов чисел пересекается с ним: 10000. Ответ должен быть 3000-6000 и 6000-8000.

каков хороший, эффективный математический способ сделать это на любом языке программирования?

5 ответов


просто псевдо код угадать:

Set<Range> determineIntersectedRanges(Range range, Set<Range> setofRangesToTest)
{
  Set<Range> results;
  foreach (rangeToTest in setofRangesToTest)
  do
    if (rangeToTest.end <range.start) continue; // skip this one, its below our range
    if (rangeToTest.start >range.end) continue; // skip this one, its above our range
    results.add(rangeToTest);
  done
  return results;
}

Я бы сделал класс диапазона и дал ему метод boolean intersects(Range) . Тогда вы можете сделать

foreach(Range r : rangeset) { if (range.intersects(r)) res.add(r) }

само пересечение что-то вроде

this.start <= other.end && this.end >= other.start

Это сильно зависит от ассортимента. Диапазон может быть большим или маленьким, кластеризованным или не кластеризованным. Если у вас есть большие кластеризованные диапазоны (подумайте о "всех положительных 32-битных целых числах, которые можно разделить на 2), простой подход с диапазоном(Нижний, Верхний) не удастся.

думаю, я могу сказать следующее: если у вас мало диапазонов (кластеризация или не кластеризация здесь не имеет значения), рассмотрите bitvectors. Эти маленькие твари пылают быстро по отношению к союзу, пересечению и тестирование членства, хотя итерация по всем элементам может занять некоторое время, в зависимости от размера. Кроме того, поскольку они используют только один бит для каждого элемента, они довольно малы, если вы не бросаете на них огромные диапазоны.

Если у вас меньше, больше диапазонов, то достаточно диапазона класса, описанного otherswill. Этот класс имеет атрибуты lower и upper, а пересечение (a, b) в основном b.верхний b.ниже. Соединение и пересечение могут быть реализовано в постоянное время для одиночных диапазонов и для compisite диапазонов, время растет с количеством поддиапазонов (таким образом, вы не хотите, чтобы не слишком много маленьких диапазонов)

Если у вас есть огромное пространство, где ваши номера могут быть, и диапазоны распределены в неприятном fasion, вы должны взглянуть на бинарные диаграммы решений (BDDs). Эти изящные диаграммы имеют два терминальных узла, True и False и узлы принятия решений для каждого немного входных данных. Узел решения имеет бит it смотрит и два следующих узла графика - один для " бит-один "и один для"бит-ноль". Учитывая эти условия, вы можете кодировать большие диапазоны в крошечном пространстве. Все положительные целые числа для произвольно больших чисел могут быть закодированы в 3 узлах графа-в основном один узел решения для наименее значимого бита, который переходит в False на 1 и в True на 0.

пересечение и объединение-довольно элегантные рекурсивные алгоритмы, например, пересечение в основном занимает два соответствующие узлы в каждом BDD, пересекают 1-ребро, пока не появится некоторый результат и не проверит: если одним из результатов является False-Terminal, создайте 1-ветвь к False-terminal в результате BDD. Если оба являются True-Terminal, создайте 1-ветвь к True-terminal в результате BDD. Если это что-то другое, создайте 1-ветвь для этого чего-то другого в результате BDD. После этого начинается некоторая минимизация (если 0-и 1-ветвь узла идут к тому же следующему BDD / terminal, удалите его и потяните входящие переходы к цели), и вы золотые. Мы даже пошли дальше, мы работали над моделированием сложения наборов целых чисел на BDDs, чтобы улучшить прогнозирование значений для оптимизации условий.

эти соображения подразумевают, что ваши операции ограничены количеством битов в вашем диапазоне чисел, то есть log_2(MAX_NUMBER). Только подумайте, вы можете пересекать произвольные множества 64-битных целых чисел почти в постоянное время.

дополнительная информация может быть, например, в Википедия и справочные документы.

далее, если ложные срабатывания терпимы, и вам нужна только проверка существования, вы можете посмотреть на фильтры Bloom. Фильтры Bloom используют вектор хэшей, чтобы проверить, содержится ли элемент в представленном наборе. Пересечение и объединение-это постоянное время. Основная проблема здесь заключается в том, что вы получаете увеличивающуюся ложноположительную скорость, если вы заполняете bloom-фильтр слишком. Информация, опять же, в Википедия, например.

Hach, set representation-забавное поле. :)


в python

class nrange(object):
    def __init__(self, lower = None, upper = None):
        self.lower = lower
        self.upper = upper
    def intersection(self, aRange):
        if self.upper < aRange.lower or aRange.upper < self.lower:
            return None
        else:
            return nrange(max(self.lower,aRange.lower), \
                          min(self.upper,aRange.upper))

Если вы используете Java Commons Lang Range есть метод overlapsRange (диапазон диапазона).