Java 哈希表的实现

哈希表中泛型的键与红黑树中泛型的键本质是不一样的。

由于实现的树是二分搜索树,所以要求键key必须具有可比较性。

而对于哈希表是不需要这种性质的。

对哈希表中键key必须有一个要求:必须实现hashCode方法。

在Java中所有的类型的父类都是Object。而Object类中默认就有hashCode方法。所以所有类型默认都有实现hashCode的方法。

 

利用TreeMap(底层为红黑树)来实现哈希表:

import java.util.TreeMap;

public class HashTable<K, V> {
    
    //利用TreeMap封装成一个数组
    //数组:每个元素存放着键和值
    private TreeMap<K, V>[] hashtable;
    //哈希表中的元素个数
    private int size;
    //哈希表的长度
    private int M;

    public HashTable(int M){
        this.M = M;
        size = 0;
        //开辟数组空间
        hashtable = new TreeMap[M];
        //对每一个TreeMap进行实例化
        for(int i = 0 ; i < M ; i ++){
            hashtable[i] = new TreeMap<>();
        }
    }

    public HashTable(){
        this(97);
    }
    //先将key转化成整型,消除符号
    private int hash(K key){
        return (key.hashCode() & 0x7fffffff) % M;
    }

    public int getSize(){
        return size;
    }

    public void add(K key, V value){
        //根据hash(key)索引取出hashtable中的元素
        TreeMap<K, V> map = hashtable[hash(key)];
        //看map中是否包含了key
        if(map.containsKey(key)){
            //修改该值
            map.put(key, value);
        }else{
            //添加数据
            map.put(key, value);
            size ++;
        }
    }

    public V remove(K key){
        //递归返回令该元素为空
        V ret = null;
        TreeMap<K, V> map = hashtable[hash(key)];
        if(map.containsKey(key)){
            ret = map.remove(key);
            size --;
        }
        return ret;
    }

    public void set(K key, V value){
        TreeMap<K, V> map = hashtable[hash(key)];
        if(!map.containsKey(key)){
            throw new IllegalArgumentException(key + " doesn't exist!");
        }
        map.put(key, value);
    }

    public boolean contains(K key){
        return hashtable[hash(key)].containsKey(key);
    }

    public V get(K key){
        return hashtable[hash(key)].get(key);
    }
}

对哈希表和红黑树的查找性能进行比较:

import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {

        System.out.println("Pride and Prejudice");

        ArrayList<String> words = new ArrayList<>();
        if(FileOperation.readFile("pride-and-prejudice.txt", words)) {
            System.out.println("Total words: " + words.size());

            // Test RBTree
            startTime = System.nanoTime();

            RBTree<String, Integer> rbt = new RBTree<>();
            for (String word : words) {
                if (rbt.contains(word)){
                    rbt.set(word, rbt.get(word) + 1);
                }else{
                    rbt.add(word, 1);
                }
            }

            for(String word: words){
                rbt.contains(word);
            }
            endTime = System.nanoTime();

            time = (endTime - startTime) / 1000000000.0;
            System.out.println("RBTree: " + time + " s");


            // Test HashTable
            startTime = System.nanoTime();

            // HashTable<String, Integer> ht = new HashTable<>();
            HashTable<String, Integer> ht = new HashTable<>(131071);
            for (String word : words) {
                if (ht.contains(word)){
                    ht.set(word, ht.get(word) + 1);
                }else{
                    ht.add(word, 1);
                }
            }

            for(String word: words){
                ht.contains(word);
            }
            endTime = System.nanoTime();

            time = (endTime - startTime) / 1000000000.0;
            System.out.println("HashTable: " + time + " s");
        }

        System.out.println();
    }
}

测试发现哈希表更快一些:

很多时候我们并不知道要存储多少元素,所以就要对哈希表的时间复杂度进行分析。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 岁月 设计师:pinMode 返回首页