Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
_Серебряков.doc
Скачиваний:
1
Добавлен:
01.03.2025
Размер:
846.34 Кб
Скачать

7.3. Таблицы символов и таблицы расстановки

Рассмотрим организацию таблицы символов с помощью таблицы

расстановки. Таблица расстановки - это массив указателей на списки

указателей на идентификаторы. В каждый такой список входят указатели

на идентификаторы, имеющие одно значение функции расстановки (рис.

7.3).

Вначале таблица расстановки пуста (все элементы имеют значение

NIL). При поиске идентификатора id вычисляется функция расстановки

H(id) и просматривается линейный список T[H]. Поиск в таблице может

быть описан следующей процедурой:

type Element= record IdenP:integer;

Next:pointer to Element;

end;

Pointer=pointer to Element

function Search(Id):Pointer;

var P:Pointer;

begin P:=T[H(Id)];

loop if P=nil then return(nil)

elsif IdenTab[P^.IdenP]=Id then return(P)

else P:=P^.Next

end end; end;

IdenTab - таблица идентификаторов. Занесение объекта в таблицу

может осуществляться следующей процедурой:

function Insert(Id):Pointer;

var P,H:Pointer;

begin P:=Search(Id);

if P<>nil then return(P)

else H:=H(Id); new(P);

P^.Next:=T[H]; T[H]:=P;

P^.Idenp:=Include(Id);

end;

return(P);

end;

|--| +------+ +------+

H----->| -+-x---->| |----->| |----->

|--| | +-->+------+ +------+

| | | |

|--| | +------------+

| +------+ |

+---| |---+

P-------->+------+

Рис. 7.4.

Процедура Include заносит идентификатор в таблицу

идентификаторов. Алгоритм иллюстрируется рис. 7.4.

7.4. Функции расстановки.

Много внимания было уделено тому, какой должна быть функция

расстановки. Основные требования к ней очевидны: она должна легко

вычисляться и распределять равномерно. Один из возможных подходов

заключается в следующем.

1. По символам строки s определяем положительное целое H.

Преобразование одиночных символов в целые обычно можно сделать

средствами языка реализации. В Паскале для этого служит функция ord, в

Си при выполнении арифметических операций символьные значения

трактуются как целые.

2. Преобразуем H, вычисленное выше, в номер списка, т.е. целое

между 0 и m-1, где m - размер таблицы расстановки, например, взятием

остатка при делении H на m.

Функции расстановки, учитывающие все символы строки, распределяют

лучше, чем функции, учитывающие только несколько символов, например в

конце или середине строки. Но такие функции требуют больше вычислений.

Простейший способ вычисления H - сложение кодов символов строки.

Перед сложением с очередным символом можно умножить старое значение H

на константу q. Т.е. полагаем H0=0, Hi=q*Hi1+ci для 1<=i<=k, k - длина

строки. При q=1 получаем простое сложение символов. Вместо сложения

можно выполнять сложение ci и q*Hi-1 по модулю 2. Переполнение при

выполнении арифметических операций можно игнорировать.

Функция Hashpjw, приведенная ниже [1], вычисляется, начиная с

H=0. Для каждого символа c сдвигаем биты H на 4 позиции влево и

добавляем c. Если какой-нибудь из четырех старших бит H равен 1,

сдвигаем эти 4 бита на 24 разряда вправо, затем складываем по модулю 2

с H и устанавливаем в 0 каждый из четырех старших бит, равных 1.

#define PRIME 211

#define EOS '\0'

int Hashpjw(s)

char *s;

{ char *p;

unsigned H=0, g;

for (p=s; *p != EOS; p=p+1)

{H=(H<<4)+(*p);

if (g = H & 0xf0000000)

{H=H^(g>>24);

H=H^g;

} }

return H%PRIME;

}

Рис. 7.5

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