Введение в сортировку
Хеширование таблиц
Алгоритм поиска
low=0; high=n-l; search=-l; while(low<high)
{
mid=(int)(low+high)/2; if (key==k[mid])
{
search=mid;
break; }
if (key<k[mid])
high=mid-l; else
low=mid+l; }
Здесь key — аргумент поиска (число, которое записывается в ключевом поле искомой записи); search — переменная, которая хранит номер разыскиваемой записи; mid— номер записи, в которой осуществляется поиск необходимого значения ключевого поля; low и high — границы поиска; п — число ключей в массиве.
Хеширование — один из способов увеличения эффективности поиска [9]. Основная идея хеширования — подобрать некий способ преобразования значения ключа сразу в адрес записи. Таким образом, поиск становится вообще ненужным.
Поясним это на примере. Пусть в файле прямого доступа лежит структура со следующими полями (табл. 3.2): 1) номер накладной, 2) грузоотправитель, 3) грузополучатель, 4) груз, 5) количество единиц груза. Номер накладной обычно
представляет собой довольно длинное целое число; в нашем примере это ключ. Если массив структур снабжен дополнительной таблицей индексов (табл. 3.3), в которой значения ключей отсортированы, например, по возрастанию, и для каждого значения ключа в таблице имеется номер соответствующей записи, то поиск нужной записи выполняется следующим образом: сначала проводим поиск в левой части таблицы индексов, а найдя заданный ключ, получаем номер записи — т. е. прямой доступ к ней.
Таблица 3.2 Поля структуры
Поля | Конкретные значения |
Номер накладной | |
Грузоотправитель | Computer ltd |
Грузополучатель | АО «Теледейта» |
Груз | AS-400 |
Количество единиц груза |
Таблица 3.3 Дополнительная таблица индексов
Ключ | Номер записи |
Попробуем упростить процесс. Пусть мы имеем не более 1000 записей. Если бы значения ключа лежали в диапазоне 1 до 1000, то таблицу индексов можно построить иначе, а именно — заносить номер записи в ячейку таблицы, номер которой равен ключу (табл. 3.4). Ясно, что теперь для поиска записи с ключом, например, 282, достаточно было бы сразу обратиться к ячейке с номером 282 (прямой доступ), извлечь оттуда значение 23 и прочитать запись номер 23 в массиве (снова прямой доступ). Таким образом, поиск не нужен.
Хеширование есть способ перехода от длинных ключей к целым значениям, лежащим в диапазоне номеров записей. На практике хеширование проводят, подбирая некоторую функцию, отображающую все множество значений исходного ключа во множество индексов (адресов). Ясно, что диапазон значений
исходного ключа шире, чем диапазон индексов; поэтому хеширующая функция (хеш-функция) не может быть взаимно однозначной. Это порождает ряд проблем.
Таблица 3.4 Таблица
Номер ячейки | Номер записи |
Вернемся к примеру.Если внимательно посмотреть на последнюю таблицу, то станет ясно, что в качестве хеш-функции мы взяли просто усечение номера накладной до последних трех цифр (это не худший метод хеширования). Однако, что делать, если имеется накладная с номером 207008282, а приходит документ с номером 010550282? Эта ситуация весьма типична и называется коллизией хеширования.
Имеется достаточное количество методов разрешения конфликтов. Возможно сформировать вторичный индекс. В частности можно для повторяющихся значений усеченного ключа использовать связный список. В основную запись можно было бы включить исходный ключ и проводить поиск по списку вторичных ключей до обнаружения нужного исходного. Известны и другие методы разрешения конфликтов.
Под сортировкой понимают процесс перестановки объектов данного множества в определенном порядке.
Цель сортировки — облегчить последующий поиск элементов в отсортированном множестве. Следовательно, методы сортировки важны особенно при обработке данных [1, 3, 9, 10, 13].
Зависимость выбора алгоритма от структуры данных — явление довольно частое, и в случае сортировки она настолько сильна, что методы сортировки обычно разделяют на две категории: сортировка массивов (внутренняя сортировка) и сортировка файлов (внешняя сортировка). Массивы обычно располагаются в оперативной памяти, для которой характерен быстрый произвольный доступ; файлы хранятся в более медленной, но более вместительной внешней памяти, на дисках.
Введем некоторую терминологию [3]. Пусть даны элементы ai,ci2, ...,an. Сортировка означает перестановку элементов в таком порядке а^\, аю., ■■■,^кп-, что при заданной упорядочивающей функции f(x) справедливо отношение
f(axl)<f(axl)<...<f(am).
Обычно упорядочивающая функция не вычисляется, а содержится в виде явной компоненты каждого элемента — поля. Её значение называется ключом элемента. Следовательно, для представления элемента at подходит структурный тип данных:
struct item
{ int key;
описание других компонент;
}; ,
где key — ключ, служащий для идентификации элементов (выбор его типа как int произволен, можно использовать любой тип, для которого задано отношение порядка).
Сортировка массивов.Основное требование к методам сортировки массивов — экономное использование памяти. Это значит, что перестановки элементов нужно выполнять на том же месте оперативной памяти, где они находятся, и что методы, которые пересылают элементы из массива А в массив В, не представляют интереса. Таким образом, выбирая метод сортировки, руководствуясь критерием экономии памяти, классификацию алгоритмов, проводят в соответствии с их эффективностью, т.е. быстродействием. Удобная мера эффективности получается при подсчете числа необходимых сравнений ключей С и пересылок элементов М. Эти параметры зависят от числа сортируемых элементов п. Хорошие алгоритмы сортировки требуют порядка nlogn сравнений.
Рассмотрим вначале простые методы, требующие порядка п сравнений элементов. Методы используются при небольших п.
Методы сортировки массивов можно разбить на три класса [3]:
1) сортировка включениями;
2) сортировка выбором;
3) сортировка обменом.
Сравним эти методы. Используем массив а, описанный следующим образом:
int nambers[n\; .