Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ТП_23_ИСТ_1_1_Какушкина_Ольга_Витальевна_ЛР_5.2

.docx
Скачиваний:
0
Добавлен:
23.06.2025
Размер:
232.86 Кб
Скачать

МИНОБРНАУКИ РОССИИ

Ф едеральное государственное бюджетное образовательное учреждение высшего образования

НИЖЕГОРОДСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ

УНИВЕРСИТЕТ им. Р.Е.АЛЕКСЕЕВА

Институт радиоэлектроники и информационных технологий

Кафедра информатики и систем управления

ОТЧЕТ по лабораторной работе №5

(наименование темы проекта или работы)

по дисциплине

Технологии программирования

(наименование дисциплины)

РУКОВОДИТЕЛЬ:

________________ Капранов С. Н.

(подпись) (фамилия, и.,о.)

СТУДЕНТ:

________________ Какушкина О.В

(подпись) (фамилия, и.,о.)

23-ИСТ-1-1

(шифр группы)

Работа защищена «___» ____________

С оценкой ________________________

Нижний Новгород 2024

Текст задания:

Реализовать алгоритмы поиска, вставки, удаления элементов таблицы и распечатки таблицы и метод ре-хэширования таблицы при увеличении размера данных.

Варианта

Ключ

1

СНИЛС

2

Номер телефона

3

Адрес Компании(Страна, Город, Улица, Дом).

4

Фамилия Имя Отчество

Варианта

Хэш-функция

1

функция деления

2

функция умножения

3

функция «середины квадрата»

4

функция свертки (слияния)

5

функции работы со строковыми ключами

Варианта

Метод разрешения коллизий

1

Метод цепочек

2

Квадратичное опробование

3

Использование бинарных деревьев

Варианта

Ключ

Хэш-функция

Метод разрешения коллизий

7

3

2

1

Список функций и структур данных с описанием:

struct Node

Узел для хэш-таблицы, который содержит ключ, значение и указатель на следующий узел. Инициализирует узел с заданным ключом и значением, а также устанавливает next в nullptr.

class HashTable

Реализация хэш-таблицы, использующая метод цепочек для разрешения коллизий. Инициализирует хэш-таблицу заданного размера и создает вектор узлов.

int hashFunction(const string& key)

Параметры:

key: Ключ для которого нужно вычислить хэш.

Возвращает: Индекс в пределах размера таблицы.

Действие: Вычисляет хэш для ключа, используя простую хэш-функцию

int getSize() const

Возвращает: Размер хэш-таблицы.

Действие: Возвращает текущее значение размера таблицы.

vector<Node*>& getTable()

Возвращает: Ссылку на вектор узлов.

Действие: Позволяет получить доступ к вектору узлов хэш-таблицы.

void insert(const string& key, const string& value)

Параметры:

key: Ключ, по которому будет храниться значение.

value: Значение, связанное с ключом.

Действие:  Вставляет новый узел в хэш-таблицу. Если количество элементов превышает порог, вызывается метод rehash

bool isThresholdReached(Node* node)

Параметры:

node: Указатель на узел, с которого начинается подсчет.

Возвращает: true, если количество узлов в цепочке превышает порог.

Действие: Проверяет, превышает ли количество узлов заданный порог.

bool remove(const string& key)

Параметры:

key: Ключ узла для удаления.

Возвращает: true, если узел был удален; false в противном случае.

Действие: Удаляет узел из хэш-таблицы по заданному ключу.

void display()

Действие: Выводит содержимое хэш-таблицы, перечисляя все ключи и значения в каждой цепочке.

bool isHashTableEmpty()

Возвращает: true, если таблица пуста; иначе false.

Действие: Проверяет, есть ли хотя бы один узел в таблице.

void rehash()

Действие: Увеличивает размер таблицы и перераспределяет все существующие узлы по новым индексам.

string search(const string& key)

Параметры:

key: Ключ для поиска.

