
- •Теоретический раздел лекции Тема 1. Программирование с использованием рекурсии
- •1.1. Cтратегии решения задачи разбиением ее на подзадачи
- •1.2. Программирование рекуррентных соотношений
- •Var z:extended;
- •1.3. Условия окончания рекурсии
- •1.4. О целесообразности использования рекурсии
- •Var I,X,y,z:word;
- •1.5 Правила выбора программной реализации рекуррентных соотношений
- •Тема 2. Задачи перебора вариантов
- •2.1. Модель дерева решений
- •2.2. Задача оптимального выбора (задача о рюкзаке)
- •2.3. Метод полного перебора двоичного дерева
- •Var wt,ct:extended;
- •Var j,k:byte;
- •If k in s then begin
- •Var j:byte;
- •Var j:byte;
- •Var wt1,oct1:byte;
- •2.4. Метод ветвей и границ
- •Var n,I:byte;
- •Var wt1,oct1:Extended;
- •Include(s,I);
- •If I in Sopt then writeln(I,a[I].W,a[I].C);
- •2.5. Эвристические методы
- •Тема 3. Поиск и сортировка массивов записей
- •3.1. Применимость сортировки и поиска
- •3.2. Массив записей и поиск в нем
- •Var m:word;
- •3.3. Сортировки массивов
- •Var c: mas; I,j,k:word;
- •Var m:word;
- •Var I,j:Word;
- •Var I,j,l,r:Word; X:Tk; w:Tzp;
- •Тема 4. Связанные списки с использованием рекурсивных данных
- •4.1. Список, стек, очередь
- •4.2. Списки на основе динамических массивов
- •Inherited create;
- •Var turn:Tlist; с1,c2:Tinf;
- •4.3. Рекурсивные данные и однонаправленные списки
- •Inherited create;
- •Var stec,st1,turn,tr1:Tlist; inf:Tinf;
- •4.4. Начальное формирование, добавление и удаление элементов однонаправленного списка
- •4.5. Разновидности связанных списков
- •Inf:Tinf;
- •Тема 5. Поиск и сортировки на связанных линейных списках
- •5.1. Поиск в однонаправленных списках
- •5.2. Сортировка однонаправленных списков
- •1 3Var Inf:tInf;
- •Тема 6. Использование линейных связанных списков
- •6.1. Вычисления арифметических выражений
- •Var ch,ch1,ch2,chr:char;
- •I:byte;ch,ch1:char;
- •6.2. Сложение больших целых чисел
- •Var u,V,s,t:byte;
- •6.3. Работа с разреженными матрицами
- •Inf:Tinf;
- •Inf:tInf;
- •Var proot,p:Ptree;
- •Var bl:boolean;
- •7.2. Бинарное дерево поиска
- •7.3. Основные операции с бинарным деревом поиска
- •Inf:tInf;
- •Var d1:Tree; c:Tinf; k:Tkey;
- •Var bl:Boolean;
- •Var m:Word;
- •Var p:Ttree; m:Word;
- •Тема 8. Хеширование
- •8.1. Что такое хеширование
- •8.2. Схема хеширования
- •Interface
- •Inf:Tinf;
- •8.4. Другие способы хеширования
- •Практический раздел Указания по выбору варианта
- •Индивидуальные практические работы и контрольные работы
- •Индивидуальная практическая работа №1. Программирование с использованием рекурсии
- •1.1. Понятие рекурсии
- •1.2. Порядок выполнения работы
- •1.2.1. Пример решения задачи
- •Индивидуальная практическая работа №2. Организация однонаправленного списка на основе рекурсивных типов данных в виде стека
- •2.1. Основные понятия и определения
- •Inf:tInf; // информация
- •Контрольная работа №1. Программирование с использованием деревьев на основе рекурсивных типов данных
- •1.1. Понятие древовидной структуры
- •Inf:tInf;
- •1.2. Компонент tTreeView
- •1.3. Бинарное дерево поиска
- •Основные операции с двоичным деревом поиска
- •1.4. Порядок написания программы
- •Inf:tInf;
- •Inherited Free;
- •Var tr:Ttree;
- •1.5. Индивидуальные задания
- •Курсовая работа
- •Литература
8.2. Схема хеширования
Выберем
М
- предельный размер массива записей H
несколько больший чем n
(n<M).
Позиции в массиве будем нумеровать
начиная с нуля. Задача состоит в том,
чтобы подобрать функцию i=h(key),
которая по возможности равномерно
отображает значения ключа key
на интервал
.
Чаще всего используютi=key
mod
M.
В этом случае если K=M
реализуется идеальная расстановка
элементов в хеш-таблице.
Функция h(key) называется функцией расстановки или хеш-функцией. Ввиду того, что число возможных значений ключа K обычно значительно превосходит возможное количество записей K>>n, любая функция расстановки может для нескольких значений ключа давать одинаковое значение позиции i в таблице. Например, если M=10 то для key=1, key=11 и key=101 позиция i=h(key)=1. В этом случае h(key) только определяет позицию, начиная с которой нужно искать запись с ключом key. Поэтому схема хеширования должна включать алгоритм разрешения конфликтов, определяющий порядок действий, если позиция i=h(key) оказывается занятой записью с другим ключом.
Имеется множество схем хеширования различающихся как выбором удачной функции h(key) так и алгоритма разрешения конфликтов. Эффективность решения реальной практической задачи будет существенно зависеть от выбираемой стратегии.
Алгоритм размещения записей в хеш-таблицу содержит следующие действия: сначала ключ key очередной записи отображается на позицию i=h(key) таблицы. Если позиция свободна то в нее размещается элемент с ключом key, если занята то отрабатывается алгоритм разрешения конфликтов, который находит место для размещения данного элемента.
Алгоритм поиска сначала находит по ключу позицию i в таблице, и если ключ не совпадает то последующий поиск осуществляется в соответствии с алгоритмом разрешения конфликтов начиная от позиции i.
Часто ключами таблиц являются не числа, а последовательность букв (строки). При выборе функции i=h(key) важно, чтобы ее значения вычислялись как можно проще и быстрее. Поэтому символьные ключи обычно заменяют целыми числами из некоторого диапазона. Например, если key - слово, то суммой кодов первых 2х-3х букв, если фраза (Ф.И.О.), то сумма кодов первых букв. При написании алгоритма разрешения конфликтов поиск ведут уже по полному слову.
8.3. Хеш-таблица на основе массива связанных списков
Один из самых изящных способов разрешения конфликтов состоит в том, чтобы сохранять записи, отображаемые на одну позицию в связанные стеки. Для этого вводится массив из М указателей на связанные стеки.
Обычно выбирают М - простое число, немного большее чем предполагаемое количество записей.
Хеш-функция выбирается в виде i:=Key mod M.
Работу с таблицей можно организовать посредством класса ТН, представленного на листинге 8.1:
Листинг 8.1
unit Unit2;
Interface
uses . . . . ;
Type
Tkey=Word;
Tinf=record
Fio:string;
key:Word;
end;
Psel=^sel;
sel=record
inf:Tinf;
A:Psel;
end;
Ms=array[0..1] of Psel;
Pms=^Ms;
TH=class(Tobject)
M,n:Word;
sp,sp1:psel;
H:Pms;
Constructor create(M0:word);
Destructor Free(var stringgrid:Tstringgrid);
Procedure Add(Inf:Tinf);
Procedure Read(key:Tkey; var Inf:Tinf);
Procedure Red(key:Tkey; var Inf:Tinf);
end;
implementation
Constructor TH.create(M0:word);
var i:word;
begin Inherited create;
M:=M0; n:=0;
Getmem(H,M*4);
for i:=0 to M-1 do begin H[i]:=Nil;
end;
Destructor TH.Free;// прочесть и удалить все записи
var i,j:word;
begin j:=0;
for i:=0 to M-1 do begin
While H[i]<>Nil do
begin Inc(j);
sp:=H[i];
StringGrid.Cells[0,j]:=sp^.inf.Fio;
StringGrid.Cells[1,j]:=IntToStr(sp^.inf.key);
H[i]:= H[i]^.A;
dispose(sp);
end;
dispose(H[i]); end;
FreeMem(H,4*M);
end;
Procedure TH.Add;// добавить новую запись
begin
i:=inf.key Mod M;
New(p); Inc(n);
p^.Inf:=Inf;
p^.A:=H[i];
H[i]:=p;
end;
Procedure TH.Read;//чтение без удаления
begin
i:=key mod M;
sp:=H[i];
While (sp<>Nil) and (sp^.inf.key<>key) do
sp:=sp^.A;
if sp<>Nil then inf:=sp^.inf
else ShowMessage('ключ не найден');
end;
Procedure TH.Red;//чтение с удалением
begin
i:=key mod M;
sp:=H[i]; sp1:=sp;
While (sp<>Nil) and (sp^.inf.key<>key) do
begin sp1:=sp; sp:=sp^.A end;
if sp<>Nil then begin
inf:=sp^.inf;
if sp1=sp then H[i]:=sp^.A
else sp1^.A:=sp^.A;
dispose(sp); Dec(n);
end
else ShowMessage('ключ не найден');
end;
end.
При освобождении таблицы (TH.Free) все записи считываются в StringGrid и освобождается память, выделенная под них, после этого освобождается память, выделенная под массив указателей. Вместо записи в StringGrid легко организовать запись в файл или Memo.
После описания этого класса работа с хэш-таблицей осуществляется, например, следующим образом:
uses unit2;
{$R *.dfm}
var H1:TH;
M0,n,i:word;