Hashing์ ๋ฐ์ดํฐ ์ถ๊ฐ์ ๋ฐํ์ ๋น ๋ฅด๊ฒ ํ๊ธฐ ์ํ ๋ฐ์ดํฐ ์ ์ฅ ๊ธฐ์ ์ด๋ค.
Hash table์ด๋ผ๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋๋ฐ, hash table์ ๋ฐ์ดํฐ ์ถ๊ฐ, ์ญ์ , ๋ฐํ์ ๋ฐฐ๋ฌด ๋น ๋ฅด์ง๋ง
์ต์๋ ์ต๋ ๊ฐ์ ๊ตฌํ๋ ๊ฒ๊ณผ ๊ฐ์ ๊ฒ์์ ๋นํจ์จ์ ์ด๋ค.
๐ฉ๐ป๐ป ์ค๋์ Hash table์ด ๋ฌด์์ธ์ง, ํด๋์ค ๊ตฌํ๋ฒ, collision๊ณผ ๊ทธ ํด๊ฒฐ๋ฒ์ ๋ํด ์ดํด๋ณด์.
Hashing ์ด๋
Hash table ์๋ฃ ๊ตฌ์กฐ๋ array๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ค์ด์ง๋ค.
์ด array๋ 0๋ถํฐ ์ ํด์ง ํฌ๊ธฐ์ ์๋ฆฌ๋จผํธ๋ก ๊ตฌ์ฑ๋๋ค. (ํ์์ ๋ฐ๋ผ ํฌ๊ธฐ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค.)
๊ฐ ๋ฐ์ดํฐ ์๋ฆฌ๋จผํธ๋ dictionary ์๋ฃ ๊ตฌ์กฐ์์ ์ดํด๋ดค๋ ๊ฒ๊ณผ ๋น์ทํ๊ฒ ํค(key)๋ก ์ ์ฅ์ด ๋๋ค.
๋ฐ์ดํฐ๋ฅผ hash table์ ์ ์ฅํ ๋, 0๋ถํฐ hash table์ ํฌ๊ธฐ์ ๋์ํ๋ ํค ๊ฐ์ hash function์ผ๋ก ๊ตฌํด์ ์ ์ฅํ๋ค.
hash table์ ํฌ๊ธฐ๋ ์ผ๋ง๋ ์ปค์ผ ํ ๊น? hash table์ array ํฌ๊ธฐ๋ ๋ฐ๋์ prime number (์์)๋ก ์ ํ๋ค.
์ด์์ ์ผ๋ก๋ hash function์ ํตํด ๊ฐ ํค์ ํ๋์ array ์๋ฆฌ๋จผํธ๊ฐ ๋์๋๋ ๊ฒ์ด ์ข๋ค.
ํ์ง๋ง ํ์ค์ ์ผ๋ก๋ ํค ๊ฐ์ผ๋ก ํ ์ ์๋ ์ซ์๋ ์ ํํ ๋ฐ๋ฉด์, ํค์ ๊ฐ์๋ ๋ฌดํํ๋ฏ๋ก ๊ฐ๋ฅํ ํ ํค๋ฅผ array์ ๊ณ ๋ฅด๊ฒ ๋ถํฌํ๋ ๊ฒ์ด๋ค. ๊ณ ๋ฅด๊ฒ ๋ถํฌ๋ฅผ ํ๋ ค๊ณ ํด๋ ๋ ํค๊ฐ ๊ฐ์ hash (hash function์ ๊ฒฐ๊ณผ๊ฐ)์ ๊ฐ์ง ์๋ ์๋ค.
์ด ๊ฒฝ์ฐ "collision(์ถฉ๋)"์ด๋ผ๊ณ ํ๋๋ฐ, ์ถฉ๋์ด ๋ฐ์ํ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ํด๊ฒฐํ ์ง์ ๋ํด ์ดํ์ ์ดํด๋ณด๋๋ก ํ์.
๐๏ธ Hash Table ํด๋์ค
hash table ํด๋์ค์๋ hash ๊ฐ์ ๊ณ์ฐํ ๋ฉ์๋, ๊ฐ์ ์ถ๊ฐํ ๋ฉ์๋, hash table๋ก๋ถํฐ ๊ฐ์ ๊ฐ์ ธ์ค๋ ๋ฉ์๋, ๊ทธ๋ฆฌ๊ณ hash table์ ๋ฐ์ดํฐ ๋ถํฌ๋ฅผ ๋ณด์ฌ์ค ๋ฉ์๋๋ฅผ ํ์๋ก ํฌํจํ ์ ์๋ค.
Hash Function ์ ํ๊ธฐ
hash function์ ๊ณ ๋ฅด๋ ๊ธฐ์ค์ ํค์ ๋ฐ์ดํฐ ํ์ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์๋ค.
modular hashing
ํค๊ฐ ์ ์์ผ ๊ฒฝ์ฐ, ๊ฐ์ฅ ๊ฐ๋จํ hash function์ array ํฌ๊ธฐ์ ํค modulo ๊ฐ์ ๋ฆฌํดํ๋๋ก ํ ์ ์๋ค.
๋ค๋ง ๋ชจ๋ ํค๊ฐ 0์ผ๋ก ๋๋๊ณ array ํฌ๊ธฐ๊ฐ 10์ธ ๊ฒฝ์ฐ์ ๊ฐ์ ์ํฉ์๋ ๋ถ์ ์ ํ ์ ์๊ธฐ ๋๋ฌธ์
array ํฌ๊ธฐ๋ฅผ ์ ํ ๋ ๋ฌด์กฐ๊ฑด ์์์ฌ์ผ ํ๋ค. ๋๋ค์ ์ ์๊ฐ์ด ํค์ผ ๊ฒฝ์ฐ ๋ ๋๊ฒ ํค๋ฅผ ๋ถํฌํ ์ ์๋ค.
๋๋ถ๋ถ์ ๊ฒฝ์ฐ ํค๊ฐ์ด string ํ์ ์ด๋ค. string ํ์ ์ ๋ง๋ hash function์ ๊ตฌํํ ๋๋ ์ข ๋ ์ ์คํด์ผ ํ๋ค.
๊ฐ๋จํ hash function์ผ๋ก ํค์ ๊ฐ ๋ฌธ์์ ASCII ๊ฐ์ ๋ํ ์ ์๋ค.
โผ ์์ ๋ ์ฑ ์ ๊ตฌํ์ ์ฐธ๊ณ ํ์ฌ ํด๋์ค๋ก ์ฌ๊ตฌ์ฑํ์ต๋๋ค!!
class HashTable{
constructor(){
this.table = new Array(137);
}
// console.log ํฌํผ ๋ฉ์๋
print(item){
console.log(item);
}
// key๊ฐ string ํ์
์ผ ๊ฒฝ์ฐ
simpleHash(data){
let total = 0;
for(let i=0; i< data.length; ++i){
total += data.charCodeAt(i);
}
this.print("Hash value: " + data + " -> " + total);
return total % this.table.length;
}
// hash table ๊ฐ ๋ณด์ฌ์ฃผ๊ธฐ
showDistribution(){
let n = 0;
for(let i = 0; i < this.table.length; ++i){
if(this.table[i] != undefined){
this.print(`${i} : ${this.table[i]}`);
}
}
}
// hash table์ ๋ฐ์ดํฐ ์ถ๊ฐ
put(data){
let position = this.simpleHash(data);
this.table[position] = data;
}
}
const names = ["David", "Jennifer", "Donnie", "Raymond",
"Cynthia", "Mike", "Clayton", "Danny", "Jonathan"];;
const hashTable = new HashTable();
for(let i=0; i < names.length; ++i){
hashTable.put(names[i]);
}
hashTable.showDistribution();
/**
Hash value: David -> 488
Hash value: Jennifer -> 817
Hash value: Donnie -> 605
Hash value: Raymond -> 730 // ์ถฉ๋!!
Hash value: Cynthia -> 720
Hash value:: Mike -> 390
Hash value: Clayton -> 730 // ์ถฉ๋!!
Hash value: Danny -> 506
Hash value: Jonathan -> 819
35 : Cynthia
45 : Clayton
57 : Donnie
77 : David
95 : Danny
116 : Mike
132 : Jennifer
134 : Jonathan
*/
ํ์ง๋ง ์์ hash function์ ๊ฒฝ์ฐ ํค ๊ฐ๋ค์ด ๊ณ ๋ฅด๊ฒ ๋ถ๋ฐฐ๋์ด ์์ง ์๋ค.
๊ทธ๋ฆฌ๊ณ names array์ ์๋ ์ด๋ฆ๋ค์ด ๋ชจ๋ ํ ๋น๋์ง ์๋๋ค๋ ๊ฒ๋ ๋ฌธ์ ๋ค.
Raymond์ Clayton์ ๊ฐ ๋ฌธ์๋ฅผ ASCII ์ฝ๋๋ก ๋ณํํ์ฌ ์ซ์๋ฅผ ๋ํ ๊ฐ์ด ๊ฐ์์ ์ถฉ๋์ด ๋ฐ์ํ ๊ฒ์ด๋ค.
Horner's method
์ถฉ๋์ ๋ฐฉ์งํ๊ธฐ ์ํด hashFunction์ ๊ฐ์ ํด๋ณด์.
๋จผ์ hash table array์ ํฌ๊ธฐ๋ 100๋ณด๋ค ํฐ ์์์ฌ์ผ ํ๋ค. 100 ์ด์์ ์์ ์ค์์ ์ถฉ๋์ด ๋ฐ์ํ์ง ์๋ ์ ์ผ ์์ ์ซ์๋ 137์ด๋ผ๋ ๊ฑธ ์ฌ๋ฌ ์คํ์ ํตํด ๋ฐ๊ฒฌํ๋ค. Horner’s method์ด๋ผ๋ ์๊ณ ๋ฆฌ์ฆ์ ํ์ฉํ๋ฉด hash ๊ฐ ๊ณ์ฐ์ ๊ฐ์ ํ ์ ์๋ค.
ASCII ๊ฐ์ผ๋ก ๋ณํํ ๊ฐ๋ค์ ๋ํ๋ ๊ณผ์ ์ ์์์ธ ์์๋ฅผ ๊ณฑํด์ ๋ํด์ฃผ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ ์ ์๋ค.
class HashTable {
constructor() {
this.table = new Array(137);
}
// console.log ํฌํผ ๋ฉ์๋
print(item) {
console.log(item);
}
// key๊ฐ string ํ์
์ผ ๊ฒฝ์ฐ
simpleHash(data) {
let total = 0;
for (let i = 0; i < data.length; ++i) {
total += data.charCodeAt(i);
}
this.print("Hash value: " + data + " -> " + total);
return total % this.table.length;
}
// Horner's method์ ํ์ฉํด ๊ฐ์ ํ hashing function
betterHash(string) {
const H = 37; // base๋ก ์ฐ์ผ ์์
let total = 0;
for (let i = 0; i < string.length; ++i) {
total = H * total + string.charCodeAt(i);
}
total = total % this.table.length;
if (total < 0) {
total += this.table.length - 1;
}
return parseInt(total);
}
// hash table ๊ฐ ๋ณด์ฌ์ฃผ๊ธฐ
showDistribution() {
let n = 0;
for (let i = 0; i < this.table.length; ++i) {
if (this.table[i] != undefined) {
this.print(`${i} : ${this.table[i]}`);
}
}
}
// hash table์ ๋ฐ์ดํฐ ์ถ๊ฐ
put(data) {
// let position = this.simpleHash(data);
let position = this.betterHash(data);
this.table[position] = data;
}
}
const names = ["David", "Jennifer", "Donnie", "Raymond",
"Cynthia", "Mike", "Clayton", "Danny", "Jonathan"];
const hashTable = new HashTable();
for (let i = 0; i < names.length; ++i) {
hashTable.put(names[i]);
}
hashTable.showDistribution();
/**
10 : Mike
12 : Danny
72 : David
73 : Jonathan
88 : Clayton
92 : Raymond
104 : Donnie
109 : Jennifer
133 : Cynthia
*/
Hashing Integer keys
์ง๊ธ๊น์ง๋ string ํ์ ์ ํค๋ก ๊ฐ๋ hash function์ ๋ค๋ค๋ดค๋ค.
์ด๋ฒ์๋ ์ ์ ํ์ ์ hash ํค๋ก ๊ฐ๋ ์์๋ฅผ ์ดํด๋ณด์.
๋ค์๊ณผ ๊ฐ์ด ํ์ ID์ ์ฑ์ ์ ์์์ ์ดํด๋ดค๋ betterHash()์ simpleHash()๋ก ๋น๊ตํ hash table์ ๋ง๋ค์ด๋ณด์.
// ๋๋ค ์ฑ์
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// ํ์ ๋ฐ์ดํฐ
function generateStudentData(arr){
for(let i = 0; i < arr.length ; ++i){
let num = "";
// ํ์ ์ ์ ์์ฑ
for(let j = 1; j <= 9; ++j){
num += Math.floor(Math.random() * 10);
}
num += getRandomInt(50, 100);
// ํ์ ID์ ์ ์ ํ ๋น
arr[i] = num;
}
}
class HashTable {
constructor() {
this.table = new Array(137);
}
// console.log ํฌํผ ๋ฉ์๋
print(item) {
console.log(item);
}
// key๊ฐ string ํ์
์ผ ๊ฒฝ์ฐ
simpleHash(data) {
let total = 0;
for (let i = 0; i < data.length; ++i) {
total += data.charCodeAt(i);
}
this.print("Hash value: " + data + " -> " + total);
return total % this.table.length;
}
// Horner's method์ ํ์ฉํด ๊ฐ์ ํ hashing function
betterHash(string) {
const H = 37; // base๋ก ์ฐ์ผ ์์
let total = 0;
for (let i = 0; i < string.length; ++i) {
total = H * total + string.charCodeAt(i);
}
total = total % this.table.length;
if (total < 0) {
total += this.table.length - 1;
}
return parseInt(total);
}
// hash table ๊ฐ ๋ณด์ฌ์ฃผ๊ธฐ
showDistribution() {
let n = 0;
for (let i = 0; i < this.table.length; ++i) {
if (this.table[i] != undefined) {
this.print(`${i} : ${this.table[i]}`);
}
}
}
// hash table์ ๋ฐ์ดํฐ ์ถ๊ฐ
// put(data) {
// // let position = this.simpleHash(data);
// let position = this.betterHash(data);
// this.table[position] = data;
// }
// ๋ hash function ๋น๊ต๋ฅผ ์ํด type ์ ๋ฐ๋ผ ๋ถ๊ธฐ
put(data,type="betterHash"){
let position = type === "betterHash"? this.betterHash(data): this.simpleHash(data);
this.table[position] = data;
}
}
let numStudents = 10;
let arrSize = 97;
let idLength = 9;
let students = new Array(numStudents);
const print = (item) =>console.log(item);
generateStudentData(students);
for(let i = 0;i<students.length; ++i){
print(students[i].substring(0,8) + " " + students[i].substring(9));
}
/**
//ํ์ID ์ฑ์
03393080 94
55511088 81
80924513 89
16529442 54
71582662 81
02959617 86
75489309 76
04226751 77
22656462 76
99380949 53
*/
print("\n\nData distribution: \n");
let betterHashTable = new HashTable();
let simpleHashTable = new HashTable();
for (let i = 0; i < students.length; ++i) {
betterHashTable.put(students[i],"betterHash");
simpleHashTable.put(students[i],"simpleHash");
}
print("\nbetter hash function:\n");
betterHashTable.showDistribution();
print("\nsimple hash function:\n");
simpleHashTable.showDistribution();
/**
Data distribution:
Hash value: 03393080594 -> 572
Hash value: 55511088981 -> 579
Hash value: 80924513989 -> 586
Hash value: 16529442154 -> 571
Hash value: 71582662781 -> 581
Hash value: 02959617586 -> 586
Hash value: 75489309776 -> 593
Hash value: 04226751777 -> 576
Hash value: 22656462476 -> 578
Hash value: 99380949253 -> 589
better hash function:
0 : 03393080594
10 : 55511088981
13 : 80924513989
14 : 02959617586
15 : 04226751777
46 : 71582662781
60 : 75489309776
82 : 99380949253
108 : 22656462476
131 : 16529442154
simple hash function:
23 : 16529442154
24 : 03393080594
28 : 04226751777
30 : 22656462476
31 : 55511088981
33 : 71582662781
38 : 02959617586
41 : 99380949253
45 : 75489309776
*/
simple hash function์ ์ดํด๋ณด๋ฉด ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ํ ๋น๋์ง ์์๋ค. 10๋ช ์ ํ์ ์ ์๊ฐ ์์ง๋ง collision ๋๋ฌธ์ 9๋ช ์ ์ ์๋ง ํ ๋น๋์๋ค. ๋ฟ๋ง ์๋๋ผ ํค์ ๋ถํฌ๊ฐ ๋ฐ์ง๋์ด ์๋ค๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
๋ฐ๋ฉด better hash function์ ๋ชจ๋ ๋ฐ์ดํฐ๊ฐ ํ ๋น๋์ด ์๊ณ ํค๊ฐ ๊ณ ๋ฅด๊ฒ ๋ถ๋ฐฐ๋์ด ์๋ค๋ ๊ฑธ ์ ์ ์๋ค.
๋ฐ๋ผ์ ํ์ ๊ณผ ๊ด๊ณ์์ด better hash function์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ข๋ค.
Hash table์ ๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ํ์
hash function ์ค ๋ ์ข์ hash ๊ฐ์ ๊ตฌํ๋ ๋ฐฉ์์ ๋ํด ์ดํด๋ดค๋ค.
betterhash function์ ํ์ฉํด ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ put ๊ณผ ๋ฐ์ดํฐ๋ฅผ ํ์ํ๋ get ๋ฉ์๋๋ฅผ ๊ตฌํํด๋ณด์.
class HashTable {
constructor() {
this.table = new Array(137);
}
// console.log ํฌํผ ๋ฉ์๋
print(item) {
console.log(item);
}
// key๊ฐ string ํ์
์ผ ๊ฒฝ์ฐ
simpleHash(data) {
let total = 0;
for (let i = 0; i < data.length; ++i) {
total += data.charCodeAt(i);
}
this.print("Hash value: " + data + " -> " + total);
return total % this.table.length;
}
// Horner's method์ ํ์ฉํด ๊ฐ์ ํ hashing function
betterHash(string) {
const H = 37; // base๋ก ์ฐ์ผ ์์
let total = 0;
for (let i = 0; i < string.length; ++i) {
total = H * total + string.charCodeAt(i);
}
total = total % this.table.length;
if (total < 0) {
total += this.table.length - 1;
}
return parseInt(total);
}
// hash table ๊ฐ ๋ณด์ฌ์ฃผ๊ธฐ
showDistribution() {
let n = 0;
for (let i = 0; i < this.table.length; ++i) {
if (this.table[i] != undefined) {
this.print(`${i} : ${this.table[i]}`);
}
}
}
///////////////////////////////// ๐์ถ๊ฐ /////////////////////////////////
// hash table์ ๋ฐ์ดํฐ ์ถ๊ฐ
put(data) {
// let position = this.simpleHash(data);
let position = this.betterHash(data);
this.table[position] = data;
}
// hash table์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
get(key) {
let position = this.betterHash(key);
return this.table[position];
}
///////////////////////////////// ๐์ถ๊ฐ /////////////////////////////////
}
const print = (item) => console.log(item);
const names = ["David", "Jennifer", "Donnie", "Raymond",
"Cynthia", "Mike", "Clayton", "Danny", "Jonathan"];
const hashTable = new HashTable();
for (let i = 0; i < names.length; ++i) {
hashTable.put(names[i]);
}
hashTable.showDistribution();
print("Retrieving values:");
for (let i = 0; i < names.length; ++i) {
print(names[i] + " -> " + hashTable.get(names[i]));
}
/**
10 : Mike
12 : Danny
72 : David
73 : Jonathan
88 : Clayton
92 : Raymond
104 : Donnie
109 : Jennifer
133 : Cynthia
Retrieving values:
David -> David
Jennifer -> Jennifer
Donnie -> Donnie
Raymond -> Raymond
Cynthia -> Cynthia
Mike -> Mike
Clayton -> Clayton
Danny -> Danny
Jonathan -> Jonathan
*/
Collision ํด๊ฒฐํ๊ธฐ
hash function์ด ๋ ๊ฐ ์ด์์ ๊ฐ์ ๊ฐ์ ํค๋ฅผ ์์ฑํ๋ฉด collision (์ถฉ๋)์ด ๋ฐ์ํ๋ค.
์ถฉ๋์ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ธ "separate chaining" ๊ณผ "linear probing"์ ๋ํด ์ดํด๋ณด์.
Separate Chaining
hash table์ ๊ฐ array ์๋ฆฌ๋จผํธ๋ฅผ array์ ๊ฐ์ ๋ค๋ฅธ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ ์ฅํ๊ณ ,
์ถฉ๋์ด ๋ฐ์ํ ํค์ array์ ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๋ฐฉ์์ผ๋ก 2์ฐจ์ array ๊ตฌ์กฐ๋ก ๋ง๋ค์ด ์ถฉ๋์ ํด๊ฒฐํ ์ ์๋ค.
โผ ์์ ๋ ์ฑ ์ ๊ตฌํ์ ์ฐธ๊ณ ํ์ฌ ํด๋์ค๋ก ์ฌ๊ตฌ์ฑํ์ต๋๋ค!! ์๋ณธ ๋ฌธ์์ ๋ฐฐ์ด์ด ์๋ linked list๋ก ๋์ฒด ๊ตฌํํด๋ดค์ต๋๋ค!!
์ด์ LinkedList๋ฅผ ๋ด๋ถ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ก ํ์ฉํ separate chaining์ ๋ํด ์ดํด๋ณด์.
class LinkedList {
constructor() {
this.head = null;
}
append(data) {
const newNode = new Node(data);
if (this.head === null) {
this.head = newNode;
} else {
let current = this.head;
while (current.next !== null) {
current = current.next;
}
current.next = newNode;
}
}
toString() {
let current = this.head;
let string = '';
while (current !== null) {
string += JSON.stringify(current.data) + ' ';
current = current.next;
}
return string.trim();
}
}
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
class HashTable {
constructor() {
this.table = new Array(137);
for (let i = 0; i < this.table.length; ++i) {
this.table[i] = new LinkedList();
}
}
// console.log ํฌํผ ๋ฉ์๋
print(item) {
console.log(item);
}
// key๊ฐ string ํ์
์ผ ๊ฒฝ์ฐ
simpleHash(data) {
let total = 0;
for (let i = 0; i < data.length; ++i) {
total += data.charCodeAt(i);
}
this.print("Hash value: " + data + " -> " + total);
return total % this.table.length;
}
// Horner's method์ ํ์ฉํด ๊ฐ์ ํ hashing function
betterHash(string) {
const H = 37; // A prime number used as the base
let total = 0;
for (let i = 0; i < string.length; ++i) {
total = H * total + string.charCodeAt(i);
}
total = total % this.table.length;
if (total < 0) {
total += this.table.length - 1;
}
return parseInt(total);
}
// hash table ๊ฐ ๋ณด์ฌ์ฃผ๊ธฐ
showDistribution() {
for (let i = 0; i < this.table.length; ++i) {
if (this.table[i].head !== null) {
this.print(`${i} : ${this.table[i].toString()}`);
}
}
}
// hash table์ ๋ฐ์ดํฐ ์ถ๊ฐ
put(key, value) {
let position = this.betterHash(key);
this.table[position].append({key, value});
}
// hash table์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
get(key) {
let position = this.betterHash(key);
let current = this.table[position].head;
while (current !== null) {
if (current.data.key === key) {
return current.data.value;
}
current = current.next;
}
return undefined;
}
}
const print = item => console.log(item);
const names = ["David", "Jennifer", "Donnie", "Raymond",
"Cynthia", "Mike", "Clayton", "Danny", "Jonathan"];
const hashTable = new HashTable();
for (let i = 0; i < names.length; ++i) {
hashTable.put(names[i], `Value for ${names[i]}`);
}
hashTable.showDistribution();
print("\nRetrieving values:");
for (let i = 0; i < names.length; ++i) {
print(names[i] + " -> " + hashTable.get(names[i]));
}
/**
10 : {"key":"Mike","value":"Value for Mike"}
12 : {"key":"Danny","value":"Value for Danny"}
72 : {"key":"David","value":"Value for David"}
73 : {"key":"Jonathan","value":"Value for Jonathan"}
88 : {"key":"Clayton","value":"Value for Clayton"}
92 : {"key":"Raymond","value":"Value for Raymond"}
104 : {"key":"Donnie","value":"Value for Donnie"}
109 : {"key":"Jennifer","value":"Value for Jennifer"}
133 : {"key":"Cynthia","value":"Value for Cynthia"}
Retrieving values:
David -> Value for David
Jennifer -> Value for Jennifer
Donnie -> Value for Donnie
Raymond -> Value for Raymond
Cynthia -> Value for Cynthia
Mike -> Value for Mike
Clayton -> Value for Clayton
Danny -> Value for Danny
Jonathan -> Value for Jonathan
*/
Linear Probing
linear probing์ open-addressing hashing์ ์์ ์ค ํ๋๋ค.
์ถฉ๋์ด ๋ฐ์ํ๋ฉด ํ๋ก๊ทธ๋จ์ hash table์ ๋ค์ ์์๊ฐ ๋น์ด์๋ ์ง ํ์ธํ๊ณ , ๋น์ด ์์ผ๋ฉด ํค๋ฅผ ํ ๋นํ๋ค.
์ด ๋ฐฉ์์ด ๋์ํ๋ ค๋ฉด ๋น ๊ณต๊ฐ์ด ์ถฉ๋ถํ ์์ ๋งํผ hash table์ด ์ปค์ผ ํ๋ค.
๊ทธ๋ผ separate chaining๊ณผ linear probing ์ค ์ด๋ค ๊ฑธ ์ฌ์ฉํด์ผ ํ ๊น?
array ํฌ๊ธฐ๊ฐ ์ ์ฅํ ์๋ฆฌ๋จผํธ์ ๊ฐ์ ๋ฐ ์ดํ์ผ ๊ฒฝ์ฐ separate chaining์ ์ฌ์ฉํ๊ณ ,
array ํฌ๊ธฐ๊ฐ ์ ์ฅํ ํฌ๊ธฐ์ ์๋ฆฌ๋จผํธ์ ๋ ๋ฐฐ ์ด์์ผ ์ ์๋ ๊ฒฝ์ฐ์๋ linear probing์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
linear probing ํด๋์ค๋ฅผ ๊ตฌํํด๋ณด์.
class HashTable {
constructor() {
this.table = new Array(137);
this.values = [];
}
// console.log ํฌํผ ๋ฉ์๋
print(item) {
console.log(item);
}
// Horner's method์ ํ์ฉํด ๊ฐ์ ํ hashing function
betterHash(string) {
const H = 37; // A prime number used as the base
let total = 0;
for (let i = 0; i < string.length; ++i) {
total = H * total + string.charCodeAt(i);
}
total = total % this.table.length;
if (total < 0) {
total += this.table.length - 1;
}
return parseInt(total);
}
// hash table ๊ฐ ๋ณด์ฌ์ฃผ๊ธฐ
showDistribution() {
for (let i = 0; i < this.table.length; ++i) {
if (this.table[i] != null) {
this.print(`${i} : ${this.table[i]}`);
}
}
}
// hash table์ ๋ฐ์ดํฐ ์ถ๊ฐ
put(key, data) {
let position = this.betterHash(key);
if(this.table[position] == undefined){
this.table[position] = key;
this.values[position] = data;
} else {
while(this.table[position] != undefined){
position++;
}
this.table[position] = key;
this.values[position] = data;
}
}
// hash table์ hash ์์น์์ ํค๊ฐ ์ผ์นํ๋ฉด ์์น์ ํ ๋นํ๊ณ ,
// ์๋๋ผ๋ฉด ํ ๋น๋์ง ์์ ์์น(undefined)๊ฐ ๋์ฌ ๋๊น์ง ๋ฃจํ๋ฅผ ๋๋ค๊ฐ ํ ๋น์ ํ๋ค.
get(key) {
let hash = -1;
hash = this.betterHash(key);
if (hash > -1) {
for (let i = hash; this.table[hash] != undefined; i++) {
if (this.table[hash] == key) {
return this.values[hash];
}
}
}
return undefined;
}
}
const print = item => console.log(item);
const names = ["David", "Jennifer", "Donnie", "Raymond",
"Cynthia", "Mike", "Clayton", "Danny", "Jonathan"];
const hashTable = new HashTable();
for (let i = 0; i < names.length; ++i) {
hashTable.put(names[i], `Value for ${names[i]}`);
}
hashTable.showDistribution();
print("\nRetrieving values:");
for (let i = 0; i < names.length; ++i) {
print(names[i] + " -> " + hashTable.get(names[i]));
}
/**
10 : Mike
12 : Danny
72 : David
73 : Jonathan
88 : Clayton
92 : Raymond
104 : Donnie
109 : Jennifer
133 : Cynthia
Retrieving values:
David -> Value for David
Jennifer -> Value for Jennifer
Donnie -> Value for Donnie
Raymond -> Value for Raymond
Cynthia -> Value for Cynthia
Mike -> Value for Mike
Clayton -> Value for Clayton
Danny -> Value for Danny
Jonathan -> Value for Jonathan
*/
๐ Reference
- Data Structures and Algorithms Using Javaโ Script by Michael McMillian (O’Reilly). Copyright 2014 Michael McMillan, 978-1-449-36493-9
'๐ค data structures & algorithms' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Data Structures & Algorithms with Javascript : Binary Trees and Binary Search Trees (0) | 2024.07.25 |
---|---|
Data Structures & Algorithms with Javascript : Sets (2) | 2024.07.24 |
Data Structures & Algorithms with Javascript : Dictionaries (0) | 2024.07.22 |
Data Structures & Algorithms with Javascript : Linked Lists (0) | 2024.07.21 |
Data Structures & Algorithms with Javascript : Queues (0) | 2024.07.20 |