5、ハッシュテーブル
1.コンセプト
ハッシュテーブルは、マッピング関係を持つデータ構造です。つまり、KEYを指定すると、対応するVALUEを見つけることができます。KEYとVALUEは、エントリ(またはノード)を形成します。
KEYはユニークです。後で追加されたエントリが前のエントリのKEYと等しい場合、新しいVALUEのみが古いVALUEを上書きし、新しいエントリは作成されません。
すべてのエントリを維持するために、配列構造を使用できます。同時に、占有を減らすために连续的内存空间
、単一リンクリスト構造を使用して、同じhashCode値のKEYに対応するエントリを維持できます(パフォーマンスを向上させるために、単一のリンクリストへの変換をバイナリツリーに変更するか、バイナリツリーを単一リンクリストに復元することもできます)
2.一般的な方法
- putは要素をハッシュテーブルに追加します(等しいKEYのエントリは、新しいVALUEが古いVALUEを上書きすることに注意してください)
- 与えられたキーに従って対応する値を見つけます
- 削除指定されたキーに従って、対応するエントリを削除します
3.例
class HashTable<K, V> {
private Entry<K, V>[] table;
private final int length;
private int size;
public HashTable(int length) {
this.length = length;
this.size = 0;
}
public void put(K key, V value) {
if (null == key || null == value) {
throw new NullPointerException();
}
if (null == table) {
@SuppressWarnings("unchecked")
Entry<K, V>[] table = (Entry<K, V>[])new Entry[this.length];
this.table = table;
}
int hash = hash(key);
Entry<K, V> entry = table[hash];
while (null != entry) {
if (entry.key.equals(key)) {
entry.value = value;
return;
}
entry = entry.prev;
}
entry = table[hash];
Entry<K, V> put = new Entry<K, V>(key, value);
table[hash] = put;
put.prev = entry;
this.size++;
}
public V get(K key) {
if (null == key) {
throw new NullPointerException();
}
int hash = hash(key);
Entry<K, V> entry = table[hash];
while (null != entry) {
if (entry.key.equals(key)) {
return entry.value;
}
entry = entry.prev;
}
return null;
}
public boolean remove(K key) {
if (null == key) {
throw new NullPointerException();
}
int hash = hash(key);
Entry<K, V> entry = table[hash];
boolean first = true;
Entry<K, V> next = table[hash];
while (null != entry) {
if (entry.key.equals(key)) {
if (first) {
table[hash] = entry.prev;
} else {
next.prev = entry.prev;
}
this.size--;
return true;
}
entry = entry.prev;
if (first) {
first = false;
} else {
next = next.prev;
}
}
return false;
}
public int size() {
return this.size;
}
private int hash(K key) {
return key.hashCode() % this.length;
}
private static class Entry<K, V> {
private final K key;
private V value;
private Entry<K, V> prev;
private Entry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
return this.key + "=" + this.value;
}
}
@Override
public String toString() {
if (null == table) {
return "{}";
}
StringBuilder sBuilder = new StringBuilder("{");
for (int i = 0; i < this.length; i++) {
Entry<K, V> entry = table[i];
while (null != entry) {
sBuilder.append(entry.toString()).append(',').append(' ');
entry = entry.prev;
}
}
return sBuilder.substring(0, sBuilder.length() - 2) + '}';
}
}