需求
自己實現一個簡單的散列表,使用平方探測(quadratic probing).
散列表(Hash table,也叫哈希表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表。
給定表M,存在函數f(key),對任意給定的關鍵字值key,代入函數後若能得到包含該關鍵字的記錄在表中的地址,則稱表M爲哈希(Hash)表,函數f(key)爲哈希(Hash) 函數。
代碼
import java.util.StringJoiner;
public class QuadraticProbingHashTable<T> {
public QuadraticProbingHashTable() {
this(DEFAULT_TABLE_SIZE);
}
public QuadraticProbingHashTable(int size) {
allocateArray(size);
makeEmpty();
}
private void makeEmpty() {
currentSize = 0;
for (int i = 0; i < array.length; i++) {
array[i] = null;
}
}
public int size() {
return currentSize;
}
public boolean isEmpty() {
return currentSize == 0;
}
public boolean contains(T t) {
int currentPos = findPos(t);
return isActive(currentPos);
}
public void insert(T t) {
int currentPos = findPos(t);
if (isActive(currentPos))
return;
array[currentPos] = new HashEntry<T>(t);
currentSize++;
if (currentSize > array.length / 2)
rehash();
}
private void rehash() {
HashEntry<T>[] oldArray = array;
allocateArray(nextPrime(oldArray.length * 2));
currentSize = 0;
for (int i = 0; i < oldArray.length; i++) {
if (oldArray[i] != null && oldArray[i].isActive) {
insert(oldArray[i].element);
}
}
}
public void remove(T t) {
int currentPos = findPos(t);
if (isActive(currentPos)){
array[currentPos].isActive = false;
currentSize--;
}
}
@Override
public String toString() {
StringJoiner joiner = new StringJoiner(", ", "[", "]");
for (int i = 0; i < array.length; i++) {
if (array[i] != null && array[i].isActive) {
joiner.add(array[i].element.toString());
}
}
return joiner.toString();
}
private static class HashEntry<T> {
T element;
boolean isActive;
public HashEntry(T element) {
this(element, true);
}
public HashEntry(T element, boolean isActive) {
this.element = element;
this.isActive = isActive;
}
}
private static final int DEFAULT_TABLE_SIZE = 11;
private HashEntry<T>[] array;
private int currentSize;
@SuppressWarnings("unchecked")
private void allocateArray(int size) {
array = new HashEntry[nextPrime(size)];
}
private boolean isActive(int currentPose) {
return array[currentPose] != null && array[currentPose].isActive;
}
private int findPos(T t) {
int offset = 1;
int currentPos = myhash(t);
while (array[currentPos] != null && !array[currentPos].element.equals(t)) {
currentPos += offset;
offset += 2;
if (currentPos >= array.length)
currentPos -= array.length;
}
return currentPos;
}
private int myhash(T t) {
int hashVal = t.hashCode();
hashVal %= array.length;
if (hashVal < 0)
hashVal += array.length;
return hashVal;
}
private static int nextPrime(int n) {
if (n % 2 == 0)
n++;
while (!isPrime(n))
n += 2;
return n;
}
private static boolean isPrime(int n) {
if (n == 2 || n == 3)
return true;
if (n == 1 || n % 2 == 0)
return false;
for (int i = 3; i * i <= n; i += 2)
if (n % i == 0)
return false;
return true;
}
}