Study/자료구조,알고리즘

[자료구조] C++ HashTable 구현

게임 만드는 나무꾼 2022. 11. 11. 16:16

 

#pragma once

#include <string>
#include <iostream>

class HashNode
{
private:
	std::string m_Key;
	int m_Value;
	HashNode* m_Next;

public:
	HashNode() :
		m_Next(nullptr)
	{
	}

	HashNode(const std::string& key, int val) :
		m_Key(key),
		m_Value(val),
		m_Next(nullptr)
	{
	}

	HashNode* GetNext()
	{
		return m_Next;
	}

	void SetNext(HashNode* node)
	{
		m_Next = node;
	}

	const std::string& GetKey() const
	{
		return m_Key;
	}

	int GetValue() const
	{
		return m_Value;
	}
};

// 노드를 담을 Linked List 방식의 Bucket
class HashBucket
{
private:
	int m_Size;
	HashNode* m_Head;

public:
	HashBucket()	:
		m_Size(0),
		m_Head(nullptr)
	{
		m_Head = new HashNode;
	}

	~HashBucket()
	{
		HashNode* node = m_Head;
		HashNode* next = nullptr;

		while(node != nullptr)
		{
			next = node->GetNext();
			delete node;
			node = next;
		}
	}

public:
	bool IsEmpty() const
	{
		return m_Size == 0;
	}

	void Push(HashNode* val)
	{
		HashNode* node = m_Head;
		HashNode* next = m_Head->GetNext();

		node->SetNext(val);
		val->SetNext(next);

		++m_Size;
	}

	HashNode* FindNode(const std::string& key) const
	{
		HashNode* node = m_Head;

		while(node != nullptr)
		{
			if (key == node->GetKey())
				break;

			node = node->GetNext();
		}

		return node;
	}

	void DeleteNode(const std::string& key)
	{
		HashNode* node = m_Head;
		HashNode* prev = nullptr;

		while(node != nullptr)
		{
			if (node->GetKey() == key)
			{
				if (prev)
					prev->SetNext(node->GetNext());
				else
					m_Head->SetNext(node->GetNext());

				delete node;
				--m_Size;
				return;
			}

			prev = node;
			node = node->GetNext();
		}
	}

	void Display()
	{
		HashNode* node = m_Head->GetNext();
		while(nullptr != node)
		{
			std::cout << node->GetValue() << " ";
			node = node->GetNext();
		}
	}
};


class HashMap
{
private:
	int m_BucketSize;
	int m_Size;
	HashBucket* m_Bucket;

private:
	int MakeHash(const std::string& key);

public:
	HashMap();
	HashMap(int bucketSize);
	~HashMap();

public:
	void Insert(const std::string& key, int val);
	void Delete(const std::string& key);
	int Find(const std::string& key);
	int operator[] (const std::string& key);
	void Display();
};

 

#include <iostream>
#include "HashMap.h"

// 간단한 해쉬 함수
int HashMap::MakeHash(const std::string& key)
{
	int hash = 401;
	int c;

	for (int i = 0; i < key.length(); ++i)
	{
		hash = ((hash << 4) + static_cast<int>(key[i])) % m_BucketSize;
	}

	return hash;
}

HashMap::HashMap():
	m_BucketSize(16),
	m_Size(0)
{
	m_Bucket = new HashBucket[m_BucketSize];
}

HashMap::HashMap(int bucketSize):
	m_BucketSize(bucketSize),
	m_Size(0)
{
	m_Bucket = new HashBucket[m_BucketSize];
}

HashMap::~HashMap()
{
	delete[] m_Bucket;
}

void HashMap::Insert(const std::string& key, int val)
{
	int hash = MakeHash(key);

	// 키가 같은 노드가 있는지 찾는다.
	HashNode* overlap = m_Bucket[hash].FindNode(key);

	// 중복 허용 X
	if (nullptr != overlap)
		return;

	// Bucket에 넣는다.
	m_Bucket[hash].Push(new HashNode(key, val));
}

void HashMap::Delete(const std::string& key)
{
	int hash = MakeHash(key);

	m_Bucket[hash].DeleteNode(key);
}

int HashMap::Find(const std::string& key)
{
	int hash = MakeHash(key);

	HashNode* find = m_Bucket[hash].FindNode(key);

	if (nullptr == find)
		return -1;

	return find->GetValue();
}

int HashMap::operator[](const std::string& key)
{
	int hash = MakeHash(key);

	HashNode* find = m_Bucket[hash].FindNode(key);

	if (nullptr == find)
		return -1;

	return find->GetValue();

}

void HashMap::Display()
{
	for(int i = 0; i < m_BucketSize; ++i)
		m_Bucket[i].Display();

	std::cout << "\n";
}

Chaining 방식으로 구현했다.