动图+源码,演示 Java 中常用数据结构执行过程及原理
最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程.
主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList LinkedHashMap中的双向列表不再是回环的.
HashMap中的单链表是尾插, 而不是头插入等等, 后文不再赘叙这些差异, 本文目录结构如下:
LinkedList
经典的双链表结构, 适用于乱序插入, 删除. 指定序列操作则性能不如ArrayList, 这也是其数据结构决定的.
add(E) / addLast(E)
add(index, E)
这边有个小的优化, 他会先判断index是靠近队头还是队尾, 来确定从哪个方向遍历链入.
if (index < (size >> 1)) { Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; }
靠队尾
get(index)
也是会先判断index, 不过性能依然不好, 这也是为什么不推荐用for(int i = 0; i < lengh; i++)的方式遍历linkedlist, 而是使用iterator的方式遍历.
remove(E)
ArrayList
底层就是一个数组, 因此按序查找快, 乱序插入, 删除因为涉及到后面元素移位所以性能慢.
add(index, E)
扩容
一般默认容量是10, 扩容后, 会length*1.5.
remove(E)
循环遍历数组, 判断E是否equals当前元素, 删除性能不如LinkedList.
Stack
经典的数据结构, 底层也是数组, 继承自Vector, 先进后出FILO, 默认new Stack()容量为10, 超出自动扩容.
push(E)
pop()
后缀表达式
Stack的一个典型应用就是计算表达式如 9 + (3 - 1) * 3 + 10 / 2, 计算机将中缀表达式转为后缀表达式, 再对后缀表达式进行计算.
中缀转后缀
- 数字直接输出
- 栈为空时,遇到运算符,直接入栈
- 遇到左括号, 将其入栈
- 遇到右括号, 执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
- 遇到运算符(加减乘除):弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
- 最终将栈中的元素依次出栈,输出。
计算后缀表达
- 遇到数字时,将数字压入堆栈
- 遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算, 并将结果入栈
- 重复上述过程直到表达式最右端
- 运算得出的值即为表达式的结果
队列
final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == items.length) notFull.await(); enqueue(e); } finally { lock.unlock(); }
private E dequeue() { // assert lock.getHoldCount() == 1; // assert items[takeIndex] != null; final Object[] items = this.items; @SuppressWarnings("unchecked") E x = (E) items[takeIndex]; items[takeIndex] = null; if (++takeIndex == items.length) takeIndex = 0; count--; if (itrs != null) itrs.elementDequeued(); notFull.signal(); return x; }
HashMap
resize 动态扩容
- 在jdk7中对所有元素直接rehash, 并放到新的位置.
- 在jdk8中判断元素原hash值新增的bit位是0还是1, 0则索引不变, 1则索引变成"原索引 + oldTable.length".
//定义两条链 //原来的hash值新增的bit为0的链,头部和尾部 Node<K,V> loHead = null, loTail = null; //原来的hash值新增的bit为1的链,头部和尾部 Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; //循环遍历出链条链 do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); //扩容前后位置不变的链 if (loTail != null) { loTail.next = null; newTab[j] = loHead; } //扩容后位置加上原数组长度的链 if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; }
LinkedHashMap
·END·
程序员的成长之路
路虽远,行则必至
本文原发于 同名微信公众号「程序员的成长之路」,回复「1024」你懂得,给个赞呗。
回复 [ 520 ] 领取程序员最佳学习方式
回复 [ 256 ] 查看 Java 程序员成长规划
动图+源码,演示 Java 中常用数据结构执行过程及原理的更多相关文章
- 动图+源码,演示Java中常用数据结构执行过程及原理
最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList Linke ...
- Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
- 从源码浅析Java中的Lock和AbstractQueuedSynchronizer
在之前的文章中我也曾经介绍过Lock,像ReentrantLock(可重入锁)和ReentrantReadWriteLock(可重入读写锁),这些所我们在说的时候并没有详细的说明它们的原理,仅仅说明了 ...
- 从源码看java中Integer的缓存问题
在开始详细的说明问题之前,我们先看一段代码 public static void compare1(){ Integer i1 = 127, i2 = 127, i3 = 128, i4 = 128; ...
- Mybatis3源码笔记(六)SqlSession执行过程
前几篇大致分析了初始化的过程,今天打算走一个SqlSession具体执行过程. @Test void shouldSelectAllAuthors() { try (SqlSession sessio ...
- python源码探秘:用户函数的执行过程
脚本函数编译后如何执行?脚本编译后是pyc码,pycodeobject对象的串行化.import时是对pyc文件反系列化.函数编译后会生成函数对象,函数对象的TP_call对应的是function_c ...
- java中for循环执行过程
for (int j = 0; j < newSize; j++) { //执行todo } 1.首先变量j初始化为0 2.然后j=0的值跟newSize进行比较,假如为true,则执行{}里面 ...
- Spring IOC 容器源码分析 - 创建单例 bean 的过程
1. 简介 在上一篇文章中,我比较详细的分析了获取 bean 的方法,也就是getBean(String)的实现逻辑.对于已实例化好的单例 bean,getBean(String) 方法并不会再一次去 ...
- Java中的数据结构有哪些?HashMap的工作原理是什么?
Java中常用数据结构 常用的数据结构有哈希表,线性表,链表,java.util包中有三个重要的接口:List,Set,Map常用来实现基本的数据结构 HashMap的工作原理 HashMap基于ha ...
随机推荐
- 短的 Guid 帮助类
直接贴代码了: /// <summary> /// 短的 Guid 帮助类 /// </summary> public class ShortGuidHelper { #reg ...
- Codekicker.BBCode(BBCode 和 HTML 互转的插件)介绍
项目地址:http://bbcode.codeplex.com/ 项目介绍: Codekicker.BBCode is a stable and performant BBCode-Parser fo ...
- 使用 jQuery.TypeAhead 让文本框自动完成 (二)(访问远程数据)
项目地址:https://github.com/twitter/typeahead.js 直接贴代码了: @section headSection { <script type="te ...
- 生成 Visual Studio 中的代码的文档生成神器
当我们在团队开发中的时候,经常要给别人提供文档,有了这个工具,设置一下,一键生成.前提是你要写好xml注释. 这也是开源项目: https://sandcastle.codeplex.com/ 它就是 ...
- 云原生生态周报 Vol. 11 | K8s 1.16 早知道
业界要闻 Pivotal 发布了完全基于 Kubernetes 的 Pivotal Application Service(PAS)预览版 这意味着 Pivotal 公司一直以来在持续运作的老牌 Pa ...
- Dockerfile 中的 CMD 与 ENTRYPOINT(转)
add by zhj: CMD和ENTRYPOINT的差异很小,可以认为完全可以相互代替.两者都支持shell模式和exec模式, shell模式:跟你在shell下执行命令的格式一样,简单方便,但 ...
- IIS Express 启用目录浏览 方法
标签: iis / visual studio / C# / ASP.NET / .NET 522 今天刚刚使用visual studio 2013创建第一个hello world,结果就发现提示错误 ...
- webform的原生操作图片预览和上传
1.使用input标签进行图片操作,input的标签有一个accept属性,accept 属性只能与 <input type="file"> 配合使用.它规定能够通过文 ...
- 微信小程序自定义tabbar的实现
微信小程序自定义tabbar的实现 目的:当采用微信的自定义tabbar组件的时候,切换的时候会出现闪屏的效果:当使用微信默认的tabbar的时候,限制了tabbar的数量以及灵活配置. 方案:自己动 ...
- i春秋四周年庆典狂欢丨价值6000元的Web安全课程免费送啦
重磅好消息 i春秋四周年庆典狂欢 感恩回馈新老用户 5888元的Web安全线上提高班 988元的Web安全线上入门班 免费送啦 快来围观 活动详情 1.活动时间:6月17日—6月30日 2.活动规则: ...