自己實現一個簡單的散列表

需求

自己實現一個簡單的散列表,使用平方探測(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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章