微信公众号:I am CR7
如有问题或建议,请在下方留言;
最近更新:2018-09-18

HashMap之元素删除

继上一篇HashMap之元素插入,我们继续来看下元素删除的实现原理。

1、源码:
1public V remove(Object key) {2    Node<K,V> e;3    return (e = removeNode(hash(key), key, null, false, true)) == null ?4        null : e.value;5}复制代码

看下核心方法removeNode:

 1//matchValue为false 表示不需要比对value值一致 2//movable为false 表示删除节点后不移动其他节点 3final Node<K,V> removeNode(int hash, Object key, Object value, 4                           boolean matchValue, boolean movable) { 5    //p为当前检查的节点 6    Node<K,V>[] tab; Node<K,V> p; int n, index; 7    if ((tab = table) != null && (n = tab.length) > 0 && 8        (p = tab[index = (n - 1) & hash]) != null) { //待删除节点在数组索引位置存在元素 9        //node为找到的删除节点10        Node<K,V> node = null, e; K k; V v;11        if (p.hash == hash &&12            ((k = p.key) == key || (key != null && key.equals(k))))//哈希值一致,key一致则找到了要删除的节点13            node = p;14        else if ((e = p.next) != null) {//未找到则看后继节点15            if (p instanceof TreeNode)//如果后继节点为红黑树节点,则在红黑树中查找要删除的节点16                node = ((TreeNode<K,V>)p).getTreeNode(hash, key);17            else {18                do {19                    if (e.hash == hash &&20                        ((k = e.key) == key ||21                         (key != null && key.equals(k)))) {22                        node = e;23                        break;24                    }25                    p = e;26                } while ((e = e.next) != null);//不为红黑树节点,则遍历单链表查找27            }28        }29        if (node != null && (!matchValue || (v = node.value) == value ||30                             (value != null && value.equals(v)))) {//找到节点,matchValue为true,还需要比对value值31            if (node instanceof TreeNode)32                ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);//待删除节点为红黑树节点,则进行红黑树节点的删除操作33            else if (node == p)//待删除节点为数组中的元素,直接将后继节点替换即可34                tab[index] = node.next;35            else//待删除节点为单链表中的元素,将后继节点作为前驱节点的后继节点即可36                p.next = node.next;37            ++modCount;38            --size;39            afterNodeRemoval(node);40            return node;41        }42    }43    return null;44}复制代码

2、流程图:

删除元素流程图

3、说明:

因为HashMap存在三种存储方式,数组、单链表、红黑树,那么删除元素时必然存在着这三种情况。其中,红黑树的删除最为复杂,咱们接着往下看。

红黑树之查找元素

1、源码:

 1final TreeNode<K,V> getTreeNode(int h, Object k) { 2    return ((parent != null) ? root() : this).find(h, k, null); 3} 4 5//查找红黑树的根节点 6final TreeNode<K,V> root() { 7    for (TreeNode<K,V> r = this, p;;) { 8        if ((p = r.parent) == null) 9            return r;10        r = p;11    }12}1314//遍历红黑树查找指定哈希和key的节点15final TreeNode<K,V> find(int h, Object k, Class<?> kc) {16    TreeNode<K,V> p = this;17    do {18        int ph, dir; K pk;19        TreeNode<K,V> pl = p.left, pr = p.right, q;//保存左节点 右节点 20        if ((ph = p.hash) > h) //左节点哈希值大于给定查找节点的哈希值,则继续往左找21            p = pl;22        else if (ph < h)//左节点哈希值小于给定查找节点的哈希值,则往右找23            p = pr;24        else if ((pk = p.key) == k || (k != null && k.equals(pk)))//当前节点key值一致,则返回该节点25            return p;26        else if (pl == null)//左节点为空,则往右找27            p = pr;28        else if (pr == null)//右节点为空,则往左找29            p = pl;30        else if ((kc != null ||//哈希相同,key不同,且有左右节点。此时看key是否可比较,是则比较key值31                  (kc = comparableClassFor(k)) != null) &&32                 (dir = compareComparables(kc, k, pk)) != 0)33            p = (dir < 0) ? pl : pr;//小于往左,大于往右34        else if ((q = pr.find(h, k, kc)) != null)//哈希相同,key不可比或者key也相同,则往右查找35            return q;36        else//否则往左37            p = pl;38    } while (p != null);39    return null;40}复制代码

2、流程图:

查找元素流程图

红黑树之删除元素