Возвращает: Значение, связанное с ключом, если найден; иначе сообщение об отсутствии.

Действие: Ищет узел с заданным ключом и возвращает его значение.

void loadFromFile(const string& filename, HashTable& hTable)

Параметры:

filename: Имя файла для загрузки данных.

hTable: Ссылка на объект HashTable, в который будут загружены данные.

Действие: Загружает данные из файла в хэш-таблицу в формате "ключ значение".

void saveToFile(const string& filename, HashTable& hTable)

Параметры:

filename: Имя файла для сохранения данных.

hTable: Ссылка на объект HashTable, данные которого будут сохранены.

Действие: Сохраняет все элементы хэш-таблицы в файл в формате "ключ значение".

void appendToFile(const string& filename, HashTable& hTable)

Параметры:

filename: Имя файла для добавления данных.

hTable: Ссылка на объект HashTable, данные которого будут добавлены.

Действие: Добавляет содержимое хэш-таблицы в конец существующего файла без перезаписи.

Программный код:

#include <iostream>

#include <vector>

#include <string>

#include <fstream>

using namespace std;

struct Node {

string key;

string value;

Node* next;

Node(const string& k, const string& v) : key(k), value(v), next(nullptr) {}

};

class HashTable {

private:

vector<Node*> table;

int size;

int threshold = 5;

int elementCount = 0;

int hashFunction(const string& key) {

const int multiplier = 31;

long long hash = 0;

for (char c : key) {

hash = hash * multiplier + c;

}

return hash % size;

}

public:

HashTable(int initialSize = 4) : size(initialSize) {

table.resize(size, nullptr);

}

int getSize() const {

return size;

}

vector<Node*>& getTable() {

return table;

}

void insert(const string& key, const string& value) {

if (key.empty() || value.empty()) {

cout << "Ключ или значение не могут быть пустыми!" << endl;

return;

}

int idx = hashFunction(key);

Node* newNode = new Node(key, value);

elementCount++; // Увеличиваем общее количество элементов

// Проверяем, достигнут ли порог

if (elementCount >= threshold) {

rehash();

}

if (table[idx] == nullptr) {

table[idx] = newNode;

}

else {

Node* current = table[idx];

while (current->next != nullptr) {

current = current->next;

}

current->next = newNode;

}

}

bool isThresholdReached(Node* node) {

int count = 0;

while (node != nullptr) {

count++;

node = node->next;

}

return count >= threshold;

}

bool remove(const string& key) {

int idx = hashFunction(key);

Node* current = table[idx];

Node* prev = nullptr;

while (current != nullptr) {

if (current->key == key) {

if (prev == nullptr) {

table[idx] = current->next;

}

else {

prev->next = current->next;

}

delete current;

cout << "Компания успешно удалена." << endl;

return true;

}

prev = current;

current = current->next;

}

cout << "Компания не найдена для удаления." << endl;

return false;

}

void display() {

cout << "\nХэш-таблица с методом цепочек (для коллизий):\n";

for (int i = 0; i < size; ++i) {

cout << "Индекс " << i << ": ";

Node* current = table[i];

while (current != nullptr) {

cout << "(" << current->key << ", " << current->value << ") -> ";

current = current->next;

}

cout << "nullptr" << endl;

}

if (isHashTableEmpty()) {

cout << "Хэш-таблица пуста." << endl;

}

}

bool isHashTableEmpty() {

for (Node* node : table) {

if (node != nullptr) {

return false;

}

}

return true;

}

void rehash() {

vector<Node*> oldTable = table;

size *= 2; // Увеличиваем размер таблицы

table.clear();

table.resize(size, nullptr);

elementCount = 0; // Сбрасываем количество и заново будем считать

for (Node* oldNode : oldTable) {

Node* current = oldNode;

while (current != nullptr) {

// Сохраняем следующий элемент

Node* temp = current->next;

// Вычисляем новый индекс для текущего узла

int idx = hashFunction(current->key);

// Вставляем узел в новую таблицу по новому индексу

current->next = table[idx];

table[idx] = current;

// Увеличиваем счетчик элементов

elementCount++;

current = temp; // Переходим к следующему узлу

}

}

cout << "Хэш-таблица успешно ре-хеширована!" << endl;

}

string search(const string& key) {

int idx = hashFunction(key);

Node* current = table[idx];

while (current != nullptr) {

if (current->key == key) {

return current->value;

}

current = current->next;

}

return "Компания не найдена";

}

};

