Открытое хеширование - C (СИ)
Формулировка задачи:
Создать файл из 15 целых чисел. Написать программу, которая реализует метод открытого хеширования и хеш-функцией, основанной на методе деления с остатком. Занести данные, хранящиеся в файле в хеш-таблицу. Вывести построенную хеш-таблицу на экран. Организовать поиск данных в хеш-таблице. Результаты поиска данных вывести на экран. Также вывести количество проб, которые были затрачены при поиске.
Решение задачи: «Открытое хеширование»
textual
Листинг программы
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> typedef struct info_t { int value; // Значение элемента bool use; // Пометка о использовании/занятости } TInfo; //----------------------------------------------------------------------------- // Формирует таблицу заданного размера TInfo* GetTable(size_t size) { return calloc(size, sizeof(TInfo)); } //----------------------------------------------------------------------------- // Вычисление стартового/первого ключа size_t GetHashKey(size_t size, int value) { return value % size; } //----------------------------------------------------------------------------- // Функция получения вторичного ключа в случае коллизии size_t GetNextKey(size_t size, int key) { return ++key == size ? 0 : key; } //----------------------------------------------------------------------------- // Функция добавления элемента в хеш-таблицу bool AddToTable(TInfo table[], size_t size, int value) { // Получаем первичный ключ int secondKey = GetHashKey(size, value); int baseKey = secondKey; bool isAdd; // Начиная с первичного ключа пытаемся найти свободное место while (table[baseKey].use && ((baseKey = GetNextKey(size, baseKey)) != secondKey)) { ; } // Сможем ли добавить элемент? isAdd = (table[baseKey].use == false); // Если добавление возможно, то добавляем if (isAdd) { table[baseKey].value = value; table[baseKey].use = true; } return isAdd; } //----------------------------------------------------------------------------- // Вывод на экран таблицы. В зависимости от переменной // all выводим либо всю таблицу, либо только заполненные элементы void PrintTable(TInfo table[], size_t size, bool all) { size_t i; for (i = 0; i < size; ++i) { if (all || table[i].use) { printf("[%u:%d] ", i, table[i].value); } } printf("\n"); } //----------------------------------------------------------------------------- // Получаем ключ искомого элемента. Возвращает -1 в случае отрицательного // результата. Если переменная counter задана, то в неё заносится количество // попыток поиска элемента int GetValue(TInfo table[], size_t size, int value, size_t* counter) { // Количество попыток size_t count = 0; // Получаем первичный ключ int secondKey = GetHashKey(size, value); int baseKey = secondKey; // Перебираем элементы таблицы в поисках искомого значение while (table[baseKey].use && table[baseKey].value != value && ((baseKey = GetNextKey(size, baseKey)) != secondKey)) { count++; } // Если искомый элемент был найден, то счётчик итераций // инкрементируем, иначе обнуляем его, ибо и так ясно, // что перебор осуществлялся size раз if ((table[baseKey].use) && (table[baseKey].value == value)) { count++; } else { count = 0; } // Если нужен счётчик if (counter) { *counter = count; } // Возвращаем ключ в случае если счётчик не был обнулён, те // искомое значение было найдено, иначе возвращаем -1 return count ? baseKey : -1; } //----------------------------------------------------------------------------- // Загрузка из файла count чисел и помещение значение в table void LoadTable(FILE* f, TInfo table[], size_t size, size_t count) { int value; while ((count--) && (fscanf(f, "%d", &value) == 1)) { if (AddToTable(table, size, value) == false) { fprintf(stderr, "error: conflict, value %d not added ...\n", value); } } } //----------------------------------------------------------------------------- int main() { const char CFile[] = "file.txt"; // Количество элементов в хеш-таблице const size_t size = 20; // Создаём таблицу TInfo* table = GetTable(size); // Открываем файл FILE* f = fopen(CFile, "r"); if (f == NULL) { perror(CFile); return EXIT_FAILURE; } // Загружаем данные из файла в таблицу LoadTable(f, table, size, 15); fclose(f); // Вывод используемых элементов таблицы printf("only used elements: "); PrintTable(table, size, false); printf("\n"); // Вывод всей хеш-таблицы printf("all elements: "); PrintTable(table, size, true); printf("\n"); int value, key; size_t count; // Просим пользователя ввести искомое значение printf("find value : "); scanf("%d", &value); // Если ключ был найден if ((key = GetValue(table, size, value, &count)) != -1) { // Выводим ключ и количество попыток printf("key %d, attempt %d\n", key, count); } else { // Элемент был не найден fprintf(stderr, "value %d not found ...\n", value); } return EXIT_SUCCESS; }
Объяснение кода листинга программы
- Типизированный код написан на C, языке, который позволяет эффективно работать с хеш-таблицами.
- Структура
info_t
объявлена как тип данных для хранения значений в хеш-таблице. Она содержит два поля:value
для хранения значения элемента иuse
для отслеживания занятости/свободности ячейки. - Функция
GetTable
создает хеш-таблицу заданного размера с использованием функцииcalloc
. Эта функция возвращает указатель на массив структурinfo_t
. - Функция
GetHashKey
вычисляет первичный ключ для элемента на основе его значения и размера хеш-таблицы. Используется операция модуля%
для получения остатка от деления. - Функция
GetNextKey
вычисляет вторичный ключ в случае коллизии, т.е. когда два разных значения дают одинаковый первичный ключ. Она возвращает следующий индекс в цепочке, начиная сkey + 1
, и проверяет, не превышает ли он размер хеш-таблицы. Если это так, она возвращает 0, чтобы начать цепочку сначала. - Функция
AddToTable
добавляет элемент в хеш-таблицу. Она начинает с первичного ключа и последовательно проверяет следующие ключи в цепочке, пока не найдет свободное место или не достигнет конца цепочки. Если свободное место найдено, элемент добавляется в хеш-таблицу. - Функция
PrintTable
выводит таблицу на экран. Она перебирает все элементы хеш-таблицы и выводит их значения. Если переменнаяall
установлена вtrue
, она выводит все элементы, включая занятые. - Функция
GetValue
ищет значение в хеш-таблице. Она начинает с первичного ключа и последовательно проверяет следующие ключи в цепочке, пока не найдет искомое значение или не достигнет конца цепочки. Если искомое значение найдено, она возвращает ключ этого элемента. В противном случае она возвращает -1. - Функция
LoadTable
загружает числа из файла в хеш-таблицу. Она использует функциюfscanf
для чтения чисел из файла и функциюAddToTable
для добавления каждого числа в хеш-таблицу. Если добавление не удалось, она выводит сообщение об ошибке. - В функции
main
создается хеш-таблица размером 20 и загружается 15 чисел из файлаfile.txt
. Затем выводятся только занятые элементы хеш-таблицы, а затем все элементы. - Пользователю предлагается ввести искомое значение. Функция
GetValue
используется для поиска этого значения в хеш-таблице. Если ключ найден, выводится ключ и количество попыток поиска. В противном случае выводится сообщение об ошибке.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д