1、源码:

  1final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,  2                          boolean movable) {  3    int n;  4    if (tab == null || (n = tab.length) == 0)  5        return;  6    int index = (n - 1) & hash;  7    TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;  8    TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;  9    if (pred == null) //待删除节点为根节点,则其后继节点作为数组索引位置的元素 10        tab[index] = first = succ; 11    else//待删除节点存在前驱节点,则后继节点作为前驱节点的下一个节点 12        pred.next = succ; 13    if (succ != null)//待删除节点存在后继节点,则前驱节点作为后继节点的上一个节点 14        succ.prev = pred; 15    if (first == null)//数组索引位置元素为null,直接返回 16        return; 17    if (root.parent != null)//找到红黑树的根节点 18        root = root.root(); 19    if (root == null || root.right == null || 20        (rl = root.left) == null || rl.left == null) {//红黑树太小则进行去树化操作 21        tab[index] = first.untreeify(map);  // too small 22        return; 23    } 24    //查找替代节点replacement 25    //p为待删除节点,pl为其左节点,pr为其右节点,replacement为替代节点 26    TreeNode<K,V> p = this, pl = left, pr = right, replacement; 27    if (pl != null && pr != null) {//待删除节点有左右节点 28       //s为后继节点  29TreeNode<K,V> s = pr, sl; 30        while ((sl = s.left) != null)//往待删除节点右子树的左边走  31            s = sl; 32        boolean c = s.red; s.red = p.red; p.red = c;//互换后继节点和待删除节点的颜色 33        //sr为后继节点的右节点 34        TreeNode<K,V> sr = s.right; 35        //pp为待删除节点的父节点 36        TreeNode<K,V> pp = p.parent; 37        if (s == pr) {//待删除节点的右节点无左孩子--->右节点和待删除节点互换 38            p.parent = s; 39            s.right = p; 40        } 41        else {//待删除节点的右节点有左孩子 42            //sp为后继节点的父节点 43            TreeNode<K,V> sp = s.parent; 44            //后继节点存在父节点,则让待删除节点替代后继节点 45            if ((p.parent = sp) != null) {//后继节点的父节点成为待删除节点的父节点 46                if (s == sp.left)//后继节点为其父节点的左孩子 47                    sp.left = p;//待删除节点就作为后继节点的父节点的左孩子 48                else 49                    sp.right = p;//待删除节点就作为后继节点的父节点的右孩子 50            } 51            //待删除节点存在右节点,则让后继节点成为其父节点 52            if ((s.right = pr) != null) 53                pr.parent = s; 54        } 55        p.left = null;//待删除节点左孩子为null 56        if ((p.right = sr) != null)//后继节点存在右节点,则让其成为待删除节点的右节点 57            sr.parent = p;//相对应,待删除节点成为其父节点 58        if ((s.left = pl) != null)//待删除节点存在左节点,则让其成为后继节点的左节点 59            pl.parent = s;//相对应,后继节点成为其父节点 60        //待删除节点存在父节点,则让后继节点替代待删除节点 61        if ((s.parent = pp) == null)//待删除节点不存在父节点,则后继节点父节点为null 62            root = s;//后继节点成为根节点 63        else if (p == pp.left)//待删除节点存在父节点,且待删除节点是其左节点 64            pp.left = s;//后继节点作为其左节点 65        else 66            pp.right = s;//后继节点作为其右节点 67        //后继节点存在右节点,则替代节点为该节点 68        if (sr != null) 69            replacement = sr; 70        else //替代节点为待删除节点(等于未找到) 71            replacement = p; 72    } 73    else if (pl != null)//待删除节点只有左节点 74        replacement = pl; 75    else if (pr != null)//待删除节点只有右节点 76        replacement = pr; 77    else//待删除节点为叶子节点 78        replacement = p; 79    if (replacement != p) {//替代节点不为待删除节点,则先进行节点删除,然后进行平衡调整 80        TreeNode<K,V> pp = replacement.parent = p.parent; 81        if (pp == null) 82            root = replacement; 83        else if (p == pp.left) 84            pp.left = replacement; 85        else 86            pp.right = replacement; 87        p.left = p.right = p.parent = null; 88    } 89 90    TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);//进行平衡调整 91 92    if (replacement == p) {  //替代节点为待删除节点,则先进行平衡调整,然后进行节点删除 93        TreeNode<K,V> pp = p.parent; 94        p.parent = null; 95        if (pp != null) { 96            if (p == pp.left) 97                pp.left = null; 98            else if (p == pp.right) 99                pp.right = null;100        }101    }102    if (movable)//将红黑树根节点移动到数组索引位置103        moveRootToFront(tab, r);104}复制代码

2、流程图:

删除元素流程图

3、说明:

以上为HashMap的红黑树删除流程,其实思路和TreeMap中红黑树大致相同,关于TreeMap的解析,请看TreeMap之元素删除,文章中我对红黑树的删除过程进行了详细的分析,这里就不做详细阐述了。

示例

我们通过一个具体的例子,来体会下删除的过程,请看:

初始状态
删除10
删除226
删除320
替代删除
平衡调整
删除384
平衡调整
删除
删除0
平衡调整
平衡调整
删除
删除64
删除
删除128
平衡调整
图注:平衡调整
删除
删除512
去树化

总结

通过上述的分析,结合着TreeMap之元素删除这篇文章,我想,要理解HashMap的删除,并不是一件难事。
     文章的最后,感谢大家的支持,欢迎扫描下方二维码,进行关注。如有任何疑问,欢迎大家留言。

HashMap 之元素删除相关推荐

  1. HashMap遍历中删除元素报错

    文章目录 一.问题描述 二.问题分析 三.解决问题 四.相关问题 一.问题描述 HashMap在遍历的时候进行删除元素报错java.util.ConcurrentModificationExcepti ...

  2. Java集合中元素删除

    在Java中删除集合中元素时,需要特别注意,一方面是因为,Java是并发编程语言,如果存在并发操作,则会出现逻辑异常:另一方面,在List中删除元素,如果操作不当,则会抛出异常. 阿里推出的<J ...

  3. 顺序表应用2:多余元素删除之建表算法

    顺序表应用2:多余元素删除之建表算法 Description 一个长度不超过10000数据的顺序表,可能存在着一些值相同的"多余"数据元素(类型为整型),编写一个程序将" ...

  4. php 元素插入数组指定位置,数组任意位置插入元素,删除特定元素的实例

    如下所示: $ary = array( array('t'=>1,'y'=>2), array('t'=>2,'y'=>9) ); $t = array_splice( $ar ...

  5. 彻底理解HashMap的元素插入原理

    转载自   彻底理解HashMap的元素插入原理 HashMap,是Java语言中比较基础也比较重要的一种数据结构,由于其用途广泛,所以,Java的工程师在设计HashMap的时候考虑了很多因素. 通 ...

  6. LinkedList理解(2)元素删除

    上一篇文章我们说了LinkedList,并说了往里添加了元素.这篇文章我们来说说LinkedList元素的删除,话不多说,上代码,还是那个Person类 还是那两个属性,name,age,提供了一些简 ...

  7. java——定义一个功能将ArrayList 集合中的重复元素删除(java集合七)

    定义一个功能将ArrayList 集合中的重复元素删除 ArrayList 集合中是允许储存重复元素的 import java.util.ArrayList; import java.util.Ite ...

  8. hashmap中的key是有序的么_深入理解HashMap遍历元素的顺序

    HashMap遍历元素的顺序. 一,HashMap元素的底层存储顺序 我们都知道HashMap是"无序"的,也就是说不能保证插入顺序.但是,HashMap其实也是有序的,一组相同的 ...

  9. C语言实现二叉查找树的元素删除功能

    接前一篇博文添加二叉查找树的元素删除功能. #include <stdio.h> #include <stdlib.h>//二叉查找树的节点 struct bst_node { ...

最新文章

  1. How do I open an editor on something that is not a file?
  2. 计算机视觉:单阶段目标检测模型YOLO-V3
  3. IT 人永远不老,老程序员价值何在?
  4. linux之写C代码出现warning: format not a string literal and no format arguments [-Wformat-security]
  5. C++ 11 深度学习(四)结构、权限修饰符
  6. 这就是我经常的C++状态,多练
  7. 700 页的机器学习笔记火啦,图文生动形象
  8. 【Flink】Flink时间之internalTimerService初始化
  9. 断言java怎么用_[java] java断言的使用
  10. 关于http协议详解(摘)
  11. WEB前端性能优化及应用服务器性能优化和存储性能优化
  12. idea配置jfinal_intellij idea如何创建JFinal项目
  13. 关于adodb的简单介绍
  14. linux 支持的中文字体,Linux 增加中文字体支持
  15. 1 如何制定购车计划
  16. ReentrantLock 源码简单分析
  17. Kali Linux简介
  18. Logic unifying接收器 绑定与取消 重新关联
  19. 读书札记:音律的基本类型
  20. 连打印机时网络里面没有计算机,打印机显示打印系统没有连接到计算机怎么回事...

热门文章

  1. 【Matlab】删除cell中所有的空白cell.
  2. 关键词4K图片采集下载软件【非常适合做电脑壁纸等】
  3. 【学习日志】学习总结
  4. 洛谷 P5197 [USACO19JAN]Grass Planting 题解
  5. STC89C52RC - 1 - 简述以及最小操作系统
  6. Godfather POJ - 3107 树的重心
  7. BUGKU------中国菜刀
  8. 微信群发工具,只能在自己电脑上使用(基于wxpy库)
  9. 浅显易懂入门大数据系列:二、MapReduce、YARN(超详细)
  10. OSError: (External) Cublas error, CUBLAS_STATUS_NOT_INITIALIZED. The cuBLAS library was not Initia