Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Бичков - Основи сучасного програмування.doc
Скачиваний:
68
Добавлен:
07.03.2016
Размер:
2.67 Mб
Скачать

Розглянемо деякі приклади розв'язання задач.

1. Хеш-таблиці та алгоритми хешування. Як приклад використання структур і списків наведемо програму, що ілюструє роботу з хеш-таблицею. Спочатку розглянемо, що таке хеш-таблиці та загальні принципи роботи з ними. Хеш-таблиця – це спосіб організації даних, що поєднує в собі переваги списків і масивів. Припустимо, що нам необхідно зберігати інформацію про набір деяких рядків, кожному з яких відповідає певний ключ (інший рядок, якась константа тощо). Іншими словами, потрібно зберігати пари

str1 str2 str3 ... strn

key1 key2 key3 ... keyn

Логічно для збереження кожного елемента пари відповідностей вибрати структуру, що матиме принаймні два поля: для збереження рядка та його ключа (корисним буде й поле-покажчик на саму структуру):

struct cell {

struct cell *next; /*покажчик на черговий елемент*/

char* key; /*ключ*/

char* val; /*значення*/

};

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

hashtable[0]->

hashtable[1]->

hashtable[2]->

hashtable[3]->

hashtable[HASHSIZE]->

До одного списку записуватимуться елементи таблиці, для яких однакове значення має спеціальна хеш-функція. Хеш-функція, аналізуючи рядок, повертає деяке ціле значення, що є індексом відповідного елемента масиву покажчиків (hashtable). У найпростішому варіанті значення функції хешування отримується як залишок від ділення суми символьних значень рядка на розмір масиву. При цьому доступ до голови відповідного списку здійснюється моментально: hashtable[hashfunc(...)]. Розмір масиву фіксований (у нашій програмі HASHSIZE дорівнює 21). У загальному випадку його вибір – це досить складне питання, він залежить від розміру таблиці та інших факторів. Наведемо всю програму з коментарями за її окремими блоками:

#include <stdio.h>

#include <string.h> /*прототип для strchr()*/

extern void *malloc(unsigned size);

/*типи ключа та значення: у нашому випадку – це рядки*/

typedef unsigned char uchar;

typedef uchar *VAL; typedef uchar *KEY;

/*Для роботи необхідно реалізувати операції

Int hashfunc(key); int eqkey(key, key);

Void freeval(val); void setval(val, val);

Void freekey(key); void setkey(key, key);

*/

#define HASHSIZE 21 /*обсяг масиву*/

uchar *strudup(const uchar *s){/*створення копії рядка в "купі"*/

uchar *p=(uchar*) malloc(strlen(s)+1); strcpy(p,s); return p;

}

/*одна з можливих хеш-функцій*/

unsigned int hash; /*останнє пораховане значення хеш-функції*/

Int hashfunc(key key){

unsigned int i=0; uchar *keysrc=key;

while(*key){

i=(i<<1)|(i>>15); /*ROL*/

i^=*key++;

}

hash=i% HASHSIZE;

printf("hash(%s)=%d\n", keysrc, hash);

return hash;

}

#define EQKEY(s1, s2) (strcmp(s1, s2)==0)

#define FREEKEY(s) free(s)

#define FREEVAL(s) free(s)

#define SETVAL(at,s) at=strudup(s)

#define SETKEY(at,s) at=strudup(s)

#define KEYFMT "%s"

#define VALFMT "%s"

/*=========== типонезалежна частина ============*/

struct cell {

struct cell *next; /*покажчик на черговий елемент*/

KEY key; /*ключ*/