关于一些数据结构会被问到的面试题

数据结构:

二叉树:

 特点:1、每个节点最多只能有两个子节点  

       2、每个节点都会存储一个关键字

   3、每个非叶子节点左指针指向比它小的节点,右指针指向比它大的节点

   

 缺点:1、由于二叉树它每个节点最多只有两个子节点,因此不适合存储大量数据,所以二叉树适合存储小量数据

       2、而且它也不适合磁盘存储,比较适合内存存储,因为每次查询都需要加载一层节点,那么二叉树层数太高磁盘io次数太多,效率太低

   

B树:

  它是由二叉树演变过来的一种多路搜索树,他每个磁盘块可以存储多个元素,而且每个节点可以有多个子节点。

所以他比二叉树更加的矮胖,比较适合磁盘存储,实际上百万级别的数据只需要三次io就能查到,效率有了极大的提升

B树他比较适合单个查询,不适合范围查询

B+树:

 1、根节点和分支节点不保存数据,只存储索引,所有的数据都存在叶子节点上,所以相同高度B+树比B树存放的数据更多

 2、所有存在根节点或者是分支节点上的元素,同时会存放在叶子节点上,并且是当前叶子节点的最大值或者最小值

 3、B+树的叶子结点之间是一个有序的链表,那么我们在范围查询的时候只需要找到链表的最大值和最小值就行,所以B+树适合范围查询

即使不考虑内存,也不考虑数据量,二叉树也有他的弊端:如果增加、移除操作不当,会导致树的倾斜

红黑树:

1)节点要么是红色要么是黑色

2)根节点是黑色

3)如果一个节点是红色的,则它的所有子节点必须是黑色的

4)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

5)每个叶子的节点都是黑色的空节点(NULL)

6)红黑树任意节点其左右子树最多相差2层红节点(自动相对平衡)

为什么不用平衡二叉树,而是红黑树??

平衡二叉树在平衡时会对节点计数,效率太低

红黑树是如何保持平衡的?

通过旋转或者是变色保持平衡;

红黑树是如何旋转的?

  1. 如果我们增加一个小的节点,如果这个节点打破了树的平衡,那么他上面的节点会进 行右旋
  2. 如果我们增加一个大的节点,如果这个节点打破了树的平衡,那么他上面的节点会进 行左旋
  3. 无论是左旋还是右旋,都不会超过三次旋转;

Java中的集合

单列集合

  1. List
    1. ArrayList : 数组实现存储,查询较快
    2. LinkedList : 双向链表实现存储,增删较快
  2. Set
    1. HashSet : 无序,不可重复
    2. TreeSet : 有序(有序是根据元素大小自动排序,不是存储的顺序) ,不可重复,底层是红黑树

双列集合

  1. Map
    1. HashMap : key唯一
    2. TreeMap : 会自动按照key排序,因为他的key是一个TreeSet
    3. LinkedHashMap : 存取有序,链表实现
      • 场景一 : shiro在配置过滤器的时候要求过滤器顺序配置,使用LinkedHashMap
      • 场景二 : controller中远程调用(restTemplate/OpenFeign)时,接口返回值默认是LinkedHashMap
    4. HashTable : 线程安全的Map,效率低
  2. currentMap : 线程安全

HashMap

问题一:(最多、每家都问)

讲讲hashmap的实现原理:数组、链表、红黑树

  hashmap底层的数据结构,在1.7的时候是数组+单链表,1.8的时候是数组+单链表+红黑树。

当创建hashmap的时候,底层有一个扩容的阈值是0.75,这个值是空间和时间的折中,如果我们增大这个值hashmap空间利用率就会变大,但是hash冲突的概率就会增大,查询效率就会变低;如果减小这个值,出现hash冲突的概率就会小很多,但是空间利用率就会降低;

hashmap通过键的hashcode值来快速存取元素的,当发生hash冲突的时候,hashmap是通过单链表+红黑树来解决的,将新元素存入链表的尾部(尾插法),如果是1.7的话是存入到链表的头部(头插法);

如果是链表长度超过了8,数组长度小于64,hashmap会进行扩容,如果链表长度超过8并且数组长度大于等于64就会将单链表转成红黑树

hashmap1.7与1.8的区别:

1.7扩容1.5倍、1.8扩容2倍

1.7链表是头插法、1.8链表尾插法:1.7并发环境下容易出现循环链表的问题,1.8优化了这个问题,但是也没有解决线程安全问题

问题二:(比较多)

请说一下hashmap的put原理

   首先hashmap会将我们的key值进行hash计算,然后根据计算的hash值从map的数组中取出node,如果取出的node是空,那么就创建出一个node给他

   如果取出的node不为空,那就说明hash冲突了,然后就会判断,如果我们新写入的key的哈希值与原来的hash值相等,并且我们key与原来的node的key相等(== 、equals都判断了),那就说明key是同一个,hashmap就做覆盖操作

   如果key不相等,就判断我们当前的节点是不是一个红黑树,如果是的话我们就将新的节点增加到红黑树上;

如果当前节点不是一个红黑树的节点,那么我们就会遍历单链表,并且追加到链表的尾部,当我们增加完之后;判断当前链表的长度,如果链表的长度达到了默认的阈值8,那么就会判断数组的长度,如果链表长度达到8,但是数组的长度小于64的话,会进行扩容(resize()),如果数组大于等于64的就会将单链表转成红黑树

  当我们移除红黑树里面的元素的话,当红黑树的节点小于6的时候就会反转成单链表

HashMap的一些参数

1、初始大小 16

2、负载因子(map扩容阈值) 0.75

3、单链表转成红黑树的阈值 8

   转成红黑树的数组最小阈值是 64

4、红黑树反转成单链表的阈值是 6

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值