zoukankan      html  css  js  c++  java
  • java——哈希表 HashTable

    在一个类中重写hashCode()和equals()

    package Date_pacage.hash;
    
    public class Student {
    private int grade;
        private int cls;
        String firstName;
        String lastName;
        
        Student(int grade, int cls, String firstName, String lastName){
            this.grade = grade;
            this.cls = cls;
            this.firstName = firstName;
            this.lastName = lastName;
        }
        
        //如果没有覆盖这个方法,java会自动给Student这个类的每个对象分配一个hashCode,
        //这个自动分配的hashCode是根据对象的地址来分配的
        @Override
        public int hashCode() {
            
            int B = 31;
            
            int hash = 0;
            hash = hash * B + grade;
            hash = hash * B + cls;
            //字符串不区分大小写
            hash = hash * B + firstName.hashCode();
            hash = hash * B + lastName.hashCode();
            
            return hash;
        }
    
        @Override
        public boolean equals(Object o) {
            if(this == o) {
                return true;
            }
            if(o == null) {
                return false;
            }
            if(getClass() != o.getClass()) {
                return false;
            }
            Student another = (Student)o;
            return this.grade == another.grade && 
                    this.cls == another.cls && 
                    this.firstName.toLowerCase().equals(another.firstName.toLowerCase()) &&
                    this.lastName.toLowerCase().equals(another.lastName.toLowerCase());
                    
        }
    }

    实现一个HashTable:

    package Date_pacage.hash;
    
    import java.util.TreeMap;
    
    //哈希冲突的处理:链地址法
    //哈希表的动态空间处理:平均每个地址承载的元素过多一定程度,即扩容
    // N/M >= upperTol
    //平均每个地址承载的元素过少一定程度,即缩容
    //N/M <= lowerTol
    public class HashTable<K, V> {
    
        private static final int upperTol = 10;
        private static final int lowerTol = 2;
        private static final int initCapacity = 7;
        //这里要求K extends Comparable
        private TreeMap<K, V> hashtable[];
        //TreeMap[]:这里表达的是一个存储TreeMap类型的数组!
        private int M;//hashTable中有M个位置
        private int size;//整个哈希表中元素的个数,就是N
        
        public HashTable(int M) {
            this.M = M;
            size = 0;
            //哈希表的底层用了TreeMap,那么hashMap是怎么实现的
            //Hashtable与HashMap类似,不同的是:它不允许记录的键或者值为空;
         //它支持线程的同步,即任一时刻只有一个线程能写Hashtable,然而,这也导致了Hashtable在写入时会比较慢。
    hashtable = new TreeMap[M]; for(int i = 0 ; i < M ; i ++) { hashtable[i] = new TreeMap<>(); } } public HashTable() { this(initCapacity); } private int hash(K key) { return (key.hashCode() & 0x7fffffff) % M; } public int getSize() { return size; } public void add(K key, V value) { //如果有两个字符串的哈希值相同,他们就被分配到一个TreeMap中去 //在将数据传入TreeMap时使用(key, value), //key是字符串,value是字符串出现的个数 TreeMap<K, V> map = hashtable[hash(key)]; if(map.containsKey(key)) { map.put(key, value); }else { map.put(key, value); size ++; if(size >= upperTol * M) { resize(2 * M); } } } public V remove(K key) { TreeMap<K, V> map = hashtable[hash(key)]; V ret = null; if(map.containsKey(key)) { ret = map.remove(key); size --; if(size < lowerTol * M && M / 2 >= initCapacity) { resize(M / 2); } } 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); } private void resize(int newM) { TreeMap<K, V>[] newHashTable = new TreeMap[newM]; for(int i = 0 ; i < newM ; i ++) { newHashTable[i] = new TreeMap<>(); } int oldM = M; this.M = newM; for(int i = 0 ; i < oldM ; i ++) { TreeMap<K, V> map = hashtable[i]; for(K key : map.keySet()) { newHashTable[hash(key)].put(key, map.get(key)); } } this.hashtable = newHashTable; } }

    hashMap中的hash方法:

    作用:是返回输入对象在hashMap数组中的下标值

    具体做法

    原始想法是根据hashcode()得到的散列值^数组长度,得到所在数组下标值,缺点是碰撞严重,只用到了散列值中数组长度的低位信息。

    优化想法:增加一个扰动函数,也就是

    (var1 = var0.hashCode()) ^ var1 >>> 16
    相当于是增加了返回值的信息量,扰动之后的值^数组长度,这时得到的数组下标值碰撞次数减少了很多
  • 相关阅读:
    Gym-101128D:Dice Cup
    C++内联汇编,输出人物名字
    钩子
    列表控件ListBox关联的MFC中的类:CListBox
    高级列表控件ListCtrl关联的MFC中的类:CListCtrl
    菜单复选及窗口置顶
    MFC学习之EDIT控件初始化
    dbgprint_Mine 调试输出
    64位内联汇编
    win7下提权代码
  • 原文地址:https://www.cnblogs.com/gaoquanquan/p/9927845.html
Copyright © 2011-2022 走看看