RSS    

   Реферат: VB, MS Access, VC++, Delphi, Builder C++ принципы(технология), алгоритмы программирования

Если позиция, выбранная при помощи интерполяции, оказывается неправильной, то алгоритм сравнивает искомое значение со значением элемента в выбранной позиции. Если искомое значение меньше, то поиск продолжается в первой части списка, если больше — во второй части. На рис. 10.3 графически изображен интерполяционный поиск.

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

    middle = min + (target - List(min)) * _

        ((max - min) / (List(max) - List(min)))

========270-271

@Рис. 10.3 Интерполяционный поиск значения 44

Этот оператор помещает значение middle между min и max в таком же соотношении, в каком искомое значение находится между List(min) и List(max). Если искомый элемент находится рядом с List(min), то разность target – List(min) почти равна нулю. Тогда все соотношение целиком выглядит почти как middle = min + 0, поэтому значение переменной middle почти равно min. Смысл этого заключается в том, что если индекс элемента почти равен min, то его значение почти равно List(min).

Аналогично, если искомый элемент находится рядом с List(max), то разность target – List(min) почти равна разности List(max) – List(min). Их частное почти равно единице, и соотношение выглядит почти как middle = min + (max – min), или middle = max, если упростить выражение. Смысл этого соотношения заключается в том, что если значение элемента близко к List(max), то его индекс почти равен max.

После того, как программа вычислит значение middle, она сравнивает значение элемента в этой позиции с искомым так же, как и в алгоритме двоичного поиска. Если эти значения совпадают, то искомый элемент найден и процесс закончен. Если значение искомого элемента меньше, чем значение найденного, то программа устанавливает значение max равным middle – 1 и продолжает поиск элементов списка с меньшими значениями. Если значение искомого элемента больше, чем значение найденного, то программа устанавливает значение min равным middle + 1 и продолжает поиск элементов списка с большими значениями.

Заметьте, что в знаменателе соотношения, которое находит новое значение переменной middle, находится разность (List(max) – Lsit(min)). Если значения List(max) и List(min) одинаковы, то произойдет деление на ноль и программа аварийно завершит работу. Такое может произойти, если два элемента в списке имеют одинаковые значения. Так как алгоритм поддерживает соотношение min <= target index <= max, то эта проблема может также возникнуть, если min будет расти, а max уменьшаться до тех пор, пока их значения не сравняются.

Чтобы справиться с этой проблемой, программа перед выполнением операции деления проверяет, не равны ли List(max) и List(min). Если это так, значит осталось проверить только одно значение. При этом программа просто проверяет, совпадает ли оно с искомым.

Еще одна тонкость заключается в том, что вычисленное значение middle не всегда лежит между min и max. В простейшем случае это может быть так, если значение искомого элемента выходит за пределы диапазона значений элементов в списке. Предположим, что мы пытаемся найти значение 300 в списке из элементов 100, 150 и 200. На первом шаге вычислений min = 1 и max = 3. Тогда middle = 1 + (300 – List(1)) * (3 – 1) / (List(3) – List(1)) = 1 + (300 – 100) * 2 / (200 – 100) = 5. Индекс 5 не только не находится в диапазоне между min и max, он также выходит за границы массива. Если программа попытается обратиться к элементу массива List(5), то она аварийно завершит работу с сообщением об ошибке “Subscript out of range”.

===========272

Похожая проблема возникает, если значения элементов распределены между min и max очень неравномерно. Предположим, что мы хотим найти значение 100 в списке 0, 1, 2, 199, 200. При первом вычислении значения переменной middle, мы получим в программе middle = 1 + (100 – 0) * (5 – 1) / (200 – 0) = 3. Затем программа сравнивает значение элемента List(3) с искомым значением 100. Так как List(3) = 2, что меньше 100, она задает min = middle + 1, то есть min = 4.

При следующем вычисления значения переменной middle, программа находит middle = 4 + (100 – 199) * (5 – 4) / (200 – 199) = -98. Значение –98 не попадает в диапазон min <= target index <= max и также далеко выходит за границы массива.

Если рассмотреть процесс вычисления переменной middle, то можно увидеть, что существуют два варианта, при которых новое значение может оказаться меньше, чем min или больше, чем max. Вначале предположим, что middle меньше, чем min.

