红黑树和JDK8的HashMap

《算法导论》中对于红黑树的定义如下:

1.每个结点或是红的,或是黑的
2.根节点是黑的
3.每个叶节点是黑的(隐藏的空的叶子节点)
4.如果一个结点是红的,则它的两个儿子都是黑的
5.对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点

红黑树是平衡的树,插入新节点默认为红色,若为根节点,变黑色。
关于插入一个新节点:

  • 如果它的parent是黑色,则直接插入不需要调整
  • 如果parent是红色,有两种情况
    • 如果parent的兄弟结点为空,要旋转+变色,左旋或右旋与插到哪边有关。
    • parent兄弟结点不空且为红色,则parent和其兄弟节点变黑色,祖父结点变红色
    • parent兄弟节点不空为黑色,旋转+变色,都是优先考虑祖孙三代,然后递归到根节点。

AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比黑红树要多,所以红黑树的插入效率更高。红黑树不追求完全平衡,AVL完全平衡。


Jdk8HashMap实现:数组+链表+红黑树

1.7版本的hashMap采用的是数组加链表方式实现的,无论如何,当链表的长度过长时,get元素的遍历时间就会增长,为了解决这一问题,1.8版本的hashMap加入了红黑树。
1.7版本中使用很多的右移和异或运算提高hashMap的散列性,1.8版本采用红黑树来提高散列性,就没有使用太多的右移和异或。
当链表size大于8时,会将其改为红黑树(提高插入和查询效率),然后将元素放到红黑树里。调用put时,有一个节点数组层,存放首节点,可以判断节点类型,链表还是树,超长链表转化成红黑树。插入时,判断当前节点是否是尾结点,然后new一个Node放到尾结点,由此可见1.8版本是采用尾插法。这和红黑树有关,是否转成红黑树,要先判断当前链表有多长,就需要遍历到尾结点,而如果采用头插法,还需要将整个链表向下移一位。采用尾插法的另一个好处是,扩容的时候不会出现1.7里面的扩容后反序的情况,也就不会出现死循环列表。

树化方法细节:首先判断数组长度,如果数组为空,会初始化数组;如果长度小于64会进行扩容。然后判断数组inde位置上的元素是否为空,不为空就进行树化,遍历链表的每一个元素,new一个TreeNode,将元素属性传给TreeNode。
将单向链表转成双向链表,这样就利于再转化成红黑树。
红黑树新节点插入时:
判断parent是否为空,若为空则是根节点,red=false,直接返回,就插入了一个根节点。


扩容:
1.7的hashMap扩容除了判断数组大小是否大于threshold,还判断数组index位置的元素是否为空,两个条件都满足才扩容。
1.8的hashMap只判断数组大小是否大于threshold。
1.7的转移元素是一个一个遍历去转移

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值