C++. Функция удаления из хеш-таблицы

362
30 мая 2017, 02:48

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

Структура Item:

#ifndef ITEM_H
#define ITEM_H
#include <string>
using namespace std;
struct Item
{
    Item *next;
    string name;
    int age;
    Item(string n, int a) : name(n), age(a) { }
};
#endif // ITEM_H

Класс Hash

#ifndef HASH_H
#define HASH_H
#include <iostream>
#include <vector>
#include "item.h"
class Hash
{
    private:
            vector<Item*> table;
            int hash(string key);
    public:
            Hash();
            ~Hash();
            void push(string name, int age);
            void dell(string name);
            Item *find(string name);
};
#endif // HASH_H

Его методы:

#include "hash.h"

int Hash::hash(string key)
{
    int hashsum = 0;
    for(size_t i=0; i<key.length(); i++)
        hashsum += key[i];
    return hashsum % table.size();
}
Hash::Hash()
{
    table.resize(50);
    for(size_t i=0; i<table.size(); i++)
        table[i] = nullptr;
}
Hash::~Hash()
{
    table.clear();
}
void Hash::push(string name, int age)
{
    int hash_index = hash(name);
    Item *person = new Item(name, age);
    Item *place = table[hash_index];
    if(!place)
    {
        table[hash_index] = person;
        return;
    }
    while(place->next)
        place = place->next;
    place->next = person;
}
void Hash::dell(string name) // ?
{
    Item *search = this->find(name);
    if(search)
    {
        delete search;
        search = nullptr;
    }
}
Item* Hash::find(string name)
{
    int hash_index = hash(name);
    Item *result = table[hash_index];
    if(!result)
    {
        cout << "Element not found!" << endl;
        return nullptr;
    }
    while(result->name != name)
    {
        if(!result->next)
        {
            cout << "Element not found!" << endl;
            return nullptr;
        }
        result = result->next;
    }
    return result;
}

main-функция:

#include "hash.h"
using namespace std;
int main()
{
    Hash table;
    table.push("John", 20);
    table.push("Li", 18);
    table.push("iL", 55);
    table.push("Simon", 24);
//    Item *search = table.find("Li");
//    if(search) cout << search->age << endl;
    table.dell("John");
    Item *se = table.find("John");
    if(se) cout << se->age << endl;
    return 0;
}
Answer 1

Давайте посмотрим на метод dell.

Item *search = this->find(name);
if (search)
{
    delete search;
    search = nullptr;
}

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

В реальности вы должны удалить найденный Item из односвязного списка (для этого обычно используют двойной указатель или указатель на предыдущий элемент), и возможно, если ваш bucket стал пустым, обнулить соответствующий элемент table.

(Код не даю, задание выглядит как учебное.)

Кроме того, у вашей программы неопределённое поведение из-за того, что вы не инициализируете поле next у Item. Добавьте в конструктор инициализацию:

Item(string n, int a) : name(n), age(a), next(nullptr) { }
Answer 2

Переделал table под вектор листов. Вот что вышло:

Структура Item

#ifndef ITEM_H
#define ITEM_H
#include <string>
#include <iostream>
using namespace std;
struct Item
{
    string name;
    int age;
    Item(string n, int a) : name(n), age(a) { }
};
#endif // ITEM_H

Класс Hash

#ifndef HASH_H
#define HASH_H
#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include "item.h"
class Hash
{
    private:
            vector<list<Item*>* > table;
            int hash(string key);
    public:
            Hash();
            ~Hash();
            void push(string key, int value);
            void pop(string name);
            Item *find(string name);
            void show();
};
#endif // HASH_H

Его методы:

#include "hash.h"

int Hash::hash(string key)
{
    int hashsum = 0;
    for(size_t i=0; i<key.length(); i++)
        hashsum += key[i];
    return hashsum % table.size();
}
Hash::Hash()
{
    table.resize(50);
    for(size_t i=0; i<table.size(); i++)
        table[i] = nullptr;
}
Hash::~Hash()
{
    table.clear();
}
void Hash::push(string key, int value)
{
    int index = hash(key);
    if(!table[index])
    {
        table[index] = new list<Item*>;
        table[index]->push_back(new Item(key, value));
    }
    else
        table[index]->push_back(new Item(key, value));
}
void Hash::pop(string name)
{
    int index = hash(name);
    Item *search = this->find(name);
    if(!table[index] || !search)
    {
        cout << "Element not found!" << endl;
        return;
    }
    table[index]->remove(search);
}
Item *Hash::find(string name)
{
    int index = hash(name);
    if(!table[index])
    {
        cout << "Element not found!" << endl;
        return nullptr;
    }
    auto it = table[index]->begin();
    while(it != table[index]->end())
    {
        if((*it)->name == name)
            return *it;
        it++;
    }
    cout << "Element not found!" << endl;
    return nullptr;
}
void Hash::show()
{
    for(size_t i=0; i<table.size(); i++)
    {
        if(table[i])
        {
            auto it = table[i]->begin();
            while(it != table[i]->end())
            {
                cout << (*it)->name << "\t" << (*it)->age << endl;
                it++;
            }
        }
    }
}

main-функция:

#include "hash.h"
using namespace std;
int main()
{
    Hash table;
    int choice;
    string name;
    int age;
    while(true)
    {
        cout << "\n1. Insert; 2. Find; 3. Delete; 4. Show; 5. Exit;" << endl;
        cout << "Choice: "; cin >> choice;
        switch(choice)
        {
            case 1: {
                        cout << "Name: "; cin >> name;
                        cout << "Age: "; cin >> age;
                        table.push(name, age);
                        break;
                    }
            case 2: {
                        cout << "Name: "; cin >> name;
                        Item *search = table.find(name);
                        if(search) cout << "Age: " << search->age << endl;
                        break;
                    }
            case 3: {
                        cout << "Name: "; cin >> name;
                        table.pop(name);
                        break;
                    }
            case 4: {
                        cout << endl;
                        table.show();
                        break;
                    }
            case 5: { exit(0); break; }
            default: { break; }
        }
    }
    return 0;
}
READ ALSO
Ошибка в QT main.cpp:(.text.startup+0xd6): undefined reference to `vtable for Counter&#39;

Ошибка в QT main.cpp:(.text.startup+0xd6): undefined reference to `vtable for Counter'

Пытаюсь создать тривиальное приложение на QT: от нажатий кнопки увеличивается счетчик, если увеличивается счетчик, отпечатывает текущее...

302
Как считать строку в цикле?

Как считать строку в цикле?

при попытке использовать getline в цикле независимо от n дает ввести строку только один разпомогите исправить

284
Проблемы с кодировкой на ideone

Проблемы с кодировкой на ideone

Как известно, ideone компилирует исходники на Си++ в utf8Однако, мне нужна строка в utf16 (wstring)

276