임의의 길이의 데이터를 고정된 길이의 데이터로 매핑하는 함수
아래와 같이 어떤 길이의 키 값이 들어오더라도 두자리 숫자로 반환되는 것을 확인할 수 있으며, 한 번 변화된 결과값에 대해서는 어떤 입력값을 넣었는지 찾는 것이 어렵다.
Hash함수를 사용하여 평균 O(1) 시간 복잡도로 특정 값을 신속하게 찾는 자료구조
array에서 for문을 순회하는 것이 아니라 바로 인덱스에 접근하기 때문에 신속하게 찾을 수 있다.
만약에 key가 같은 hash값을 가리키고 있다고 하면, 기존에 저장되어 있는 값 때문에 저장이 되지 않거나 해당 값이 이미 저장이 되었다고 판단할 수도 있기 때문에 충돌이 일어날 수 있다.
hash는 key와 value로 이루어진 객체들을 다루는 자료구조이기 때문에 Element 클래스가 필요하다.
class Element {
constructor(key, value) {
this.key = key;
this.value = value;
}
}
미리 정의해 둔 HASH_SIZE를 넣어 새로운 테이블 객체를 만들어준다.
class HashTable {
constructor() {
this.table = new Array(HASH_SIZE);
this.length = 0;
}
}
가장 중요한 함수 중 하나인 hashCode, 즉 해시코드를 만드는 함수이다.
각자의 글자의 char코드를 더해서 전체 hash의 사이즈로 나눈 나머지로 만든다.
hashCode(key) {
let hash = 0;
for (let i = 0; i < key.length; ++i) {
hash += key.charCodeAt(i);
}
return hash % HASH_SIZE;
}
hashcode를 생성한 이후, 그 위치가 undefined일 경우에만 데이터를 추가해 준다.
put(key, value) {
let index = this.hashCode(key);
if (this.table[index] !== undefined) {
return false;
}
this.table[index] = new Element(key, value);
this.length++;
}
간단하게 바로 index로 접근해서 데이터를 가져온다.
get(key) {
return this.table[this.hashCode(key)];
}
데이터가 undefined는 아닌지 확인한 이후, 해당 데이터를 삭제하고, 미리 저장한 데이터를 return 값으로 돌려준다.
remove(key) {
let element = this.table[this.hashCode(key)];
if (element !== undefined) {
delete this.table[this.hashCode(key)];
this.length--;
}
return element;
}
테이블을 기존의 HASH_SIZE로 초기화 시켜주고, 길이 또한 0으로 바꿔준다.
clear() {
this.table = new Array(HASH_SIZE);
this.length = 0;
}
size() {
return this.length;
}
테이블의 길이만큼 탐색한 후 table에 데이터가 존재한다면, array에 저장한 후 return 한다.
getBuffer() {
let array = [];
for (let i = 0; i < this.table.length; i++) {
if (this.table[i]) {
array.push(this.table[i]);
}
}
return array;
}
있는 테이블의 데이터 개수 만큼 print한다.
print() {
for (let i = 0; i < this.table.length; i++) {
if (this.table[i]) {
console.log(`${i} -> ${this.table[i].key} : ${this.table[i].value}`);
}
}
}
여기서 가장 문제점은 HASH_TABLE의 수가 적으면 hash값이 겹칠 수 있고, 이는 데이터가 삭제되거나 중복되는 일이 발생할 수 있다는 것이다. 이것을 loselose hash size**라고 한다.
⇒ 그래서 선형조사법 해시테이블이나, 체이닝 해시테이블을 사용한다.
하지만 해시 함수를 변경해서 찾아내는 방법도 존재한다.
조금이나마 덜 겹치도록 만드는 방법
// djb2 hash size
const HASH_SIZE = 1013;
hashCode(key) {
let hash = 5381; //seed, 모두 값이 소수로 되어있음
for (let i = 0; i < key.length; i++) {
hash = hash * 33 + key.charCodeAt(i);
}
return hash % HASH_SIZE;
}
관련 전체 코드는 Git에 업로드 해두었습니다.
Github_hashTable