[SWEA] 7-8. Hash
2.実戦講座
2.1 djb2
djb 2は文字列のhash関数の1つであり、ランダム分布を簡略化することができる.magicnumberと呼ばれる5381および33を使用してhashキーを生成する.
djb 2のコードは以下の通りです.
ハッシュ・テーブルのサイズは、デフォルトではhash関数として現れるhash idxの範囲よりも小さいため、常に競合する可能性があります.競合を解決するには、次の方法を使用します.
2.2.1 Open addressing
競合が発生した場合は、ハッシュ・テーブルの他の場所として保存されます.
2.2.2 Chaining
リンクリストを使用して競合を解決する方法.(主な使い方)
2.2.3効率的なハッシュ関数の使用
データの分布を均一にし、衝突の可能性を低減します.(djb 2の使用を推奨)
2.3適切なハッシュ・テーブル・サイズ
通常は2*Nに最も近い小数または2 mの値を使用します.
それぞれに欠点があるTable sizeとして小数を使用する場合は、より遅い%演算子を使用する必要があります.2 mを使用すると、ビットシールドで高速に計算できます.
しかしhash関数がサブビットを均一に分布できない場合、m未満のサブビットを使用するため、多くの競合が発生する.したがって,良いhash関数を用いることが重要である.
また,2 mはrehashにも有利であるため,JavaはhashMapのsizeを2の繰返し二乗として用いる.
Java: A “prime” number or a “power of two” as HashMap size?
https://stackoverflow.com/questions/15437345/java-a-prime-number-or-a-power-of-two-as-hashmap-size
しかし、小数または2の反復二乗または糖楽には影響しなかった.
便利な方法を使えばいい
10007、20011、30011、4009、10003、200003はよく使われる小数で、小数を使う方は参考にしてください.
2.4実施練習
hashデータ構造におけるメンバー関数の追加、検索、削除の例を直接実現します.
input dataの条件.
1.add最大100000
2.keyは小文字からなる文字列で、長さは2~10です.
3.存在しない鍵が見つかったり削除されたりしていない場合.
2.Chainingはlinklistとして実装される.
3.Single Linked Listは前のノードに戻って削除しています.
4.元のデータ(キーワード文字列)をハッシュにコピーするのは、競合のためです.
競合が発生した場合、2つ以上のノードは同じhash値を有します.
ハッシュ値は通常復号できないため、元のデータはわかりません.
2.1 djb2
djb 2は文字列のhash関数の1つであり、ランダム分布を簡略化することができる.magicnumberと呼ばれる5381および33を使用してhashキーを生成する.
djb 2のコードは以下の通りです.
unsigned long djb2(const char* str)
{
unsigned long hash = 5381; // base
int c;
while (c = *str++)
{
hash = (((hash << 5) + hash) + c); // hash = hash * 33 + ascii code of str[i]
}
return hash % HASH_TABLE_SIZE;
}
2.2 Hash Collision(衝突)ハッシュ・テーブルのサイズは、デフォルトではhash関数として現れるhash idxの範囲よりも小さいため、常に競合する可能性があります.競合を解決するには、次の方法を使用します.
2.2.1 Open addressing
競合が発生した場合は、ハッシュ・テーブルの他の場所として保存されます.
2.2.2 Chaining
リンクリストを使用して競合を解決する方法.(主な使い方)
2.2.3効率的なハッシュ関数の使用
データの分布を均一にし、衝突の可能性を低減します.(djb 2の使用を推奨)
2.3適切なハッシュ・テーブル・サイズ
通常は2*Nに最も近い小数または2 mの値を使用します.
それぞれに欠点があるTable sizeとして小数を使用する場合は、より遅い%演算子を使用する必要があります.2 mを使用すると、ビットシールドで高速に計算できます.
しかしhash関数がサブビットを均一に分布できない場合、m未満のサブビットを使用するため、多くの競合が発生する.したがって,良いhash関数を用いることが重要である.
また,2 mはrehashにも有利であるため,JavaはhashMapのsizeを2の繰返し二乗として用いる.
Java: A “prime” number or a “power of two” as HashMap size?
https://stackoverflow.com/questions/15437345/java-a-prime-number-or-a-power-of-two-as-hashmap-size
しかし、小数または2の反復二乗または糖楽には影響しなかった.
便利な方法を使えばいい
10007、20011、30011、4009、10003、200003はよく使われる小数で、小数を使う方は参考にしてください.
2.4実施練習
hashデータ構造におけるメンバー関数の追加、検索、削除の例を直接実現します.
input dataの条件.
1.add最大100000
2.keyは小文字からなる文字列で、長さは2~10です.
3.存在しない鍵が見つかったり削除されたりしていない場合.
#define HASH_SIZE (1 << 18)
#define MAXN 100000
#define DIV (HASH_SIZE - 1)
typedef unsigned long long ll;
bool strCmp(char a[], char b[]) {
int i = 0;
for (; a[i]; i++) {
if (a[i] != b[i]) {
return false;
}
}
return a[i] == b[i];
}
void strCpy(char dst[], char src[]) {
while (*src) {
*dst++ = *src++;
}
*dst = 0;
}
struct Node {
char key[11];
int data;
Node *next;
Node *alloc(char _key[], int _data, Node *_next) {
strCpy(key, _key);
data = _data;
next = _next;
return this;
}
/* 찾는 node의 바로 이전 node를 반환한다. */
Node *getPrevNode(char _key[]) {
Node *ptr = this;
while (ptr->next) {
if (strCmp(_key, ptr->next->key)) {
break;
}
ptr = ptr->next;
}
return ptr;
}
};
int bCnt;
Node buf[MAXN];
Node hashTable[HASH_SIZE];
void init()
{
bCnt = 0;
for (int i = 0; i < HASH_SIZE; ++i) {
hashTable[i].next = 0;
}
}
int getKey(char str[]) {
ll key = 5381;
for (int i = 0; str[i]; ++i) {
key = ((key << 5) + key) + (str[i] - 'a' + 1);
}
return (int) (key & DIV); // 해당 code에서 hash값은 unsigned long long범위를 초과할 일이 없음.
}
int find(char key[])
{
Node *prevNode;
int target = getKey(key);
prevNode = hashTable[target].getPrevNode(key);
return prevNode->next->data;
}
void add(char key[], int data)
{
int target = getKey(key);
hashTable[target].next = buf[bCnt++].alloc(key, data, hashTable[target].next);
}
int remove(char key[])
{
Node *prevNode, *targetNode;
int target = getKey(key);
prevNode = hashTable[target].getPrevNode(key);
targetNode = prevNode->next;
prevNode->next = targetNode->next;
return targetNode->data;
}
1.Hash tableは通常変数として宣言され、ヘッダーとして使用されます.2.Chainingはlinklistとして実装される.
3.Single Linked Listは前のノードに戻って削除しています.
4.元のデータ(キーワード文字列)をハッシュにコピーするのは、競合のためです.
競合が発生した場合、2つ以上のノードは同じhash値を有します.
ハッシュ値は通常復号できないため、元のデータはわかりません.
Reference
この問題について([SWEA] 7-8. Hash), 我々は、より多くの情報をここで見つけました https://velog.io/@sshin/SWEA-7-8テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol