Реализация хеш-таблицы

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

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <time.h>
#include <cstring>
#include <unordered_map>

using namespace std;

long long generateRandLong() { //генератор большого(12 цифрового) ключа для хеш-функции
    
    int num = 12;
    long long a = 1;
    long long r = 0;
    for (int i = 0; i < num; i++)
    {
        if (i == (num - 1))
        {
            r += a * ((long long)(rand() % 9) + 1);
            break;
        }
        r += a * (rand() % 10);
        a *= 10;
    }
    return r;
    
}

struct Data { // структура данных 
    char name[10];
    int amountOfStudents;
    bool turnstiles;

    Data() {  // генератор случайных данных для структуры Data
        char* name1 = new char[10];
        for (int i = 0; i < 9; i++)
        {
            name1[i] = 'a' + rand() % 26;
        }
        name1[9] = '\0';
        strcpy(name, name1);

        this->amountOfStudents = rand() % 30;
        this->turnstiles = rand() % 2;
        delete[] name1;
        name1 = nullptr;
    }
        Data(const char a[], int b, bool c){ // конструктор Data
            strncpy(name, a, 10);
            amountOfStudents = b;
            turnstiles = c;
        }

    
};

struct HashNode { узел, необходимый для реализации односвязного списка
    long long key;
    Data data;
    HashNode* next;
    HashNode(Data data, long long key, HashNode* next) {
        this->data = data;
        this->key = key;
        this->next = next;
    }

};

struct LinkedList { // односвязный список для каждой ячейки в массиве
    
    HashNode* head = NULL;
    HashNode* tail = NULL;

    void push_back(Data data, long long key) // метод, необходимый для "insert" в таблицу
    {
        HashNode* newHashNode = new HashNode(data, key, NULL);

        if (head == NULL)
        {
            head = newHashNode;
            tail = newHashNode;
        }
        else
        {
            tail->next = newHashNode;
            tail = newHashNode;
        }
    }
};

struct HashTable { // сама хеш-таблица
    int m = 8;
    LinkedList* bucketsArray = new LinkedList[m];
    
    const int alpha = 2;
    int realsize = 0;
    float LoadFactor = 3;
    
    int hash(long long key) { // хеш-функция
        //cout << key % m << endl;
        return key % m;
    }
    
    void insert(long long key, Data value) // добавление элемента в таблицу
    {
        
        if (LoadFactor < ((float)realsize / m))
        {
            m *= alpha;
            LinkedList* NewbucketsArray = new LinkedList[m];
            for (int i = 0; i < m / alpha; i++)
            {
                NewbucketsArray[i] = bucketsArray[i];
            }
            delete[] bucketsArray;
            bucketsArray = NewbucketsArray;
        }
        int index = hash(key);
        HashNode* currentNode = bucketsArray[index].head;
        while (currentNode != NULL) {
            if (currentNode->key == key) {
                currentNode->data = value;
                return;
            }
            currentNode = currentNode->next;
        }
        
        bucketsArray[index].push_back(value, key);
        
        realsize++;
    }

    Data* find(long long key) // поиск элемента по таблице
    {
        int index = hash(key);
        HashNode* currentNode = bucketsArray[index].head;
        if (currentNode == NULL)
        {
            //cout << "There is no such an element with such a key" << endl;
            return NULL;
        }
        if (currentNode->key == key)
        {
            return &currentNode->data;
        }
        
        while (currentNode != NULL)
        {
            if (currentNode->key == key)
                return &currentNode->data;
            currentNode = currentNode->next;
        }
        return NULL;
    }
    Data erase(long long key) // удаление элемента из таблицы
    {
        int index = hash(key);
        if(bucketsArray[index].head == NULL)
        {
            //cout << "There is no such an element in the list" << endl;
            Data a("\0", 0, 0);
            return a;
        }
        else
        {
            HashNode* tempNode = bucketsArray[index].head;
            if (tempNode->key == key)
            {
                if (tempNode->next == NULL)
                {
                    
                    bucketsArray[index].head = NULL;
                    Data a = tempNode->data;
                    delete tempNode;
                    realsize--;
                    return a;
                }
                
                bucketsArray[index].head = bucketsArray[index].head->next;
                Data a = tempNode->data;
                delete tempNode;
                realsize--;
                return a;
            }
            
            HashNode* prevNode = bucketsArray[index].head;
            HashNode* currentNode = bucketsArray[index].head->next;
            while (currentNode != NULL)
            {
                if (currentNode->key == key)
                    break;
                
                prevNode = currentNode;
                currentNode = currentNode->next;
            }
            if (currentNode == NULL)
            {
                //cout << "There is no such an element with such a key" << endl;
                Data a("\0", 0, 0);
                return a;
            }
            prevNode->next = currentNode->next;
            realsize--;
            Data a = currentNode->data;
            delete currentNode;
            return a;
        }
    }

    int size() // размер таблицы
    {
        return realsize;
    }
};



bool testHashTable() // сравнение моей таблицы с unordered_map
{
    const int iters = 500000;
    const int keysAmount = iters * 1;
    // generate random keys:
    long long* keys = new long long[keysAmount];
    long long* keysToInsert = new long long[iters];
    long long* keysToErase = new long long[iters];
    long long* keysToFind = new long long[iters];
    for (int i = 0; i < keysAmount; i++)
    {
        keys[i] = generateRandLong();
    }
    for (int i = 0; i < iters; i++)
    {
        keysToInsert[i] = keys[generateRandLong() % keysAmount];
        keysToErase[i] = keys[generateRandLong() % keysAmount];
        keysToFind[i] = keys[generateRandLong() % keysAmount];
    }
    // test my HashTable:
    HashTable hashTable;
    clock_t myStart = clock();
    for (int i = 0; i < iters; i++)
    {
        hashTable.insert(keysToInsert[i], Data());
    }
    int myInsertSize = hashTable.size();
    for (int i = 0; i < iters; i++)
    {
        hashTable.erase(keysToErase[i]);
    }
    int myEraseSize = hashTable.size();
    int myFoundAmount = 0;
    for (int i = 0; i < iters; i++)
    {
        if (hashTable.find(keysToFind[i]) != NULL)
        {
            myFoundAmount++;
        }
    }
    clock_t myEnd = clock();
    float myTime = (float(myEnd - myStart)) / CLOCKS_PER_SEC;
    // test STL hash table:
    unordered_map<long long, Data> unorderedMap;
    clock_t stlStart = clock();
    for (int i = 0; i < iters; i++)
    {
        unorderedMap.insert({ keysToInsert[i], Data() });
    }
    int stlInsertSize = unorderedMap.size();
    for (int i = 0; i < iters; i++)
    {
        unorderedMap.erase(keysToErase[i]);
    }
    int stlEraseSize = unorderedMap.size();
    int stlFoundAmount = 0;
    for (int i = 0; i < iters; i++)
    {
        if (unorderedMap.find(keysToFind[i]) != unorderedMap.end())
        {
            stlFoundAmount++;
        }
    }
    clock_t stlEnd = clock();
    float stlTime = (float(stlEnd - stlStart)) / CLOCKS_PER_SEC;
    cout << "My HashTable:" << endl;
    cout << "Time: " << myTime << ", size: " << myInsertSize << " - " << myEraseSize << ", found amount: " << myFoundAmount << endl;
    cout << "STL unordered_map:" << endl;
    cout << "Time: " << stlTime << ", size: " << stlInsertSize << " - " << stlEraseSize << ", found amount: " << stlFoundAmount << endl << endl;
    delete [] keys;
    delete [] keysToInsert;
    delete [] keysToErase;
    delete [] keysToFind;
    
    if (myInsertSize == stlInsertSize && myEraseSize == stlEraseSize && myFoundAmount == stlFoundAmount)
    {
        cout << "Сompleted" << endl;
        return true;
    }
    cerr << ":(" << endl;
    return false;
}



int main() {
    srand((unsigned)time(NULL));
    
    testHashTable();
    
    
    return 0;
}

Принцип работы: Создать специальный ключ для каждого элемента, найти индекс для вставки через хеш-функцию и через insert вставить элемент. Если LoadFactor(количество элементов в таблице разделенное на размер массива) меньше 3, то увеличить длину массива в 2 раза. Если под индексом в массиве есть уже данные, то проверить если ключ совпадает, то заменить старые на новые, если нет, то добавить элемент в односвязный список.


Ответы (0 шт):