@ivan_ivanov_ivanych

Как правильно реализовать алгоритм бинарного поиска?

Добрый всем день!
Мне нужно найти список всех городов подходящих по критерию поиска в строке.
Файл со списком городов приходит мне в json в таком формате
[
  {
    "Спорная территория": "",
    "Область": "Алтайский край",
    "Город": "Камень-на-Оби"
  },
...
]

Я решил что эту проблему лучше всего решить с помощью бинарного поиска, так как список населенных пунктов довольно таки большой. Естественно для начала я сортирую весь приходящий массив по алфавиту по полю "Город", так как по этому полю и происходит поиск
const sortCities = () => citiesList.sort((a, b) => {
    const nameA = a["Город"].toLowerCase();
    const nameB = b["Город"].toLowerCase();
    if (nameA < nameB) {
      return -1
    }
    if (nameA > nameB) {
      return 1
    }
    return 0
  })


Далее, при вводе происходит поиск
const binarySearch = (list: ICities[], value: string): ICities[] => {
    let suitableValues = []
    let low = 0
    let high = list.length - 1
    while (low <= high) {
      let mid = Math.floor((low + high) / 2)
      let guess = list[mid]
      let flag = true
      for (let i = 0; i < value.length; i ++) {
       if (guess["Город"].toLocaleLowerCase()[i] !== value.toLocaleLowerCase()[i]) {
          flag = false
        }
      }
      if (flag) {
        suitableValues.push(guess)
      }
      if (guess["Город"].toLowerCase() > value.toLowerCase()) {
        high = mid - 1
      } else {
        low = mid + 1
      }
    }
    return suitableValues
  }


Проблема в том, при выполнении условия flag - while не останавливается, а меняет значение low или high, что обрезает нужные мне значения. Я понимаю, что мне нужно прописать continue - но перед эти явно нужно какое-то изменение, чтобы не создавать бесконечный цикл, но не могу догадаться какое именно.
  • Вопрос задан
  • 144 просмотра
Решения вопроса 1
wataru
@wataru Куратор тега Алгоритмы
Разработчик на С++, экс-олимпиадник.
Во-первых, лучшее решение тут - это использовать структуру данных "бор", а не запускать бинарный поиск по сортированным строкам. Да, в конце-концов, какой-нибудь встроенный ассоциативный массив или словарь в вашем языке программирования может быть эффективнее вашего ручного бинарного поиска.

Но если вам по заданию надо бинпоиск использовать, то у вас там следующие ошибки в реализации:
- постоянное преобразование к toLowerCase - это ОЧЕНЬ неэффективно. Один раз все приведите к lowerCase и работайте только с этим. Можно эти ключи схоранить в новых полях.
- когда вы нашли совпадение, можно делать из цикла break.

Вы не сможете бинпоиском найти все объекты. Он может найти только один. Самый левый, самый правый, или как повезет - зависит от реализации.
Вам надо запустить два бинпоиска последовательно. Один будет искать минимальный элемент, больше равный искомому (lower_bound), а второй бинпоиск будет искать максимальный элемент строго больший искомому (upper_bound). Пусть ваши бинпоиски возвращают индекс в массиве list. Эти две функции будут отличаться только в одном месте - там будет < и <= соответсственно.
Ответ к задаче будет в массиве list по индексам от lower_bound (включительно) до upper_bound (не включительно). Может быть и так, что lower_bound == upper_bound, если искомого элемента в массиве нет и ответ будет пустым.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы