Открытое хеширование - 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;
}

Объяснение кода листинга программы

  1. Типизированный код написан на C, языке, который позволяет эффективно работать с хеш-таблицами.
  2. Структура info_t объявлена как тип данных для хранения значений в хеш-таблице. Она содержит два поля: value для хранения значения элемента и use для отслеживания занятости/свободности ячейки.
  3. Функция GetTable создает хеш-таблицу заданного размера с использованием функции calloc. Эта функция возвращает указатель на массив структур info_t.
  4. Функция GetHashKey вычисляет первичный ключ для элемента на основе его значения и размера хеш-таблицы. Используется операция модуля % для получения остатка от деления.
  5. Функция GetNextKey вычисляет вторичный ключ в случае коллизии, т.е. когда два разных значения дают одинаковый первичный ключ. Она возвращает следующий индекс в цепочке, начиная с key + 1, и проверяет, не превышает ли он размер хеш-таблицы. Если это так, она возвращает 0, чтобы начать цепочку сначала.
  6. Функция AddToTable добавляет элемент в хеш-таблицу. Она начинает с первичного ключа и последовательно проверяет следующие ключи в цепочке, пока не найдет свободное место или не достигнет конца цепочки. Если свободное место найдено, элемент добавляется в хеш-таблицу.
  7. Функция PrintTable выводит таблицу на экран. Она перебирает все элементы хеш-таблицы и выводит их значения. Если переменная all установлена в true, она выводит все элементы, включая занятые.
  8. Функция GetValue ищет значение в хеш-таблице. Она начинает с первичного ключа и последовательно проверяет следующие ключи в цепочке, пока не найдет искомое значение или не достигнет конца цепочки. Если искомое значение найдено, она возвращает ключ этого элемента. В противном случае она возвращает -1.
  9. Функция LoadTable загружает числа из файла в хеш-таблицу. Она использует функцию fscanf для чтения чисел из файла и функцию AddToTable для добавления каждого числа в хеш-таблицу. Если добавление не удалось, она выводит сообщение об ошибке.
  10. В функции main создается хеш-таблица размером 20 и загружается 15 чисел из файла file.txt. Затем выводятся только занятые элементы хеш-таблицы, а затем все элементы.
  11. Пользователю предлагается ввести искомое значение. Функция GetValue используется для поиска этого значения в хеш-таблице. Если ключ найден, выводится ключ и количество попыток поиска. В противном случае выводится сообщение об ошибке.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

13   голосов , оценка 4 из 5