集合(常见面试题) (HashMap算法优化)

1 篇文章 0 订阅
1 篇文章 0 订阅

数组/链表

数组(查询快 , 新增, 删除慢)
链表(查询慢, 新增,删除快 )

Collection (单列)(接口)(java.util)

常用方法

  1. c .add 新增一个元素, 返回值是固定 true
  2. c. clear 清空集合所有元素
  3. c.contains 判断集合中是否存在这个元素
  4. c.iterator 获取集合的迭代器
    iterator . next 获取下一个元素
    iterator . hasNext 判断是否有下一个元素

List (可重复)(接口)

  • 有序集合/可以存储重复元素

  • 并发修改异常

      在用迭代器遍历集合时,不允许新增或者删除元素.新增或者修改后,再次调用next时,
         就会抛出并发修改异常.
         避免此异常的方法 : 用for循环遍历集合,不用迭代器遍历. 
    
  • 列表迭代器: ListIterator .继承自Iterator

         列表迭代器可以从任一方向遍历集合.
         提供上一个/下一个方法. 
         可以新增或者移除元素. 需要用列表迭代器提供的add方法.
    
  • 增强for循环 , 其实底层是一个迭代器.

  • ArrayList (实现类)

         底层数据结构是数组: 查询快 , 增删慢. 
    
  • LinkedList (实现类)

        底层数据结构是链表: 增删快,查询慢
        特有功能:
            针对头尾的操作,获取/新增/删除 等.
    

Set (不可重复)

  • 底层是hashcode, 对集合的迭代顺序不做任何保证. 即每次遍历顺序都不一定一致.

        hashcode特点
            同一个对象的hashcode的值是一致的
            默认情况下, 不同对象的hashcode不相同,但是通过方法重写, 是可以获得相同的
    
  • hashcode.

     遍历的方式:
         增强for
         迭代器
    
  • HashSet(实现类)

    底层数据结构是hash表
        数组 + 链表实现
        默认长度为16 
        通过hashcode 计算对象在hash表中的位置 :  
        		hashcode 对数组长度取模. 即除数组长度的余数.
    
  • HashSet保证元素唯一性的源码分析

     先初始化hash表
             根据插入对象的hash值计算对象的存储位置, 
             如果该位置没有元素就存储元素.如果该位置有元素. 
             将两个元素先进行hash值比较, 
             如果hash值不同,将元素添加到集合(也保存到hash表同样的位置) , 
             如果hash值相同. 再次调用对象的equals()方法进行比较该位置的所有元素,
             如果不同,将元素添加到集合.
    
  • LinkedHashSet(有序不重复)

     底层数据结构是hash表和链表
         链表决定了迭代器中元素插入的顺序. 
         hash表决定了元素不重复.
    
  • TreeSet(实现类)(有序不可重复)

     元素是有序的. 默认是是根据元素的自然排序进行排序.也可以通过构造方法设置比较器排序.
     
     自然排序 :  并不是按照元素添加顺序进行排序,  比如数字是根据从小到大的顺序进行排序的. 
                 被自然排序的对象必须实现自然排序接口 Comparable,不然会抛出异常. 
                 重写Cpmparable接口中的cpmparaTo()方法, 本方法如果return 0 ; 
                 则认为返回的重复元素.如果返回正数则是认为在后面, 如果是负数则是认为在前面.
    根据指定的比较器进行排序
                 new TreeSet<T>( new Comparator<T> )
    

Map (双列)

  • HashMap(实现类)

    put() 新增元素put 方法, 后面赋值会覆盖之前的赋值.
    remove() 根据key移除元素,并返回vaule, 没有这个key时返回null
    keySet() 获取map中所有key的集合,用于map遍历
    
  • HashMap底层的数据结构是什么样的?

    底层最核心的数据结构是数组。
    map是长度可变的,但是数组是有固定长度的,所以map也是动态扩容.
    
  • hash算法的优化

    1. 先取到key的hash值32位, 然后将二进制计算后的结果,向右移动16位,左数前16位用0补全。 
    2. 然后将hashcode和右移16位之后的hashcode进行亦或运算。高低16位算法。
    3. 亦或运算后的结果再转换成一个32位的int值 则是这个key的hash值。
    4. 寻址算法 : 上面得到的hash值进行‘与’运算 (n - 1)& hash 
        &运算   相同则为1 , 不同则是0 
        核心:前16位是固定的,无需参与&运算,只有后16位实际进行了计算。
    5. 计算后得到数组长度的一位位置。
    
  • 为什么要如此优化数组寻址的过程?有什么优势?

    因为取模运算性能较差,为了优化这个寻址算法,采用如上算法,得到的效果一样。
    
  • 算法优化总结 :

    hash算法的优化 : 
    	对每个hash值,在低16位之中,让高低16位进行亦或,
    	保留了高低16位的特征,尽量避免了hash值后续出现冲突,
    	防止大家进入相同位置。
    	
    寻址算法的优化:
    	用与&运算替代了 取模运算,提升了性能。
    
  • HashMap是如何解决hash冲突?

      如果经过取址算法计算后的值还是一致的。
      此时底层会在这个数组的位置,挂一个链表,将多个key-value同时放在数组的一个位置里。
      get时, 会找到这个链表,遍历这个链表,取出value。
      如果链表过长,会把链表转化成红黑树。
    
  • HsahMap是如何进行扩容的

      2倍扩容。默认是16位。 -> 32位数组。
      扩容的时候 ,会重新进行寻址运算。之前的链表有可能会分开。
    
  • map集合的遍历

     方式1  : 获取keySet , 遍历set , 获取到每个key , 通过可以获取value 
     方式2 : 获取所有键值对对象的集合 entrySet() ,获取Map.Entry<key,value>获取到键值.
    

Collections集合 工具类

常用方法
    sort 指定list 按照升序排序
    reverse 指定list 反转元素顺序
    shuffle  重新随机排列元素顺序 (模拟洗牌)

哪些容器的线程安全的?

Vector
HashTable

HashTable 是线程安全的 , 这是他和HashMap的最大不同点 , 他的线程安全 , 在于在读写操作的时候都是synchronized . 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值