Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Структуры данных и алгоритмы. Учебное пособие.pdf
Скачиваний:
0
Добавлен:
15.08.2026
Размер:
1 Мб
Скачать

Разрешение коллизии

Разрешать коллизии можно в исходной или в дополнительной таблице. Если коллизия разрешается в исходной таблице, то такая таблица называется таблицей с перемешиванием или с открытой адресацией. В таблицах с перемешиванием применяют линейное (метод последовательных испытаний или проб), случайное или квадратичное рехеширование. Наиболее простой метод – линейное рехеширование, который заключается в том, что функция вторичной расстановки f определяется как

f (ключ, i) = (f(ключ) + i ) mod N,

здесь значение i равно 1, 2, ... , а f(ключ) – это значение, дающее коллизию.

пусто

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

элемент с

 

 

элемент с

NULL

 

 

 

 

 

ключом С1

 

 

ключом С4

 

 

 

 

 

 

 

 

 

 

 

 

 

пусто

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

элемент с

 

 

элемент с

 

 

элемент с

NULL

 

 

ключом С1

 

 

ключом С6

 

 

ключом С8

 

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

элемент с

 

 

элемент с

NULL

 

 

 

 

 

ключом С1

 

 

ключом С6

 

 

 

 

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

 

 

 

 

.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

пусто

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Рис. 4.3.

93

Рехеширование завершается, когда очередная позиция массива с номером f (ключ, i) окажется пустой или равной снова своему начальному значению (в этом случае таблица полна). Линейное рехеширование применяют, если таблица никогда не бывает полностью заполненной (лучше, если она заполнена не более чем на 70%). В случае разрешения коллизии в дополнительной таблице удобно использовать хеширование с цепочками. В таких таблицах элементы, которым соответствует одно и то же хеш-значение, связываются в цепочку – список, а в самом элементе таблицы хранится ссылка на список (см. рис. 4.3).

Операции над таблицами

Основные операции при работе с таблицами:

а) поиск в таблице элемента с заданным ключом. Поиск элемента в таблице заключается в просмотре элементов до тех пор, пока нельзя сделать вывод: есть элемент в таблице или его нет. В неупорядоченной таблице последовательный (линейный) поиск элемента завершается, когда элемент найден или просмотрены все элементы. В последнем случае делаем вывод, что элемента в таблице нет.

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

Различные способы организации таблиц принято сравнивать по числу выполнения в них основных операций и прежде всего по числу операций сравнения. Линейный поиск элемента в таблице в среднем будет выполнен за n / 2 сравнений, максимальное число сравнений n. Общая оценка сложности алгоритма линейного поиска элемента в таб-

лице O(n).

Вупорядоченной таблице кроме последовательного просмотра можно применять бинарный поиск (поиск делением пополам), максимальное число сравнений при котором 1 + log2 n. Общая оценка сложности алгоритма бинарного поиска элемента в таблице O(log n).

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

94

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

При поиске элемента в хеш-таблице вычисляется значение функции расстановки. Если позиция с вычисленным по хеш-функции номером «пуста», то элемента в таблице нет. При непустой позиции, если ключ элемента совпадает с искомым ключом, элемент найден, иначе в таблицах с открытой адресацией необходимо, выполняя рехеширование, продолжать поиск. Для продолжения поиска используется та же функция вторичной расстановки, что и при построении хеш-таблицы. Если допускается операция удаления элемента из хеш-таблицы, то в таблице с перемешиванием надо различать еще одно состояние: элемент удален из таблицы. В хеш-таблицах с цепочками при непустой позиции просматриваем список до тех пор, пока элемент не найден и не просмотрен весь список. Если список просмотрен полностью, то делаем вывод, что элемента в таблице нет.

Время поиска в хеш-таблице без коллизий (таблица с прямой адресацией) постоянно (равно 1) – это время вычисления функции расстановки. Время поиска в таблицах с перемешиванием для метода линейного рехеширования зависит от коэффициента загрузки таблицы k = n / N, среднее число сравнений в этом случае e = (1 - k / 2)(1 - k). В хеш-таблице с цепочками время поиска зависит от длины списка.

б) включение элемента в таблицу. Включение элемента в неупорядоченную таблицу заключается в добавлении элемента в таблицу (если n < N) на очередное свободное место – в конец таблицы. Включению элемента в упорядоченную таблицу предшествует поиск места k для нового элемента с учетом отношения порядка. Затем освобождение этого места (если оно занято) смещением всех последующих элементов с k-го по последний элемент вниз на одну позицию. Таким образом, включение в упорядоченную таблицу требует больше времени, чем в неупорядоченную таблицу.

При включении элемента в хеш-таблицу вычисляется значение функции расстановки. Если позиция с вычисленным по хеш-функции номером «пуста», то элемент помещается в данную позицию, иначе необходимо разрешать коллизию, используя функцию вторичной расстановки.

95

Алгоритм включения элемента в таблицу с открытой адресацией:

i = 0; b = 1;

j = f(ключi); do

{

if (T[j] == "пусто")

{

T[j] = элемент; b = 0;

}

else

{

i = i + 1;

j= (j + i) mod N;

}

} while (i != N && b);

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

При исключении элемента из хеш-таблицы по ключу вычисляется номер его позиции в таблице. Если позиция «не пуста» и ключ элемента, находящегося в этой позиции, совпадает с ключом удаляемого элемента, то чтобы исключить элемент, достаточно сделать данную позицию «пустой» или в таблицах с перемешиванием «удаленной». Если ключи не совпадают, то поиск элемента осуществляется с учетом метода разрешения коллизии.

Примеры операций над таблицей с ключом целого типа:

struct elem

{

char name[15];

96

int m;

};

struct table

{

elem el[N]; int n;

};

1) операция поиск элемента в таблице с однозначным ключом

линейный поиск в неупорядоченной таблице

elem *find1 (table G, int x)

{

int i = 0;

for (i < G.n && G.el[i].m != x; i++); return i == G.n ? NULL : &G.el[i];

}

линейный поиск в упорядоченной таблице (упорядочение по воз-

растанию ключа)

int find2 (table *G, int x, elem *y)

{

int i = 0;

for ( ; i< G->n - 1 && G->el[i].m < x; i++); if (G->el[i].m == x)

{

*y = G->el[i]; return 1;

}

else

return 0;

}

97

бинарный поиск в упорядоченной таблице (упорядочение по воз-

растанию ключа)

int find3 (table G, int x)

{

int l = 0, r = G.n – 1; while (l < r)

{

int c = (l + r) / 2; if (x G.el[c])

r = c; else

l = c + 1;

}

if (G.el[i].m == x) return i;

else

return -1;

}

2) операция включение элемента в упорядоченную таблицу с неоднозначным ключом (линейный поиск места совмещен с освобождением места в таблице):

int InsertTable (table *G, elem x)

{

int i = G->n - 1; if (G->n < N)

{

for ( ; i >= 0 && G->el[i].m > x.m; i--) G->el[i + 1] = G->el[i];

G->el[i + 1] = x; G->n++;

return 1;

}

98

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]