русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Пошук по таблиці


Дата додавання: 2014-11-28; переглядів: 875.


У цьому розділі, ми напишемо осердя програми пошуку за таблицею, щоб проілюструвати додаткові риси структур. Цей код типовий для того, що можна знайти у функціях по обробці таблиці символів макро-процесору або компілятора. Наприклад, розглянемо твердження#define. Коли ми зустріли рядок на кшталт

#define IN 1

назва IN і її текст заміни 1 буде збережено в таблиці. Пізніше, коли IN з'явиться у виразі на зразок

state = IN;

її замістить 1.

Ми побачимо дві функції, по обробці назв і текстів заміни. install(s,t) реєструє в таблиці назву s і текст заміни t; s із t, це просто символьні ланцюжки. lookup(s) шукає s у таблиці, і повертає покажчик на місце, де його знайдено, або NULL, як такого ланцюжка там немає.

Використовується алгоритм гешованого пошуку — новоприбуле ім'я перетворено на невелике додатнє ціле, яке пізніше використовується як індекс масиву покажчиків. Елемент масиву вказує на початок суцільного списку блоків з описами назв, що відповідають цьому хеш-значенню.NULL означає, що жодне ім'я не відповідає вказаному значенню.

+-----+ +-----+ +-----+

| *--|---->| *--|----->| 0 |

+-----+ | *--|--> | *--|---> назва

| 0 | | *--|--> | *--|---> визначення

+-----+ +-----+ +-----+

| 0 |

+-----+ +-----+

| *--|---->| 0 |

+-----+ | *--|---> назва

| 0 | | *--|---> визначення

+-----+ +-----+

Блок являється списком всередині структури з покажчиками на назву, текст заміни та наступний блок у списку. Наступний нульовий покажчик позначає кінець списку.

struct nlist { /* запис таблиці: */

struct nlist *next; /* наступний запис в ланцюжку */

char *name; /* визначене ім'я */

char *defn; /* текст заміни */

};

Масив покажчиків, це просто

#define HASHSIZE 101

 

static struct nlist *hashtab[HASHSIZE]; /* таблиця покажчиків */

Функція гешування, використовувана обома, lookup та install, додає кожне значення символу ланцюжка до зашифрованої комбінації попередніх, і повертає остаток поділу на розмір гешу. Це не найкраща з можливих функцій гешування, але вона коротка й ефективна.

/* hash: утворює геш-значення для ланцюжка s */

unsigned hash(char *s)

{

unsigned hashval;

 

for (hashval = 0; *s != '\0'; s++)

hashval = *s + 31 * hashval;

return hashval % HASHSIZE;

}

Беззнакова арифметика забезпечує додатнє геш-значення.

Процес гешування видасть початковий індекс для масиву hashtab; якщо ланцюжок існує, його можна буде знайти у списку блоків, які там беруть свій початок. Пошук здійснюється функцієюlookup. Якщо lookup знайде відповідний запис, вона поверне покажчик на нього; якщо ні —NULL.

/* lookup: шукає s у hashtab */

struct nlist *lookup(char *s)

{

struct nlist *np;

 

for (np = hashtab[hash(s)]; np != NULL; np = np->next)

if (strcmp(s, np->name) == 0)

return np; /* знайдено */

return NULL; /* не знайдено */

}

Цикл for функції lookup є стандартною ідіомою проходження вздовж зв'язного списку:

for (ptr = head; ptr != NULL; ptr = ptr->next)

...

функція install використовує lookup, щоб визначити, чи назва, яка додається вже присутня; якщо так, то нове визначення витіснить старе. У протилежному випадку, буде створено новий запис. install поверне NULL, якщо з якоїсь причини не залишилося місця для нового запису.

struct nlist *lookup(char *);

char *strdup(char *);

 

/* install: додає (name, defn) до hashtab */

struct nlist *install(char *name, char *defn)

{

struct nlist *np;

unsigned hashval;

 

if ((np = lookup(name)) == NULL) { /* not found */

np = (struct nlist *) malloc(sizeof(*np));

if (np == NULL || (np->name = strdup(name)) == NULL)

return NULL;

hashval = hash(name);

np->next = hashtab[hashval];

hashtab[hashval] = np;

} else /* already there */

free((void *) np->defn); /*free previous defn */

if ((np->defn = strdup(defn)) == NULL)

return NULL;

return np;

}

Вправа 6-5. Напишіть функцію undef, яка би видаляла назву та визначення з таблиці, утворюваної функціями lookup та install.

Вправа 6-6. Втільте просту версію (без аргументів) оброблювача визначень #define (який можна би було використовувати із C-програмами), основуючись на функціях із цього розділу. Вам можливо доведеться згадати функції getch і ungetch.


<== попередня лекція | наступна лекція ==>
Структури зі зворотнім звертанням | Typedef


Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн