Чтение онлайн

на главную - закладки

Жанры

Фундаментальные алгоритмы и структуры данных в Delphi

Бакнелл Джулиан М.

Шрифт:

begin

inherited Create;

FDispose := aDispose;

if not Assigned(aHashFunc) then

htcError(tdeHashTblNoHashFunc, 'Create');

FHashFunc := aHashFunc;

FTable := TList.Create;

FTable.Count := TDGetClosestPrime(aTableSize);

FNodeMgr := TtdNodeManager.Create(sizeof(THashedItem));

htcAllocHeads(FTable);

FMaxLoadFactor := 5;

end;

destructor TtdHashTableChained.Destroy;

begin

if (FTable <> nil) then begin

Clear;

htcFreeHeads(FTable);

FTable.Destroy;

end;

FNodeMgr.Free;

inherited Destroy;

end;

Созданный

нами диспетчер узлов предназначен для работы с узлами THashItem. Он определяет структуру записей этого типа. Эта структура во многом аналогична структуре записей класса TtdHashLinear, за исключением того, что требуется связное поле и не требуется поле "используется" (все элементы в связном списке "используются" по определению;

удаленные из хеш-таблицы элементы в связном списке отсутствуют).

type

PHashedItem = ^THashedItem;

THashedItem = packed record

hiNext : PHashedItem;

hiItem : pointer;

{$IFDEF Delphi1}

hiKey : PString;

{$ELSE}

hiKey : string;

{$ENDIF}

end;

Конструктор вызывает метод htcAllocHeads для создания первоначально пустой хеш-таблицы. Вот что должно при этом происходить. Каждая ячейка в хеш-таблице будет содержать указатель на односвязный список (поскольку каждая ячейка содержит только указатель, для хранения хеш-таблицы можно воспользоваться TList). Для упрощения вставки и удаления элементов мы выделяем заглавные узлы для каждого возможного связного списка, как было описано в главе 3. Естественно, деструктор должен освобождать эти заглавные узлы - данная операция выполняется при помощи метода htcFreeHeads.

Листинг 7.13. Выделение и освобождение заглавных узлов связных списков

procedure TtdHashTableChained.htcAllocHeads(aTable : TList);

var

Inx : integer;

begin

for Inx := 0 to pred(aTable.Count) do

aTable.List^[Inx] := FNodeMgr.AllocNodeClear;

end;

procedure TtdHashTableChained.htcFreeHeads(aTable : TList);

var

Inx : integer;

begin

for Inx := 0 to pred(aTable.Count) do

FNodeMgr.FreeNode(aTable.List^[Inx]);

end;

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

Листинг 7.14. Вставка нового элемента в хеш-таблицу со связыванием

procedure TtdHashTableChained.Insert(const aKey : string; aItem : pointer );

var

Inx : integer;

Parent : pointer;

NewNode : PHashedItem;

begin

if htcFindPrim(aKey, Inx, Parent) then

htcError(tdeHashTblKeyExists, 'Insert');

NewNode := FNodeMgr.AllocNodeClear;

{$IFDEF Delphi1}

NewNode^.hiKey := NewStr(aKey);

{$ELSE}

NewNode^.hiKey := aKey;

{$ENDIF}

NewNode^.hi Item := aItem;

NewNode^.hiNext := PHashedItem(Parent)^.hiNext;

PHashedItem(Parent)^.hiNext := NewNode;

inc(FCount);

{увеличить

таблицу, если значение коэффициента загрузки превышает максимальное значение}

if (FCount > (FMaxLoadFactor * FTable.Count)) then

htcGrowTable;

end;

Прежде всего, мы вызываем подпрограмму htcFindPrim. Она выполняет такую же операцию, как и htllIndexOf, при использовании линейного зондирования: предпринимает попытку найти ключ и возвращает индекс ячейки, в которой он был найден. Однако этот метод создан с учетом применения связных списков. Если поиск ключа выполняется успешно, метод возвращает значение "истина", а также индекс ячейки хеш-таблицы и указатель на родительский узел элемента в связном списке. Почему родительский? Что ж, если вспомнить сказанное в главе 3, основные операции с односвязным списком предполагают вставку и удаление узла за данным узлом. Следовательно, целесообразнее, чтобы метод htcFindPrim возвращал родительский узел узла, в который выполняется вставка.

