zoukankan      html  css  js  c++  java
  • 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; }
  • 相关阅读:
    BadUSB 利用
    java 将函数作为参数传递
    odoo12 修行提升篇之 常用的高阶函数 (二)
    odoo12 修行提升篇之 异步定时任务 (一)
    odoo12 修行基础篇之 利用kanban做分析 点击跳转分析模型列表 (九)
    odoo12 修行基础篇之 kanban (八)
    odoo12 修行基础篇之 记录批处理 (七)
    odoo12 修行基础篇之 列表的筛选和分组 (六)
    odoo12 修行基础篇之 添加记录编码 (五)
    odoo12 修行基础篇之 添加工作流和操作记录 (四)
  • 原文地址:https://www.cnblogs.com/ydymz/p/10078287.html
Copyright © 2011-2022 走看看