2012-02-08 3 views
2

Вот ситуация. У меня есть отсортированный список целых чисел, представляющих события, которые нужно уволить на определенную миллисекунду. Этот список может выглядеть следующим образом:Ищете эффективный алгоритм для нахождения ближайшего целого числа в списке целых чисел

0 
1500 
5000 
9348 
89234 
109280 
109281 
109283 
150000 

Я тогда playhead, который обычно движется вперед каждые 100 мс, но может случайным образом искать и кустарниковые вперед и назад, а также. Этот проигрыватель не гарантирует, что он будет кратным 100, но может быть перекрыт до нескольких, без каких-либо реальных проблем.

Мой вызов состоит в том, чтобы иметь возможность эффективно находить ближайший элемент в списке, который меньше или равен текущей точке воспроизведения. Средняя длина списка составляет от 300 до 1500 элементов. Я могу легко оптимизировать форвард с заданными интервалами, но случайный поиск немного сложнее.

Заставляет меня пожелать, чтобы я спал по классу алгоритмов.

+0

Простейший способ: Цикл через массив в обратном направлении и выбрать первый элемент, который меньше или равен ползунка. Вы пробовали это, это слишком неэффективно для вашего случая использования? – deceze

+0

Задача состоит в том, чтобы * эффективно * найти ... Линейный поиск неэффективен. –

+0

Возможно, это будет достаточно эффективно *. 1500 элементов не * это * много для современной машины. – deceze

ответ

1

Похоже, вы хотите изменить бинарный поиск. Поскольку список отсортирован по порядку, бинарный поиск значительно улучшит эффективность поиска по линейному поиску, и если вы ничего не знаете об интервалах элементов в массиве, вы не сможете сделать намного лучше, чем двоичный поиск. Бинарный поиск должен быть слегка изменен, потому что вы не ищете равенства, а что-то вроде как близко, не переходя.

Вот фактический алгоритм, который сохраняет разделив данные поиска в 1/2 (переход с верхней половины или нижней половине каждый раз на основе сравнения со значением теста), пока она не сводится только один элемент:

var testData = [0,1500,5000,9348,89234,109280,109281,109283,150000]; 

function findNearest(data, val) { 
    if (!data || !data.length) { 
     return(null); 
    } 
    var lowest = 0, mid; 
    var highest = data.length - 1; 
    while (true) {  
     if (lowest == highest) { 
      return(lowest); 
     } 
     mid = Math.ceil(((highest - lowest)/2) + lowest); 
     if (data[mid] == val) { 
      return(mid); 
     } 
     else if (data[mid] < val) { 
      lowest = mid; 
     } else { 
      highest = Math.max(lowest, mid - 1); 
     } 
    } 
} 

и, рабочая программа испытаний: http://jsfiddle.net/jfriend00/rWk2X/

Примечание: этот код предполагает, что все значения в массиве в отсортированном порядке, и массив не пуст.

Если вы дадите ему массив, который не имеет значений меньше целевого значения, он вернет 0, что может быть специальным случаем, который вам нужно обработать, если не уверены, что первое значение в массиве всегда меньше целевого значение (например, всегда ноль).

Если вы дадите ему массив, который не имеет значений больше целевого значения, он вернет последнее значение в массиве (как и должно быть), и это не особый случай, а только желаемый ответ.

+0

Поскольку это казалось интересной проблемой алгоритма, я добавил пример рабочего кода к моему ответу. Если вы играете с этим, будьте осторожны, так как очень легко получить бесконечный цикл. У меня на самом деле было максимальное количество итераций, закодированных в моем коде во время тестирования (он прервал бы после 1000 итераций с ошибкой), чтобы избежать бесконечных циклов. – jfriend00

+0

Это похоже на лучшее решение. Есть ли определенный набор входов, которые приведут к бесконечному циклу? – turing1

+0

@ turing1 - входы не вызовут бесконечного цикла. Вы можете передать что угодно, и он обрабатывается отлично, как комментарии после того, как код попытается объяснить. Только если вы возитесь с кодом в функции и выходите из него, вы рискуете бесконечным циклом. – jfriend00

0

Поскольку это отсортированный список, используйте двоичный поиск. Вы можете сделать лучше, но тогда вам нужно сделать дополнительные предположения (например, вы должны предполагать даже распределение чисел, что, на мой взгляд, не так). Вы можете прочитать об этом здесь: http://en.wikipedia.org/wiki/Binary_search_algorithm

0

Я столкнулся с этой проблемой некоторое время назад и провел несколько сравнений времени выполнения.

Посмотрите here. (образец НЕ работает с IE)

Четвертая реализация, похоже, действительно правильна по сравнению с немым двоичным поиском.

Надеюсь, это поможет.

Bye

Смежные вопросы