У меня есть массив объектов Java.

  • Каждый объект хранит два длинных числа, определяющих диапазон чисел.
  • У меня уже есть гарантия, что для всех объектов в диапазоне диапазоны номеров не перекрываются.

Я хочу быстро найти конкретный объект в массиве, учитывая число, которое может (или не может) попадать в один из диапазонов чисел, определенных объектами.

Я надеялся сделать это с помощью Array.binarySearch, но это не выглядело подходящим.

Есть какие-нибудь мысли о том, как это сделать?

2
tomdee 1 Июл 2009 в 19:06
Массив как-то отсортирован?
 – 
Erix
1 Июл 2009 в 19:10
Array.binarySearch требует, чтобы ваш массив был предварительно отсортирован. Это?
 – 
Jørn Schou-Rode
1 Июл 2009 в 19:10
Нет, не отсортировано. Сортировка массива кажется простой, но тогда двоичный поиск сложнее, поскольку я пытаюсь найти число, которое попадает в диапазон.
 – 
tomdee
2 Июл 2009 в 18:50

3 ответа

Лучший ответ

Используйте TreeMap. Ключ - это нижняя из двух границ дальнего действия; значение - это объект.

private TreeMap<Long, T> map = new TreeMap<Long, T>();

void insertObject(T object) {
    map.put(object, object.getLowerRangeBoundary());
}

T getObjectByKeyInRange(Long query) {
    // Get the first Object in the tree that corresponds with the query
    Map.Entry<Long, T> e = map.floorEntry(query);

    // If there's no entry, then the query value is lower than all ranges in the tree
    if (e == null) {
        return null;
    }

    T target = e.getValue();
    // "target" is the only object that can contain the query value
    // If the query value is within the range of "target", then it is our object
    if (query < target.getUpperRangeBoundary()) {
        return target;
    }

    // Nobody has the query value in their range; return null
    return null;
}
7
jprete 1 Июл 2009 в 19:24

Попросите элементы в массиве реализовать интерфейс Comparable, позволив элементу a быть больше, чем другой элемент b, если a.start> b.end. Затем отсортируйте массив, используя это сравнение.

Затем, чтобы определить, находится ли число x в диапазоне в элементе массива, выполните поиск в массиве первого элемента k с помощью k.end> = x и проверьте, является ли k.start <= x. Если да, то k - это диапазон. В противном случае x не входит ни в один диапазон в массиве.

4
drvdijk 1 Июл 2009 в 19:13
Определенно, как бы я это сделал. Я бы даже, вероятно, сначала отсортирую массив в этой точке, а затем бинарный поиск значений.
 – 
AlbertoPL
1 Июл 2009 в 19:15
В общем, это не полный порядок. Поэтому я бы выбрал компаратор. На самом деле, я бы все равно предпочел Comparator.
 – 
Tom Hawtin - tackline
1 Июл 2009 в 19:32
Я не уверен, что понимаю это. Как выполнить поиск в массиве первого элемента k с помощью k.end> =?
 – 
tomdee
2 Июл 2009 в 17:26
Например, перебирая массив, ломая его, когда вы его нашли? Или примените бинарный поиск, начав с середины этого массива, влево или вправо и т. Д.
 – 
drvdijk
2 Июл 2009 в 18:31
Я не хочу выполнять линейный поиск по массиву - это именно то, чего я пытаюсь избежать. Я также надеялся избежать реализации моего собственного binarySearch (). Я подумал, что есть способ подчинить существующую мою волю.
 – 
tomdee
2 Июл 2009 в 18:51

На самом деле вы можете справиться с этим очень эффективно (для большого количества диапазонов и миллионов запросов в диапазонах) и разрешите перекрытие диапазонов.

Псевдокод:

Пусть rangeMap будет TreeMap:

foreach(Range r in ranges)
    rangeMap[r.start].Increment();
    rangeMap[r.end].Decrement();

RangeMap.GreatestLowerBound (i) теперь будет возвращать количество диапазонов, к которым принадлежит данное целое число i (т.е. GreatestLowerBound - это наибольшее число <= i).

Вы можете добиться большего с точки зрения практической производительности, если заранее знаете количество диапазонов ... выделив один массив, заполнив его с помощью deltaRange, затем «интегрировав», чтобы получить массив, показывающий совокупные «диапазоны» для каждое число x.

0
Paul Hollingsworth 1 Июл 2009 в 19:47