Загрузка данных
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// Размер хеш-таблицы.
// Лучше брать простое число, чтобы было меньше коллизий.
const int SIZE = 31;
// Максимальное количество позиций одного слова в тексте.
const int MAX_POS = 1000;
// Один элемент хеш-таблицы.
// Он хранит слово, позиции этого слова и ссылку на следующий элемент.
struct Node {
string word; // слово
int positions[MAX_POS]; // массив позиций слова в тексте
int count; // сколько раз слово найдено
Node* next; // следующий элемент в цепочке
};
// Хеш-таблица.
// Это массив указателей на элементы Node.
Node* table[SIZE];
// Перевод английских заглавных букв в маленькие.
string toLower(string s) {
for (int i = 0; i < s.length(); i++) {
if (s[i] >= 'A' && s[i] <= 'Z') {
s[i] = s[i] + 32;
}
}
return s;
}
// Хеш-функция.
// Считает сумму кодов символов слова
// и берёт остаток от деления на размер таблицы.
int hashFunc(string word) {
int sum = 0;
for (int i = 0; i < word.length(); i++) {
sum += word[i];
}
return sum % SIZE;
}
// Алгоритм Бойера-Мура.
// Ищет все позиции слова word в тексте text.
// Позиции записываются в массив positions.
// Количество найденных позиций записывается в count.
void boyerMoore(string text, string word, int positions[], int& count) {
count = 0;
int n = text.length(); // длина текста
int m = word.length(); // длина слова
// Если слово пустое или длиннее текста, искать нечего.
if (m == 0 || m > n) {
return;
}
// Таблица смещений.
int shiftTable[256];
// Сначала для всех символов сдвиг равен длине слова.
for (int i = 0; i < 256; i++) {
shiftTable[i] = m;
}
// Для символов, которые есть в слове,
// задаём свои смещения.
for (int i = 0; i < m - 1; i++) {
shiftTable[(unsigned char)word[i]] = m - 1 - i;
}
// pos — позиция в тексте, с которой прикладываем слово.
int pos = 0;
while (pos <= n - m) {
// Сравнение начинаем с последнего символа слова.
int j = m - 1;
// Сравниваем справа налево.
while (j >= 0 && word[j] == text[pos + j]) {
j--;
}
// Если j < 0, значит все символы совпали.
if (j < 0) {
if (count < MAX_POS) {
positions[count] = pos;
count++;
}
// Сдвигаемся на 1, чтобы найти следующие вхождения.
pos++;
} else {
// Если символы не совпали, делаем сдвиг по таблице.
pos += shiftTable[(unsigned char)text[pos + m - 1]];
}
}
}
// Добавление слова в хеш-таблицу.
void addWord(string word, int positions[], int count) {
int index = hashFunc(word);
// Если такое слово уже есть, просто обновляем его позиции.
Node* current = table[index];
while (current != NULL) {
if (current->word == word) {
current->count = count;
for (int i = 0; i < count; i++) {
current->positions[i] = positions[i];
}
return;
}
current = current->next;
}
// Если слова ещё нет, создаём новый элемент.
Node* newNode = new Node;
newNode->word = word;
newNode->count = count;
// Копируем позиции в новый элемент.
for (int i = 0; i < count; i++) {
newNode->positions[i] = positions[i];
}
// Добавляем элемент в начало цепочки.
newNode->next = table[index];
table[index] = newNode;
}
// Поиск слова в хеш-таблице.
Node* searchWord(string word) {
int index = hashFunc(word);
Node* current = table[index];
// Проходим по цепочке в нужной ячейке.
while (current != NULL) {
if (current->word == word) {
return current;
}
current = current->next;
}
return NULL;
}
// Удаление слова из хеш-таблицы.
void deleteWord(string word) {
int index = hashFunc(word);
Node* current = table[index];
Node* previous = NULL;
while (current != NULL) {
if (current->word == word) {
// Если удаляем первый элемент цепочки.
if (previous == NULL) {
table[index] = current->next;
}
// Если удаляем элемент из середины или конца.
else {
previous->next = current->next;
}
delete current;
cout << "Слово удалено" << endl;
return;
}
previous = current;
current = current->next;
}
// Если слова нет в хеш-таблице.
cout << "-1" << endl;
}
// Вывод позиций найденного слова.
void printPositions(Node* node) {
// Если слова нет в таблице или оно не найдено в тексте.
if (node == NULL || node->count == 0) {
cout << "-1" << endl;
return;
}
cout << "Позиции слова в тексте: ";
for (int i = 0; i < node->count; i++) {
cout << node->positions[i] << " ";
}
cout << endl;
}
// Вывод всей хеш-таблицы на экран.
void printHashTable() {
cout << "\nХеш-таблица:" << endl;
for (int i = 0; i < SIZE; i++) {
cout << i << ": ";
Node* current = table[i];
// Если ячейка пустая.
if (current == NULL) {
cout << "пусто";
}
// Если в ячейке есть элементы, выводим цепочку.
while (current != NULL) {
cout << current->word << " [";
if (current->count == 0) {
cout << "-1";
} else {
for (int j = 0; j < current->count; j++) {
cout << current->positions[j];
if (j < current->count - 1) {
cout << ", ";
}
}
}
cout << "]";
// Если есть следующий элемент, показываем цепочку.
if (current->next != NULL) {
cout << " -> ";
}
current = current->next;
}
cout << endl;
}
}
int main() {
setlocale(LC_ALL, "Russian");
// Изначально все ячейки хеш-таблицы пустые.
for (int i = 0; i < SIZE; i++) {
table[i] = NULL;
}
// Открываем входные файлы.
ifstream textFile("text.txt");
ifstream wordsFile("words.txt");
if (!textFile.is_open()) {
cout << "Не удалось открыть файл text.txt" << endl;
return 0;
}
if (!wordsFile.is_open()) {
cout << "Не удалось открыть файл words.txt" << endl;
return 0;
}
string text = "";
string line;
// Считываем весь текст из text.txt в одну строку.
while (getline(textFile, line)) {
text += line + " ";
}
textFile.close();
// Переводим текст в нижний регистр.
text = toLower(text);
string word;
int positions[MAX_POS];
int count;
// Считываем слова из words.txt.
// Для каждого слова ищем позиции и добавляем его в хеш-таблицу.
while (wordsFile >> word) {
word = toLower(word);
boyerMoore(text, word, positions, count);
addWord(word, positions, count);
}
wordsFile.close();
cout << "Хеш-таблица создана." << endl;
int choice;
do {
cout << "\nМеню:" << endl;
cout << "1 - найти слово" << endl;
cout << "2 - добавить слово" << endl;
cout << "3 - удалить слово" << endl;
cout << "4 - вывести хеш-таблицу" << endl;
cout << "0 - выход" << endl;
cout << "Выбор: ";
cin >> choice;
if (choice == 1) {
cout << "Введите слово для поиска: ";
cin >> word;
word = toLower(word);
Node* found = searchWord(word);
printPositions(found);
}
else if (choice == 2) {
cout << "Введите слово для добавления: ";
cin >> word;
word = toLower(word);
// Ищем позиции нового слова в тексте.
boyerMoore(text, word, positions, count);
// Добавляем слово в хеш-таблицу.
addWord(word, positions, count);
cout << "Слово добавлено." << endl;
// Если слово в тексте не найдено, по заданию выводим -1.
if (count == 0) {
cout << "-1" << endl;
} else {
cout << "Позиции слова в тексте: ";
for (int i = 0; i < count; i++) {
cout << positions[i] << " ";
}
cout << endl;
}
}
else if (choice == 3) {
cout << "Введите слово для удаления: ";
cin >> word;
word = toLower(word);
deleteWord(word);
}
else if (choice == 4) {
printHashTable();
}
else if (choice == 0) {
cout << "Выход из программы." << endl;
}
else {
cout << "Ошибка: неверная команда" << endl;
}
} while (choice != 0);
return 0;
}