// Реализация бинарного поиска, рекурсивный вариант. // array - отсортированный массив // value - значение для поиска в массиве array func BinarySearch(array []int, value int) int { end := len(array) - 1 if end >= 0 { // Вычисление середины массива index := end / 2 // Если значения равны, значит удалось найти элемент if array[index] == value { return index // Если выбранный элемент больше, то переходим в левую часть } else if array[index] > value { if result := BinarySearch(array[:index], value); result >= 0 { return result } // Если выбранный элемент меньше, то переходим в правую часть } else if array[index] < value { begin := index + 1 if result := BinarySearch(array[begin:end+1], value); result >= 0 { return begin + result } } } // Если значение не найдено в массиве return -1 }
// Реализация бинарного поиска, итеративный вариант. // array - отсортированный массив // value - значение для поиска в массиве array func BinarySearch(array []int, value int) int { index := 0 begin := 0 end := len(array) - 1 for begin <= end { // Вычисление середины массива index = (begin + end) / 2 // Если значения равны, значит удалось найти элемент if array[index] == value { return index // Если выбранный элемент больше, то переходим в левую часть } else if array[index] > value { end = index - 1 // Если выбранный элемент меньше, то переходим в правую часть } else if array[index] < value { begin = index + 1 } } // Если значение не найдено в массиве return -1 }
// Реализация бинарного поиска, поиск всех вхождений. // array - отсортированный массив // value - значение для поиска в массиве array func BinarySearch(array []int, value int) []int { index := 0 begin := 0 end := len(array) - 1 result := []int{} for begin <= end { // Вычисление середины массива index = (begin + end) / 2 // Если значения равны, значит удалось найти элемент if array[index] == value { result = append(result, index) // Двигаемся влево до тех пор пока значения совпадают и есть элементы leftIndex := index - 1 for leftIndex >= begin && array[leftIndex] == value { result = append(result, leftIndex) leftIndex-- } // Двигаемся вправо до тех пор пока значения совпадают и есть элементы rightIndex := index + 1 for rightIndex <= end && array[rightIndex] == value { result = append(result, rightIndex) rightIndex++ } break // Если выбранный элемент больше, то переходим в левую часть } else if array[index] > value { end = index - 1 // Если выбранный элемент меньше, то переходим в правую часть } else if array[index] < value { begin = index + 1 } } // Если значение не найдено в массиве return result }
Количество элементов для сравнения на каждом шаге алгоритма уменьшается ровно в два раза, что соответствует формуле двоичного логарифма, и описывается как O(log n). Ниже приведена таблица для всех описанных вариантов.
Реализация | Сложность в O-нотации |
---|---|
Рекурсивный алгоритм | O(log n) |
Итеративный алгоритм | O(log n) |
Получение всех вхождений | O(log n + l + r) |
Обратите внимание на то, что получение всех вхождений имеет отличную от других вариантов сложность, это связано с тем, что после нахождения первого вхождения необходимо последовательно найти все оставшиеся элементы, l - количество совпавших элементов слева, r - количество совпавших элементов справа.
Весь исходный код примеров к данной статье вы можете найти на GitHub.