精华内容
下载资源
问答
  • 散列冲突

    2017-09-08 18:40:14
    概念:如果当一个元素被插入时与一个已经插入的元素散列到相同的值, 那么就会产生冲突, 这个冲突需要消除。解决这种冲突的方法有几种:本章介绍两种方法:分离链接法和开放定址法1.分离链接法 其做法就是将散列到...

    概念:如果当一个元素被插入时与一个已经插入的元素散列到相同的值, 那么就会产生冲突, 这个冲突需要消除。解决这种冲突的方法有几种:本章介绍两种方法:分离链接法和开放定址法

    1.分离链接法

        其做法就是将散列到同一个值得所有元素保留到一个表中。我们可以使用标准库的实现方法。如果空间很紧(因为表是双向链表的并且浪费空间)。
    为执行一次查找,我们使用散列函数来确定是那一个链表, 然后我们在被确定的链表中执行一次查找。

        import java.util.LinkedList;
    import java.util.List;
    
    public class SeparateChainingHashTable<AnyType> {
        private static final int DEFAULT_TABLE_SIZE = 101;
        private List<AnyType>[] theLists;
        private int currentSize;
    
        public SeparateChainingHashTable(){
            this(DEFAULT_TABLE_SIZE);
        }
        public SeparateChainingHashTable(int size){
            theLists = new LinkedList[nextPrime(size)];
    
            for(int i = 0; i < theLists.length; i++)
                theLists[i] = new LinkedList<>();
        }
    
        public boolean contains(AnyType x){
            List<AnyType> whichList = theLists[myhash(x)];
            return whichList.contains(x);
        }
    
        /*
         * 数据的插入
         */
        public void insert(AnyType x){
            List<AnyType> whichList = theLists[myhash(x)];
            if(!whichList.contains(x)){
                whichList.add(x);
    
                //
                if(++currentSize > theLists.length)
                    rehash();
            }
        }
    
        /*
         * 数据的删除
         */
        public void remove(AnyType x){
            List<AnyType> whichList = theLists[myhash(x)];
            if(whichList.contains(x))
            {
                whichList.remove(x);
                currentSize--;
            }
        }
    
        public void makeEmpty(){
            for(int i = 0; i < theLists.length; i++)
                theLists[i].clear();
            currentSize = 0;
        }
    
        private void allocateArray(){
            for(int i = 0; i < theLists.length; i++)
                theLists[i] = new LinkedList<>();
        }
    
        //将传过来的数变成质数
        private static int nextPrime(int n){
            if(n < 11)
                return 11;
            else if(isPrime(n))
                return n;   
            else
                while(true){
                    n++;
                    if(isPrime(n)){
                        return n;
                    }
                }
        }
    
        //判断是不是质数
        private static boolean isPrime(int n){
            if(n % 2 != 0 && n % 3 != 0 && n % 5 != 0 && n % 7 != 0)
                return true;
            else
                return false;
        }
    
        /*
         * 对分离链接散列表和探测散列表的在散列
         */
        private void rehash(){
            List<AnyType> [] oldList = theLists;
            theLists = new LinkedList[theLists.length * 2];
            allocateArray();
            for(int i = 0; i < oldList.length; i++){
                List<AnyType> whichList = oldList[i];
                for (AnyType x : whichList) {
                    insert(x);
                }
            }
        }
    
        /*
         * 散列表的myHash的方法
         */
        private int myhash(AnyType x){
            int hashVal = x.hashCode();
    
            hashVal %= theLists.length;
            if(hashVal < 0)
                hashVal += theLists.length;
    
            return hashVal;
        }
    
        /*测试*/
        public static void main(String[] args) {
            SeparateChainingHashTable<String> hash = new SeparateChainingHashTable<>();
            hash.insert("Tom");
            hash.insert("SanZi");
            System.out.println(hash.contains("Tom"));
        }
    }

    2.开放定址法

    不用链表的散列表

    2.1线性探测法

    就是在插入冲突的时候, 当前位置有值存放的话, 那么就会到下一个位置存放。这种解决冲突的方法虽然在前期效果明显, 但是在插入数量比较庞大的时候。 它解决冲突的时间和链接法的时间相差无几。所以在线性探测这种情况下优化, (平方探测法)。

    2.1平方探测法
    public class QuadraicProbindHashTale<T> {
    
        /**
         *  数据域
         * @param <T>   : 泛型,存放对象
         */
        private static class HashEntry<T>{
            public T element;
            public boolean isActive;
    
            public HashEntry(T e){
                this(e, true);
            }
    
            public HashEntry(T e, boolean i){
                element = e;
                isActive = i;
            }
        }
    
        /*
         * 默认的大小为11
         */
        private static final int DEFAULT_TABLE_SIZE = 11;
    
        private static int currentSize = 0;
    
        private HashEntry<T>[] array;
    
        public QuadraicProbindHashTale(){
            this(DEFAULT_TABLE_SIZE);
        }
    
        /**
         * 
         * @param size  : 表的大小
         */
        public QuadraicProbindHashTale(int size) {
            allocateArray(size);//先判断传过来的size是不是质数, 如果不是, 把它变成质数, 这样方便hash计算和不容易出现冲突情况
            makeEmpty();
        }
    
        /*
         * 判断对象是否在这个hash表当中
         */
        public boolean contains(T x){
            int currentPos = findPos(x);
            return isActive(currentPos);
        }
    
        /**
         * 数据的插入
         * @param x :数据的元素
         * 首先调用findPox方法来判断在第一次执行hash的时候里面有没有元素,如果没有直接插入
         * 如果有元素, 那么在存放的位置往后挪。(线性探测, 平方探测)
         */
        public void insert(T x){
            int currentPos = findPos(x);
            if(isActive(currentPos))
                return;
    
            array[currentPos] = new HashEntry<>(x, true);
    
            if(currentSize > array.length / 2)
                rehash();
        }
    
        /**
         * 数据的删除
         * @param x :要删除的数据
         * 在数据域内有识别这个内容是否有效的一个boolean类型, 当isActive是为true的时候, 表示有效
         * 如果有效的话, 那么就删除。
         */
        public void remove(T x){
            int currentPos = findPos(x);
            if(isActive(currentPos))
                array[currentPos].isActive = false;
        }
    
        /**
         */
        private void rehash(){
            HashEntry<T>[] oldArray = array;
    
            allocateArray(nextPrime(2 * oldArray.length));
            currentSize = 0;
    
            for(int i = 0; i < oldArray.length; i++)
                if(oldArray[i] != null && oldArray[i].isActive)
                    insert(oldArray[i].element);
        }
    
        private boolean isActive(int currentPos){
            return array[currentPos] != null && array[currentPos].isActive;
        }
    
        /**
         * 查找在hash表中元素
         * @param x :要查找的元素
         * @return  所在数组中的位置
         */
        private int findPos(T x){
            int offset = 1;
            int currentPos = myhash(x);
    
            while(array[currentPos] != null && !array[currentPos].equals(x)){
                currentPos += offset;
                offset += 2;
                if(currentPos >= array.length)
                    currentPos -= array.length;
            }
    
            return currentPos;
        }
    
        /*
         * 初始化hash表中的所有的值为空
         */
        public void makeEmpty(){
            currentSize = 0;
            for(int i = 0; i < array.length; i++)
                array[i] = null;
        }
    
        private void allocateArray(int arraySize){
            array = new HashEntry[nextPrime(arraySize)];
        }
    
        //将传过来的数变成质数
            private static int nextPrime(int n){
                if(n < 11)
                    return 11;
                else if(isPrime(n))
                    return n;   
                else
                    while(true){
                        n++;
                        if(isPrime(n)){
                            return n;
                        }
                    }
            }
    
            //判断是不是质数
            private static boolean isPrime(int n){
                if(n % 2 != 0 && n % 3 != 0 && n % 5 != 0 && n % 7 != 0)
                    return true;
                else
                    return false;
            }
    
            /*
             * 散列表的myHash的方法
             */
            private int myhash(T x){
                int hashVal = x.hashCode();
    
                hashVal %= array.length;
                if(hashVal < 0)
                    hashVal += array.length;
    
                return hashVal;
            }
    }
    展开全文
  • 散列表与散列冲突

    2021-01-08 02:22:16
    散列表与散列冲突 解决散列冲突的方法 1.分离链接法(拉链法) 2.开放寻址法 再散列 散列表与散列冲突 HashTable,音译为哈希表,是根据关键字(key)而直接进行访问的数据结构。关键字k,值存放在f(k)的存储位置上...
  • 散列冲突解决方案

    2021-03-10 18:24:14
    散列冲突解决方案 如果两个数据项被散列映射到同一个槽,需要一个系统化的方法在散列表中保存第二个数据项,这个过程称为==“解决冲突”== 如果散列函数是完美的,那么就不会有散列冲突,但完美散列函数常常是不现实的,...

    散列冲突解决方案

    如果两个数据项被散列映射到同一个槽,需要一个系统化的方法在散列表中保存第二个数据项,这个过程称为==“解决冲突”==

    如果散列函数是完美的,那么就不会有散列冲突,但完美散列函数常常是不现实的,解决散列冲突成为散列方法中很重要的一部分

    1. 解决散列冲突的一种方法就是为冲突的数据项再找一个开放的空槽来保存—“线性探测”

      1. 最简单方法就是从冲突的槽开始往后扫描,直到碰到一个空槽,如果到散列表尾部还未找到,则从手部接着扫描
      2. 这种寻找空槽的技术被称为"开放定址"(open addressing)
      3. 向后逐个槽寻找的方法则是开放定址技术中的"线性探测"(linear probing)

      我们把44,55,20逐个插入到散列表中, h(44)=0,但发现0#槽已被77占据,向后找到第一个空槽1#,保存,h(55)=0,同样0#已经被占据,向后找到一个空槽2#,保存

      h(20)==9,发现9#槽已经被31占据了,向后,再从头开始找到3#槽保存

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oMwNMITA-1615371832332)(C:\Users\93623\AppData\Roaming\Typora\typora-user-images\image-20210310114755727.png)]

      1. 采用线性探测方法来解决散列冲突的话,则散列表的查找也遵循同样的规则,如果在散列位置没有找到查找项的话,就必须向后做顺序查找,直到找到查找项,或者碰到空槽(查找失败)
      2. 线性探测法的一个缺点就是聚集的趋势,即如果同一个槽冲突的数据项较多的话,这些数据项机会在槽附近聚集起来,从而连锁式影响其它数据项的插入, 避免聚集的一个方法就是将线性探测扩展,从逐个探测改为跳跃式探测
      3. 重新寻找空槽的过程可以用一个更为通用的==“再散列”==来概括
        1. newhashvalue = rehash(oldhashvalue)
        2. 对于线性探测来说,rehash(pos) = (pos + 1) % sizeoftable
        3. "+3"的跳跃式探测则是: rehash(pos) = (pos+3) % sizeoftable
        4. 跳跃式探测的再散列通式是:rehash(pos) = (pos+skip) % sizeoftable
        5. 跳跃式探测中,需要注意的是skip的取值,不能被散列表大小整除,否则会产生周期,造成很多空槽都永远无法被探测到,一个技巧是把散列表的大小设为素数,如例子的11
        6. 还可以吧线性探测变为"二次探测",不再固定skip的值,而是逐步增加skip值,如1,3,5,7,9. 这样槽号就会是原散列值以平方数增加: h, h+1, h+4, h+9, h+16
    2. 数据项链

      除了寻找空槽的开放定址技术之外,另一种解决散列冲突的方案是将容纳单个数据项的槽扩展为容纳数据项集合(或者对数据项链表的引用),

      这样,散列表中的每个槽就可以容纳多个数据项,如果有散列冲突发生,只需要简单地将数据项添加到数据项集合中

      查找数据项则需要查找同一个槽中的整个集合,当然,随着散列冲突的增加,对数据项的查找时间也会相应增加

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bt9crlWT-1615371832336)(C:\Users\93623\AppData\Roaming\Typora\typora-user-images\image-20210310140617753.png)]

    展开全文
  • 散列冲突及解决方案

    2021-04-25 09:49:48
    散列冲突 对于散列表而言,无论设置的存储区域(n)有多大,当需要存储的数据大于 n 时, 那么必然会存在哈希值相同的情况。这就是所谓的散列冲突。一般解决散列冲突的方法有开放寻址法与链表法。 开放寻址法 定义...

    散列冲突
    对于散列表而言,无论设置的存储区域(n)有多大,当需要存储的数据大于 n 时, 那么必然会存在哈希值相同的情况。这就是所谓的散列冲突。一般解决散列冲突的方法有开放寻址法与链表法。

    开放寻址法
    定义:将散列函数扩展定义成探查序列,即每个关键字有一个探查序列h(k,0)、h(k,1)、…、h(k,m-1),这个探查序列一定是0….m-1的一个排列(一定要包含散列表全部的下标,不然可能会发生虽然散列表没满,但是元素不能插入的情况),如果给定一个关键字k,首先会看h(k,0)是否为空,如果为空,则插入;如果不为空,则看h(k,1)是否为空,以此类推。

    线性探测方法

    向散列表中插入数据时,某个数据经过散列函数得到散列值之后,如果存储位置已经被占用,我们就从当前位置开始,依次往后查找,直到找到空闲位置。

    缺点:当散列表中插入的数据越来越多时,散列冲突发生的可能性就会越来越大,空闲位置会越来越少,线性探测的时间就会越来越久。极端情况下,需要从头到尾探测整个散列表,所以最坏情况下的时间复杂度为 O(n)。

    二次探测方法

    二次探测进行探测的步长变成了原来的“二次方”,也就是说,它探测的下标序列为 hash(key)+0,hash(key)+1^2或[hash(key)-1^2],hash(key)+2^2或[hash(key)-2^2]。

    双重散列方法

    所谓双重散列,意思就是不仅要使用一个散列函数,而是使用一组散列函数 hash1(key),hash2(key),hash3(key)。。。。。。先用第一个散列函数,如果计算得到的存储位置已经被占用,再用第二个散列函数,依次类推,直到找到空闲的存储位置。

    总结:

    事实上,不管采用哪种探测方法,只要当散列表中空闲位置不多的时候,散列冲突的概率就会大大提高。为了尽可能保证散列表的操作效率,一般情况下,需要尽可能保证散列表中有一定比例的空闲槽位。

    一般使用加载因子(load factor)来表示空位的多少。

    加载因子是表示 Hsah 表中元素的填满的程度,若加载因子越大,则填满的元素越多,这样的好处是:空间利用率高了,但冲突的机会加大了。反之,加载因子越小,填满的元素越少,好处是冲突的机会减小了,但空间浪费多了。

     

    链表法
    链表法是一种更加常用的散列冲突解决办法,相比开放寻址法,它要简单很多。如下动图所示,在散列表中,每个位置对应一条链表,所有散列值相同的元素都放到相同位置对应的链表中。
     

    展开全文
  • 处理散列冲突

    2017-06-26 13:27:00
    处理散列冲突的常用方法有两种,一种是开放地址法,一种是链地址法。 开放地址法 开放地址法就是一旦发生冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列表总能找到,并存入。开放地址法又分为线性...

    解决冲突主要有三种方法:定址法,拉链法,再散列法

    处理散列冲突的常用方法有两种,一种是开放地址法,一种是链地址法。

    开放地址法

    开放地址法就是一旦发生冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列表总能找到,并存入。开放地址法又分为线性探测法,二次探测法和随机探测法。
    线性探测法的公式是:
    fi(key)=(f(key)+di) MOD m (di=123m1)
    二次探测法目的是为了不让关键字都聚集在某一区域,公式为:
    fi(key)=(f(key)+di) MOD m (di=12122222q2q2qm1)

    链地址法

    将所有同义词的关键字存储在同一个单链表中,称这个单链表为同义词子表,在散列表中只存储同义词子表的头指针。只要有冲突,就在同义词的子表中增加结点。

     

    链表法就是将相同hash值的对象组织成一个链表放在hash值对应的槽位;开放地址法是通过一个探测算法,当某个槽位已经被占据的情况下继续查找下一个可以使用的槽位。很显然我们使用的不是开放地址法

    转载于:https://www.cnblogs.com/bdqczhl/p/7080083.html

    展开全文
  • Hash冲突怎么办,哪些解决散列冲突的方法?
  • 说说Python中字典和散列表,散列冲突的解决原理.pdf
  • 解决散列冲突的方法有: 开放定址法: 线性探测,每次增加的步长线性增加:1,2,3 。。。 二次探测,每次增加的步长二次增加:12,22,32 。。。 再散列法: 多准备几个hash函数,遇到散列冲突就换一个,重新...
  • 散列冲突的处理——分离链接法

    千次阅读 2018-09-06 20:58:35
    散列冲突的处理——分离链接法和开放定址法 承接上一篇博文哈,上次因为去拯救中国电竞,没有写完。只说了说散列的思想和散列函数的一些讨论,这次详细的分析下对散列冲突的消除方式,会用到一些上一篇博文的一些...
  • 近来上班划水划得起飞,又...散列冲突(哈希冲突):两个关键字散列到同一个值。 哈希代码: 第一种(适用整数): typedef unsigned int Index; Index Hash(const char *key, int tableSize) { unsigned in..
  • 散列冲突的处理——开放定址法

    千次阅读 2018-10-05 13:40:02
    散列冲突的处理——开放定址法 之前聊了聊用分离链接法解决散列冲突的问题,这次就来聊聊对散列冲突的另一种解决办法:开放定址法。开放定址法分为线性探测,平方探测,双散列三种方法。 开放定址法 分离链接法...
  • 这里是从PTA平台整理的【散列冲突】题目集
  • 处理散列冲突的方法

    2021-01-08 03:35:36
    一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。 发生冲突,另寻他处 我们把这种解决冲突的方法称为线性探测法。 我们在解决冲突的时候,还会碰到比如说一个...
  • 如何处理散列冲突

    千次阅读 2012-10-09 15:06:08
    散列表中散列冲突是一种必然,既然不能回避他,我们应该怎么处理散列冲突呢?   1、开放寻址法 根据探查序列的不同分为:线性探查、二次探查、以及双重探查 2、再次Hash法 当出现hash冲突时,使用第二个、第三...
  • P61 5.1 哈希表概述 1、哈希表概念 P62 5.2 散列函数的设计 P63 5.3 散列冲突的解决方案 1、开放地址法 1.1、线性探测法 1.2、二次探测法 1.3、再哈希法 2、链地址法
  • Java: 散列冲突

    2019-02-26 20:19:42
    解决冲突主要有三种方法:定址法,拉链法,再散列法。 HashMap是采用拉链法解决哈希冲突。拉链法解决冲突的做法是: 将所有关键字为同义词的结点链接在同一个单链表中 。 ...
  • 所谓开发定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入。 它的公式是:,这种也称线性探测法。可能一开始学的同学看到di不知道怎么回事,其实这个...
  • 0 1散列表 1简单来说就是给一个key,...1.1散列冲突 我们时常会碰到两个关键字key1 ≠ key2,但是却有f (key1) = f (key2),这种现象我们称为冲突(collision), 打个比方说:加上f的函数是这样的f(key)=key%10...
  • 散列冲突处理:开放定址法   前面我们讲了一些设计散列函数的方法,从前面的除留余数法的例子也可以看出,我们设计得再好的散列函数也不可能完全避免冲突,这就像我们再健康也只能尽量预防疾病,但却无法保证永远...
  • 其实现原理是:通过散列函数(也叫哈希函数)将元素的键映射为数组下标(转化后的值叫做散列值或哈希值),然后在对应下标位置存储记录值。当我们按照键值查询元素时,就是用同样的散列函数,将键值转化数组下标,...
  • hash散列冲突解决方法

    2020-10-26 23:39:02
    什么是hash冲突? 假设hash表的大小为9(即有9个槽),现在要把一串数据存到表里:5,28,19,15,20,33,12,17,10 简单计算一下:hash(5)=5, 所以数据5应该放在hash表的第5个槽里;...这种方法也称再散列法,其基本思想
  • (6)散列冲突处理:链地址法

    千次阅读 2016-02-01 17:52:08
    前面我们谈到了散列冲突处理的开放定址法,它的思路就是一旦发生了冲突,就去寻找下一个空的散列地址。那么,有冲突就非要换地方呢,我们直接就在原地处理行不行呢? 可以的,于是我们就有了链地址法。 将所有...
  • 处理散列冲突的方法 让编程改变世界 Change the world by program 本节课讲解处理散列冲突的方法 开放定址法 ...... 省略,具体请看视频讲解 ...... 再散列函数法 ...... 省略,具体请看视频讲解 ...... ...
  • 哈希冲突(散列冲突)的解决方案

    千次阅读 2017-05-23 12:06:57
     哈希表底层是链表的数组实现的,如果通过哈希算法散列key之后,发现要添加新元素的位置已经有别的元素占有了,并且二者的key值不相等,这就是哈希冲突现象。 解决哈希冲突的方案有开放地址法、链表法、再哈希法和...
  • 散列冲突解决的方式

    2020-11-16 23:32:00
    一、散列思想 散列表的英文叫Hash Table,也叫哈希表或者Hash表。散列表用的是数组支持按照下标随机访问数据的特性,所以散列表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有散列表。 散...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 49,512
精华内容 19,804
关键字:

散列冲突