Главная страница
Навигация по странице:

  • "МИРЭА

  • Расскажите о назначении хеш-функции. Алгоритм хеш-функции преобразует уникальный ключ записи в её индекс в таблице. Что такое коллизия

  • Коллизия

  • Открытый адрес

  • Какая проблема, может возникнуть после удаления элемента из хеш-таблицы с открытым адресом и как ее устранить

  • Что определяет коэффициент нагрузки в хеш-таблице

  • Что такое «первичный кластер» в таблице с открытым адресом Первичный кластер

  • Задание 2 сем 2 в2. Отчет по выполнению практического задания 2 По дисциплине Структуры и алгоритмы обработки данных


    Скачать 286.57 Kb.
    НазваниеОтчет по выполнению практического задания 2 По дисциплине Структуры и алгоритмы обработки данных
    Дата20.02.2022
    Размер286.57 Kb.
    Формат файлаdocx
    Имя файлаЗадание 2 сем 2 в2.docx
    ТипОтчет
    #367980




    МИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ

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

    "МИРЭА - Российский технологический университет"

    РТУ МИРЭА






    Отчет по выполнению практического задания №2

    По дисциплине «Структуры и алгоритмы обработки данных»


    Тема:

    Хеширование и организация быстрого поиска данных.





    Выполнил студент



    Бананов Б.Б.

    группа

    БАНБ-АН-АН





    Оглавление




    Тема. Хеширование и организация быстрого поиска данных.

    Цель. Получить навыки по разработке хеш-таблиц и их применении

    Задание


    1. Разработайте приложение, которое использует хеш-таблицу для организации прямого доступа к записям файла, структура записи которого приведена в варианте 17.



    Коллизия обрабатывается в 5 строке функции push:



    Разработайте и реализуйте функции для операций:

    1) Хеш-функцию (метод определите сами).

    2) Прочитать запись из файла и вставки запись в таблицу (запись

    включает: ключ и номер записи с этим ключом в файле).

    3) Удалить запись из таблицы и соответственно из файла.

    4) Найти запись с заданным ключом в файле, используя хеш-таблицу.

    5) Выполнить рехеширование.

    2. Разработайте такие тесты, чтобы возникли коллизии.

    3. Разработайте такие тесты, чтобы требовалось рехеширование.

    4. Заполните файл большим количеством записей. Определите время чтения записи с заданным ключом для первой записи файла, для последней и где-то в середине. Убедитесь (или нет), что время доступа для всех записей одинаково.

    5. Выведите список индексов, которые формируются при вставке элементов в таблицу.

    Разработка программы


    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include

    #include
    using namespace std;

    std::vector split(const std::string& s, char delim) {

    std::stringstream ss(s);

    std::string item;

    std::vector elems;

    if (s.length() < 1) return elems;

    while (std::getline(ss, item, delim)) {

    elems.push_back(item);

    // elems.push_back(std::move(item)); // if C++11 (based on comment from @mchiasson)

    }

    return elems;

    }

    int getNextPrime(int n) {

    while (1) {

    int c = 1;

    n++;

    for (int i = 2; i <= n; i++)

    if (n % i == 0)

    c++;

    if (c == 2)

    return n;

    }

    }

    struct Node {

    int id = -1; //номер читательского

    string name = ""; //фио

    string adress = ""; //адрес

    void output() {

    if (id < 0) {

    printf("(Пусто)");

    return;

    }

    if (isDeleted) {

    printf("(УДАЛЕНО)");

    return;

    }

    printf("(Номер читательского: %d, ФИО: ", id);

    cout << name;

    cout << ", Адрес: ";

    cout << adress;

    cout << ")";

    cout << " Позиция в файле: ";

    cout << position;

    }

    int position = -1;

    bool isFree = true;

    bool isDeleted = false;
    friend bool operator!= (Node n1, Node n2) {

    return n1.id != n2.id;

    }

    friend bool operator== (Node n1, Node n2) {

    return n1.id == n2.id;

    }

    };
    class HashTable {

    //открытая адресация

    int size = 11; //размер таблицы

    int amountItemsExisting = 0; //количество элементов в таблице

    int amountItemsDeleted = 0; //кол-во удалённых элементов в таблице

    int step = 1; //смещение

    vector table;

    public:

    //рехэширование таблицы

    void rehash() {

    amountItemsDeleted = 0;

    if (isOverflow()) size *= 2;

    amountItemsExisting = 0;

    vector temp(table);

    table.clear();

    table.resize(size);

    while (!(temp.empty())) {

    Node node = temp.back();

    temp.pop_back();

    if (node.isFree) continue;

    if (node.isDeleted) continue;

    push(node);

    }

    }

    private:

    public:

    HashTable() {

    table.resize(this->size);

    }

    //добавить в таблицу

    void push(Node node) {

    if (node.id < 0) return;

    int key = getHash(node);

    int tableSize = table.size();

    while (!table[key].isFree) {

    key += step;

    key %= tableSize;

    }

    node.isFree = false;

    node.isDeleted = false;

    table[key] = node;

    amountItemsExisting++;

    if (isOverflow()) {

    rehash();

    }

    }

    //удалить из таблицы

    void pop(Node node) {

    int key = getHash(node);

    if (key < 0 || key >= size) return;

    Node& tableNode = table[key];

    tableNode.isDeleted = true;
    amountItemsExisting--;

    amountItemsDeleted++;

    }

    //форматированный вывод таблицы в консоль

    void output() {

    int tableSizeNumbers = log10(table.size());

    for (auto i = 0; i < this->table.size(); i++) {

    Node node = table[i];

    printf(("%3d "), i);

    table[i].output();

    cout << endl;

    }

    }

    //найти запись по ключу

    Node find(int id) {

    int key = getHash(id);

    for (auto i = key; i < table.size(); i++) {

    Node& selNode = table[i];

    if (selNode.isDeleted) continue;

    if (selNode.isFree) break;

    if (selNode.id == id) return selNode;

    }

    Node badNode = Node();

    badNode.id = -1;

    return badNode;

    }
    HashTable() {}
    private:

    //проверка на переполненность

    bool isOverflow() {

    return ((double)amountItemsExisting + amountItemsDeleted) / size > 0.75 ? true : false;

    }

    //хэш-функция(по записи и отдельно по ключу)

    int getHash(Node node) {

    return node.id % size;

    }

    //хэш-функция(по записи и отдельно по ключу)

    int getHash(int id) {

    return id % size;

    }
    };
    class File {

    fstream file;

    ofstream O2File;

    HashTable* hashTable; //хэш-таблица

    vector freeFields;

    string path;

    static const int LINE_LENGTH = 128;

    public:

    void rehash() {

    hashTable->rehash();

    }

    File(string path) {

    this->path = path;

    file.open(path, fstream::out | fstream::in);

    if (!file.is_open()) throw new exception();

    //O2File.open("TEMP." + path, ofstream::out | ofstream::in);

    hashTable = new HashTable();

    this->fillTable();

    }

    //поиск записи по ключу

    Node find(int key) {

    return this->hashTable->find(key);

    }
    void output() {

    this->hashTable->output();

    }
    void add(Node newNode) {

    file.clear();

    if (freeFields.size() > 0) {

    file.seekp(freeFields.front(), ios_base::beg);

    freeFields.erase(freeFields.begin());

    } else {

    file.seekp(0, ios_base::end);

    file << endl;

    }

    newNode.position = file.tellg();

    string msg = (boost::format(string("%-" + to_string(LINE_LENGTH) + "s")) % (boost::format("%d;%s;%s") % newNode.id % newNode.name % newNode.adress)).str();

    file << msg;

    file.flush();

    push(newNode);

    }

    void pop(int key) {

    Node node = hashTable->find(key);

    if (node.id < 0) return;

    hashTable->pop(node);

    clearLine(node.position);

    }
    File() {

    delete hashTable;

    file.close();

    O2File.close();

    }
    private:

    //всорптавка записи в таблицу

    void push(Node newNode) {

    hashTable->push(newNode);

    }

    //заполнение таблицы из файла

    void clearLine(int pos) {

    file.clear();

    if (pos < 0) return;

    file.seekg(pos, ios::beg);

    string line;

    getline(file, line);

    file.clear();

    file.seekp(pos, ios::beg);

    file << string(" ").substr(0, line.length());

    file.flush();

    if (line.length() < 128) return;

    freeFields.push_back(pos);

    }

    void fillTable() {

    string line;

    while (!file.eof() && !file.bad() && !file.fail() && file.good()) {

    //file.clear();

    auto pos = file.tellg();

    file.sync();

    getline(file, line);

    vector elems = split(line, ';');

    if (elems.size() < 3) {

    auto lastPos = file.tellg();

    clearLine(pos);

    file.seekg(lastPos);

    continue;

    }

    Node* node = new Node();

    int id = stoi(elems[0]);

    string name = elems[1];

    string adress = elems[2];
    node->id = id;

    node->name = name;

    node->adress = adress;

    //node->code = buff;

    node->position = pos;

    this->hashTable->push(*node);

    }

    }

    };
    void main() {

    setlocale(LC_ALL, "Russian");

    File* file = new File("database.txt");

    file->output();
    cout << "обновление новой записи" << endl;

    int deletingNumber = 179815;

    Node node = { deletingNumber, "Шампунь", "Вернский, 4" };

    file->add({ 12321+rand()%10, "Вадим", "Горский, 5" });

    file->add(node);

    file->output();

    cout << (boost::format("Удаление записи с номером %d:\n\t") % deletingNumber).str();

    file->find(deletingNumber).output();

    file->pop(deletingNumber);

    cout << endl;

    file->output();

    cout << "Рехеширование:\n";

    file->rehash();

    file->output();

    system("pause");

    }



    Тесты



    Входные данные




    database.txt

    Выводы


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

    Ответы на вопросы


    1. Расскажите о назначении хеш-функции.

    Алгоритм хеш-функции преобразует уникальный ключ записи в её индекс в таблице.

    1. Что такое коллизия?

    Коллизия – это ситуация, когда разным ключам соответствует одно значение хеш-функции.

    1. Что такое «открытый адрес» по отношению к хеш-таблице?

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

    1. Как в хеш-таблице с открытым адресом реализуется коллизия?

    В случае коллизии происходит смещение на ограниченное кол-во ячеек, определяемое определёнными алгоритмами или просто константа(напр. =1)

    1. Какая проблема, может возникнуть после удаления элемента из хеш-таблицы с открытым адресом и как ее устранить?

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

    Решением этой проблемы является добавление метки “удалено”. А очистка от “удалённых” элементов возможно только при рехешировании.

    1. Что определяет коэффициент нагрузки в хеш-таблице?

    Кол-во записей в таблице / максимальный размер таблицы.

    Обычно это значение не должно превышать 0,75.

    1. Что такое «первичный кластер» в таблице с открытым адресом?

    Первичный кластер(или первичная кластеризация) - это явление, которое происходит, когда обработчик коллизий создает условие роста кластера. Обработчик коллизий со смещением 1 из таблицы с открытым адресом способствует первичной кластеризации. Первичная кластеризация порождает длинные пути.

    1. Как реализуется двойное хеширование?

    Помимо хеширования ключа, идёт хеширования смещения для устранения первичной кластеризации.

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


    написать администратору сайта