min + (target - List(min)) * ((max - min) / (List(max) - List(min))) < min

После вычитания min из обеих частей уравнения, получим:

(target - List(min)) * ((max - min) / (List(max) - List(min))) < 0

Так как max >= min, то разность (max – min) должна быть больше нуля. Так как List(max) >= List(min), то разность (List(max) – List(min)) также должна быть больше нуля. Тогда все значение может быть меньше нуля, только если (target – List(min)) меньше нуля. Это означает, что искомое значение меньше, чем значение элемента List(min). В этом случае, искомый элемент не может находиться в списке, так как все элементы списка со значением меньшим, чем List(min) уже были исключены.

Теперь предположим, что middle больше, чем max.

min + (target - List(min)) * ((max - min) / (List(max) - List(min))) > max

После вычитания min из обеих частей уравнения, получим:

(target - List(min)) * ((max - min) / (List(max) - List(min))) > 0

Умножение обеих частей на (List(max) – List(min)) / (max – min) приводит соотношение к виду:

target – List(min) > List(max) – List(min)

И, наконец, прибавив к обеим частям List(min), получим:

target > List(max)

Это означает, что искомое значение больше, чем значение элемента List(max). В этом случае, искомое значение не может находиться в списке, так как все элементы списка со значениями большими, чем List(max) уже были исключены.

==========273

Учитывая все эти результаты, получаем, что новое значение переменной middle может выйти из диапазона между min и max только в том случае, если искомое значение выходит за пределы диапазона от List(min) до List(max). Алгоритм может использовать этот факт при вычислении нового значения переменной middle. Он вначале проверяет, находится ли новое значение между min и max. Если нет, то искомого элемента нет в списке и работа алгоритма завершена.

Следующий код демонстрирует реализацию интерполяционного поиска в программе Search:

Public Function InterpSearch(target As Long) As Long

Dim min As Long

Dim max As Long

Dim middle As Long

    min = 1

    max = NumItems

    Do While min <= max

        ' Избегаем деления на ноль.

        If List(min) = List(max) Then

           ' Это искомый элемент (если он есть в списке).

           If List(min) = target Then

               InterpSearch = min

           Else

               InterpSearch = 0

           End If

           Exit Function

        End If

        ' Найти точку разбиения списка.

        middle = min + (target - List(min)) * _

           ((max - min) / (List(max) - List(min)))

        ' Проверить, не вышли ли мы за границы.

        If middle < min Or middle > max Then

           ' Искомого элемента нет в списке.

           InterpSearch = 0

           Exit Function

        End If

        NumSearches = NumSearches + 1

        If target = List(middle) Then     ' Искомый элемент найден.

           InterpSearch = middle

           Exit Function

        ElseIf target < List(middle) Then ' Поиск в левой части.

           max = middle - 1

        Else                              ' Поиск в правой части.

           min = middle + 1

        End If

    Loop

    ' Если мы дошли до этой точки, то элемента нет в списке.

    InterpSearch = 0

End Function

Двоичный поиск выполняется очень быстро, а интерполяционный еще быстрее. В одном из тестов, двоичный поиск потребовал в 7 раз больше времени для поиска значений в списке из 100.000 элементов. Эта разница могла бы быть еще больше, если бы данные находились на диске или каком‑либо другом медленном устройстве. Хотя при интерполяционном поиске на вычисления уходит больше времени, чем в случае двоичного поиска, за счет меньшего числа обращений к диску мы сэкономили бы гораздо больше времени.

Строковые данные

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

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

Если строки достаточно короткие, то можно закодировать их при помощи целых чисел или чисел формата long или double, используя методы, которые были описаны в 9 главе. После этого можно использовать для нахождения элементов в списке интерполяционный поиск.

Если строки слишком длинные, и их нельзя закодировать даже числами в формате double, то все еще можно использовать для интерполяции значения строк. Вначале найдем первый отличающийся символ для строк List(min) и List(max). Затем закодируем его и следующие два символа в каждой строке при помощи методов из 9 главы. Затем можно использовать эти значения для выполнения интерполяционного поиска.

Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82


Новости


Быстрый поиск

Группа вКонтакте: новости

Пока нет

Новости в Twitter и Facebook

                   

Новости

© 2010.