Лекции / Лекция_5_Алгоритмы_поиска_ipynb_Colab
.pdf
На первом шаге, в качестве левой точки выбирается первый элемент последовательности в качестве правой точки последний элемент последовательности. Индекс вычисленный с помощью интерполяционной функции равен:
На втором индексе стоит 3. Это меньше искомого следовательно новое значение |
, |
Вычисляем новый индекс:
На 3 индексе стоит 5. Это искомое. Поиск окончен.
Вычислительный эксперимент
Для оценки асимптотического поведения реализации этого алгоритма был проведен следующий вычислительный эксперимент. Для одномерного массива из 100 000 элементов построена зависимость времени поиска от количества искомых элементов. Рассмотрен линейный,бинарный, поиск Фибоначчи, интерполяционный (для трех последних время сортировки массива также учитывалось). Для корректности каждый замер был повторен 100 раз и было взято усредненное время.
Область применения интерполяционного поиска
В случае равномерно распределенных данных в последовательности эффективность алгоритма интерполяционного поиска превышает эффективность бинарного. И только в случае неудачно подобранной интерполяционной функции или неравномерного распределения данных (например данные распределены экспоненциально, а интерполяционная функция выбрана линейной) его эффективность может снизится до линейной.
Как показывает практика чем больше размер последовательности, тем равномернее в ней распределены данные. На больших последовательностях интерполяционный поиск эффективнее бинарного. Это и определяет область его применения.
Реализация алгоритма на Python
def interpolation_search(sequence, element): |
|
|||
|
#Устанавливаемлевуюграницунапервыйэлемент |
|
||
l= |
0 |
|
|
|
|
#Устанавлиправграницуаемуюнапоследний |
элемент |
||
r= |
len(sequence)- |
1 |
|
|
|
#Покаэлементнаходитсявпределахтекущего |
интервала |
||
|
while sequence[l]<element |
|
and sequence[r]>element: |
|
|
#Еслизначенияграницахравныдальше, |
интерполироватьнельзя |
||
|
if sequence[l]==sequence[r]: |
|
||
|
break |
|
|
|
|
#Интерполяционнаяформуладляпредсказания |
позицииэлемента |
||
|
#(element-sequence[l])-насколькоискомое |
значениебольшелевого |
||
|
#(l-r)-разностьиндексов(отрицательная) |
|
||
|
#(sequence[l]-sequence[r])-разностьзначений |
награницах |
||
index=(element-sequence[l])*(l-r) |
|
|
//(sequence[l]-sequence[r])+l |
|
|
#Еслинайденныйэлементбольшеискомого |
|
||
|
if sequence[ind>element:x] |
|
|
|
|
r=index- |
1 |
#Сдвигаемправуюграницувлево |
|
|
#Еслинайденныйэлементменьшеискомого |
|
||
|
elif sequence[ind<element:x] |
|
||
|
l=index+ |
1 |
#Сдвигаемлевуюграницувправо |
|
|
#Еслинашлиискомыйэлемент |
|
|
|
|
else: |
|
|
|
|
return index |
#Возвращаемегоиндекс |
|
|
|
#Проверяемнеравенли,искомыйэлементлевой |
|
границе |
|
|
if sequence[l]==element: |
|
|
|
|
return l |
|
|
|
|
#Проверяемнеравенли,искомыйэлементправой |
границе |
||
|
if sequence[r]==element: |
|
|
|
return r
#Элемененайдент return -1
Экспоненциальный поиск
Сведение об алгоритме
Сложность по времени в наихудшем случае
— Позиция искомого элемента в последовательности
Краткие сведение о авторах и принципе алгоритма
Алгоритм был разработан Джоном Бентли и Эндрю Чи-Чи Яо в 1976 году. Этот алгоритм используется для быстрого определение диапазона поиска, с последующим поиском в указанном диапазоне с помощью бинарного поиска.
Описание алгоритма
1.Поиск проводим в отсортированной последовательности. Для определения границы объявляется дополнительная переменная (в дальнейшем border ) ее значение устанавливается равной единице. Переходим к пункту 2.
2.Выполняется проверка: если значение border больше чем длина последовательности то в таком случае выполняем бинарный поиск нужного элемента в промежутке от border/2 до размера последовательности. Заканчиваем поиск. В противном случае переходим к пункту 3.
3.Выполняем проверку: если значение на индексе border больше искомого элемента то выполняем бинарный поиск нужного элемента в промежутке от border/2 до border . Заканчиваем поиск. В противном случае переходим к пункту 4.
4.Увеличиваем значение border в два раза. Переходим к пункту 2.
Графическое пояснение алгоритма
Значение border = 1 . Это меньше чем длина последовательности. Значение на 1 индексе меньше искомого. Увеличиваем значение border в два раза и переходим к следующему шагу.
Значение border = 2 . Это меньше чем длина последовательности. Значение на 2 индексе меньше искомого. Увеличиваем значение border в два раза и переходим к следующему шагу.
Значение border = 4 . Это меньше чем длина последовательности. Значение на 4 индексе больше искомого. Проводим бинарный поиск в диапазоне от 2 ( border/2 ) до 4 ( border ). Заканчиваем алгоритм.
Реализация алгоритма на Python
Бинарный поиск в указанных границах
def binary_search(sequence, required_element, start, end):
""" |
|
|
|
Бинарныйпоискэлементавподмассиве |
sequence[start:end+1]. |
||
Возвращаинднайденногокст элементаили |
None,еслиэлемененайдент. |
||
""" |
|
|
|
while start<=end: |
|
#Покаграницынесомкнулись |
|
m= |
(start+end |
) // 2 |
#Индекссреднегоэлемента |
element=sequence |
[m] |
#Значениесреднегоэлемента |
|
|
if element==required_element: |
#Еслинашлиискомыйэлемент |
|
|
return m |
|
#Возвращаемегоиндекс |
|
if element<required_element: |
#Еслисреднийэлементменьшеискомого |
|
start=m+ |
1 |
#Сужаемпоискправойловине |
|
|
else: |
|
#Иначесреднийэлементбольшеискомого |
end=m- |
1 |
#Сужаемпоисклевойполовине |
|
return None |
|
#Элемененайдент |
|
Экспоненциальный поиск
def exponential_search(sequence, required_element):
""" |
|
|
|
|
Экспоненциальный(двоичныйпоиск) |
|
отсортированномсписке. |
||
Сначалаэкспоненциальнорасширяетграницу, |
|
затемвыполняетбинарныйпоиск. |
||
""" |
|
|
|
|
border= |
1 |
|
|
#Начальнаяграница |
#Покаграницаневышлазапределысписка |
|
элементнаграницеменьшеискомого |
||
while border< |
len(sequence)- |
1 and sequence[border]<required_element: |
||
border=border* |
2 |
|
#Увеличиваемграницу2раза |
|
#Еслиграницапревысилапоследнийиндекс, |
|
устанавливаемеё последнийэлемент |
||
if border> |
|
len(sequence)- |
1: |
|
border= |
|
len(sequence)- |
1 |
|
#Выполняембинарныйпоисквдиапазонеот |
|
border//2доborder |
||
return binary_search(sequence,requiredborderelement, |
// 2,border) |
|||
Вычислительный эксперимент
Для проверки ускорения от применения экспоненциального поиска. Был выполнен вычислительный эксперимент. В массиве размером 100_000_000 элементов было произведено k поисков. На графике представлена зависимость времени на k поисков от значения k. Искомые значения равномерно распределены по диапазону значений в массиве.
Как видно из графика экспоненциальный поиск оказывается незначительно оптимальнее бинарного поиска.
Поиск Фибоначчи
Сведение об алгоритме поиска Фибоначчи.
Сложность по времени в наихудшем случае
Затраты памяти
Принцип работы алгоритма
1.Последовательность сортируется в возрастающем порядке. Если последовательность уже отсортирована то этот пункт можно пропустить.
2. |
Производится начальная инициализация. Нужно найти такое число |
, что |
. После чего нужно ввести |
||
|
следующие значения: |
, |
, |
, |
. |
3. |
Проверить корректность индекса. Если индекс меньше нуля перейти к 5. Если индекс больше или равен перейти к 4. |
||||
|
Выполнить сравнение |
, если да то перейти к 4. Если |
|
перейти к 5. |
вернуть поиск успешен. |
4. |
Выполнить проверку |
. Если да, поиск неудачен закончить выполнение. В противном случае установить: |
|||
выполнить обмен Перейти к 3.
5. Выполнить проверку . Если да, поиск неудачен закончить выполнение. В противном случае установить:
Перейти к 3. |
|
|
Тут — число элементов в последовательности. — искомый элемент. |
— элемент последовательности расположенный на |
|
— индексе. |
— -й элемент в последовательности Фибоначчи. |
|
Последовательность Фибоначчи
Последовательность Фибоначчи — последовательность которая задаётся линейным рекуррентным соотношением:
Числа Фибоначчи — элементы числовой последовательности Фибоначчи:
Т.е. нулевое число это 0, первое 1, каждое последующее вычисляется как сумма двух предыдущих.
Графическая иллюстрация работы алгоритма
Вычислительный эксперимент
Для оценки асимптотического поведения реализации этого алгоритма был проведен следующий вычислительный эксперимент. Для одномерного массива из 100_000 элементов построена зависимость времени поиска от количества искомых элементов. Рассмотрен как линейный,бинарный и поиск Фибоначчи (для двух последних время сортировки массива также учитывалось). Для корректности каждый замер был повторен 100 раз и было взято усредненное время.
