• hash冲突解决和javahash冲突解决


    其实就是四种方法的演变

    1.开放定址法

    具体就是把数据的标志等的对长度取模

    有三种不同的取模

    线性探测再散列 给数据的标志加增量,取模

    平方探测再散列 给数据的标志平方,取模

    随机探测再散列 把数据的标志随机化,取模

    线性,平方显然很容被人猜出规律,所以最终是随机,那么是不是存在随机会出现取模的值相等的情况

    2.链地址法

    而解决值不同,hash相同的方法有链地址法。

    //先从数组上取下原来的值,给塞到新的节点去,然后把新的节点再放到数组上。  
    void createEntry(int hash, K key, V value, int bucketIndex) {  
           Entry<K,V> e = table[bucketIndex];  
           table[bucketIndex] = new Entry<>(hash, key, value, e);  
           size++;  
    } 
    Entry(int h, K k, V v, Entry<K,V> n) {  
              value = v;  
              next = n;  
              key = k;  
              hash = h;  
    }  

    将值不同hash相同的放在同一个地方,取值时遍历数据。

    那么是不是存在一个地方有几个值,一个地方没有值的情况

    3.再hash法

    就是当hash遇到重复的hash的时候,给自己在hash一次,然后hashCount+1,说明要多hash一次获取地址。

    那么是不是存在hashCount+9999999,才能找到地址的情况

    4.建立一个公共溢出区

    上面都有hashCount来记录hash的次数了,我直接新一个公共溢出区,用overIndex=99来记录不是更好吗?

    那么,hash冲突基本解决,但是同样存在一个问题!

    建立一个公共溢出区在map容器小的时候,作用不大,放在公共溢出区还不如扩容。只有当map的容器越大,扩容需要的空间越多,公共溢出区才实用。

    5.java的hash冲突解决 链地址法

    put方法分析

        public V put(K key, V value) {
            //hash()方法在上面已经出现过了,就不贴了
            return putVal(hash(key), key, value, false, true);
        }
     
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                       boolean evict) {
            Node<K, V>[] tab;
            Node<K, V> p;
            int n, i;
            // tab为空则创建
            if ((tab = table) == null || (n = tab.length) == 0)
                n = (tab = resize()).length;
            // 计算index,并对null做处理
            if ((p = tab[i = (n - 1) & hash]) == null)
                tab[i] = newNode(hash, key, value, null);
            else {
                Node<K, V> e;
                K k;
                // 节点key存在,直接覆盖value
                if (p.hash == hash &&
                        ((k = p.key) == key || (key != null && key.equals(k))))
                    e = p;
                    // 判断该链为红黑树
                else if (p instanceof TreeNode)
                    e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
                    // 该链为链表
                else {
                    for (int binCount = 0; ; ++binCount) {
                        if ((e = p.next) == null) {
                            p.next = newNode(hash, key, value, null);
                            //链表长度大于8转换为红黑树进行处理 TREEIFY_THRESHOLD = 8
                            if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                treeifyBin(tab, hash);
                            break;
                        }
                        // key已经存在并相等,不往链表加值
                        if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k))))
                            break;
                 // key不存在,p,e是老值,p.next是新值 p
    = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e);
               //链地址法触发,返回老值,写了这么久代码才知道put返回不仅仅是null。
    return oldValue; } } ++modCount; // 超过最大容量 就扩容 threshold:单词解释--阈(yu)值,不念阀(fa)值!顺便学下语文咯。 if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
  • 相关阅读:
    ubuntu创建桌面启动器
    UVA 题目11300 Spreading the Wealth
    js实现C#的Server.Encode和Server.Decode
    boost库在工作(20)线程之五
    rmmod: chdir(/lib/modules): No such file or directory
    例说uboot从命令到驱动
    java高级工程师struts的知识重点
    ThreadLocal简单学习
    [CSS]为什么不推荐在CSS中使用ID选择器
    laravel中将session由文件保存改为数据库保存
  • 原文地址:https://www.cnblogs.com/ydymz/p/10078287.html
Copyright © 2020-2023  润新知