void loadFromFile(const string& filename, HashTable& hTable) {

ifstream file(filename);

if (!file.is_open()) {

cout << "Ошибка открытия файла." << endl;

return;

}

string key, value;

while (file >> key >> value) {

hTable.insert(key, value);

}

file.close();

}

void saveToFile(const string& filename, HashTable& hTable) {

ofstream file(filename);

if (!file.is_open()) {

cout << "Ошибка открытия файла." << endl;

return;

}

for (int i = 0; i < hTable.getSize(); ++i) {

Node* current = hTable.getTable()[i];

while (current != nullptr) {

file << current->key << " " << current->value << endl;

current = current->next;

}

}

file.close();

}

void appendToFile(const string& filename, HashTable& hTable) {

ofstream file(filename, ios_base::app); // Открываем в режиме добавления

if (!file.is_open()) {

cout << "Ошибка открытия файла." << endl;

return;

}

for (int i = 0; i < hTable.getSize(); ++i) {

Node* current = hTable.getTable()[i];

while (current != nullptr) {

file << current->key << " " << current->value << endl;

current = current->next;

}

}

file.close();

}

int main() {

setlocale(LC_ALL, "Russian");

HashTable hTable;

int choice;

string key, value;

string filename = "C:/comp.txt";

loadFromFile(filename, hTable);

while (true) {

cout << "\nМеню:\n"

<< "1. Добавить компанию\n"

<< "2. Найти компанию\n"

<< "3. Удалить компанию\n"

<< "4. Вывести содержимое\n"

<< "5. Сохранить данные в файл\n"

<< "6. Перезаписать данные в файл\n"

<< "7. Загрузить данные из файла\n"

<< "8. Выйти\n";

cin >> choice;

switch (choice) {

case 1:

cout << "Введите адрес компании: ";

cin.ignore();

getline(cin, key);

cout << "Введите название компании: ";

getline(cin, value);

hTable.insert(key, value);

break;

case 2:

cout << "Введите адрес для поиска компании: ";

cin.ignore();

getline(cin, key);

cout << "Результат поиска: " << hTable.search(key) << endl;

break;

case 3:

cout << "Введите адрес компании для удаления: ";

cin.ignore();

getline(cin, key);

if (hTable.remove(key)) {

cout << "Компания успешно удалена." << endl;

}

else {

cout << "Компания не найдена для удаления." << endl;

}

break;

case 4:

hTable.display();

break;

case 5:

saveToFile(filename, hTable);

cout << "Данные успешно сохранены в файл." << endl;

break;

case 6:

appendToFile(filename, hTable);

cout << "Данные успешно добавлены в файл." << endl;

break;

case 7:

loadFromFile(filename, hTable);

cout << "Данные успешно загружены из файла." << endl;

break;

case 8:

return 0;

default:

cout << "Неверный ввод. Попробуйте снова." << endl;

}

}

return 0;

}

Файл:

Вывод в консоли:

Ввод с клавиатуры и чтение из файла

Вывод:

Данная лабораторная работа над проектом хэш-таблицы помогла углубить знания о структурах данных и алгоритмах. Реализация хэш-таблицы с учетом методов разрешения коллизий и динамического изменения размера представляет собой важный шаг в понимании более сложных систем хранения и обработки данных. Использование методов, таких как ре-хеширование и функции хэширования, значительно улучшает эффективность и производительность работы с большими объемами информации.