Если ключ не найден, метод htcFindPrlm возвращает значение "ложь" и индекс ячейки, в которую нужно вставить элемент, и родительский узел, за которым его можно успешно вставить.

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

Если при этом коэффициент загрузки хеш-таблицы достигает максимального значения, мы расширяем хеш-таблицу.

Как легко догадаться, метод Delete работает аналогично.

Листинг 7.15. Удаление элемента из хеш-таблицы со связыванием

procedure TtdHashTableChained.Delete(const aKey : string);

var

Inx : integer;

Parent : pointer;

Temp : PHashedItem;

begin

{поиск ключа}

if not htcFindPrim(aKey, Inx, Parent) then

htcError(tdeHashTblKeyNotFound, 'Delete');

{удалить элемент и ключ из данного узла}

Temp := PHashedItem(Parent)^.hiNext;

if Assigned(FDispose) then

FDispose(Temp^.hiItem);

{$IFDEF Delphi1}

DisposeStr(Temp^.hiKey);

{$ELSE}

Temp^.hiKey := '';

{$ENDIF}

{разорвать связь с узлом и освободить его}

PHashedItem(Parent)^.hiNext := Temp^.hiNext;

FNodeMgr.FreeNode(Temp);

dec(FCount);

end;

Мы предпринимаем попытку найти ключ (если он не найден, метод генерирует ошибку), а затем избавляемся от содержимого возвращенного элемента и удаляем его из связного списка. Обратите внимание на простоту кода обеих методов, Insert и Delete, обусловленную наличием заглавного узла в каждом связном списке. Не нужно беспокоиться о том, является ли родительский узел нулевым. Метод htcFindPrlm всегда будет возвращать допустимый родительский узел.

Поделиться:
Популярные книги

Сама себе хозяйка

Красовская Марианна
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Сама себе хозяйка

Сердце Дракона. Том 11

Клеванский Кирилл Сергеевич
11. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
6.50
рейтинг книги
Сердце Дракона. Том 11

Первый среди равных. Книга IV

Бор Жорж
4. Первый среди Равных
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Первый среди равных. Книга IV

Неучтенный. Дилогия

Муравьёв Константин Николаевич
Неучтенный
Фантастика:
боевая фантастика
попаданцы
7.98
рейтинг книги
Неучтенный. Дилогия

Мастер Разума IV

Кронос Александр
4. Мастер Разума
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер Разума IV

Авиатор: назад в СССР

Дорин Михаил
1. Авиатор
Фантастика:
попаданцы
альтернативная история
5.25
рейтинг книги
Авиатор: назад в СССР

Кадры решают все

Злотников Роман Валерьевич
2. Элита элит
Фантастика:
боевая фантастика
попаданцы
альтернативная история
8.09
рейтинг книги
Кадры решают все

Плеяда

Суконкин Алексей
Проза:
военная проза
русская классическая проза
5.00
рейтинг книги
Плеяда

Потусторонний. Книга 2

Погуляй Юрий Александрович
2. Господин Артемьев
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Потусторонний. Книга 2

Ученик. Книга 4

Первухин Андрей Евгеньевич
4. Ученик
Фантастика:
фэнтези
5.67
рейтинг книги
Ученик. Книга 4

Законник Российской Империи. Том 3

Ткачев Андрей Юрьевич
3. Словом и делом
Фантастика:
городское фэнтези
альтернативная история
аниме
дорама
5.00
рейтинг книги
Законник Российской Империи. Том 3

Ваше Сиятельство 7

Моури Эрли
7. Ваше Сиятельство
Фантастика:
боевая фантастика
аниме
5.00
рейтинг книги
Ваше Сиятельство 7

Война

Валериев Игорь
7. Ермак
Фантастика:
боевая фантастика
альтернативная история
5.25
рейтинг книги
Война

Младший сын князя. Том 4

Ткачев Андрей Юрьевич
4. Аналитик
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Младший сын князя. Том 4