最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程.

主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList LinkedHashMap中的双向列表不再是回环的.

HashMap中的单链表是尾插, 而不是头插入等等, 后文不再赘叙这些差异, 本文目录结构如下:

LinkedList

经典的双链表结构, 适用于乱序插入, 删除. 指定序列操作则性能不如ArrayList, 这也是其数据结构决定的.

add(E) / addLast(E)

add(index, E)

这边有个小的优化, 他会先判断index是靠近队头还是队尾, 来确定从哪个方向遍历链入.

 1         if (index < (size >> 1)) {
2 Node<E> x = first;
3 for (int i = 0; i < index; i++)
4 x = x.next;
5 return x;
6 } else {
7 Node<E> x = last;
8 for (int i = size - 1; i > index; i--)
9 x = x.prev;
10 return x;
11 }

靠队尾

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, 计算机将中缀表达式转为后缀表达式, 再对后缀表达式进行计算.

中缀转后缀

  • 数字直接输出
  • 栈为空时,遇到运算符,直接入栈
  • 遇到左括号, 将其入栈
  • 遇到右括号, 执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
  • 遇到运算符(加减乘除):弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
  • 最终将栈中的元素依次出栈,输出。

计算后缀表达

  • 遇到数字时,将数字压入堆栈
  • 遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算, 并将结果入栈
  • 重复上述过程直到表达式最右端
  • 运算得出的值即为表达式的结果

队列

与Stack的区别在于, Stack的删除与添加都在队尾进行, 而Queue删除在队头, 添加在队尾.

ArrayBlockingQueue

生产消费者中常用的阻塞有界队列, FIFO.

put(E)

put(E) 队列满了

1         final ReentrantLock lock = this.lock;
2 lock.lockInterruptibly();
3 try {
4 while (count == items.length)
5 notFull.await();
6 enqueue(e);
7 } finally {
8 lock.unlock();
9 }

take()

当元素被取出后, 并没有对数组后面的元素位移, 而是更新takeIndex来指向下一个元素.

takeIndex是一个环形的增长, 当移动到队列尾部时, 会指向0, 再次循环.

 1     private E dequeue() {
2 // assert lock.getHoldCount() == 1;
3 // assert items[takeIndex] != null;
4 final Object[] items = this.items;
5 @SuppressWarnings("unchecked")
6 E x = (E) items[takeIndex];
7 items[takeIndex] = null;
8 if (++takeIndex == items.length)
9 takeIndex = 0;
10 count--;
11 if (itrs != null)
12 itrs.elementDequeued();
13 notFull.signal();
14 return x;
15 }

HashMap

最常用的哈希表, 面试的童鞋必备知识了, 内部通过数组 + 单链表的方式实现. jdk8中引入了红黑树对长度 > 8的链表进行优化, 我们另外篇幅再讲.

put(K, V)

put(K, V) 相同hash值

resize 动态扩容

当map中元素超出设定的阈值后, 会进行resize (length * 2)操作, 扩容过程中对元素一通操作, 并放置到新的位置.

具体操作如下:

  • 在jdk7中对所有元素直接rehash, 并放到新的位置.
  • 在jdk8中判断元素原hash值新增的bit位是0还是1, 0则索引不变, 1则索引变成"原索引 + oldTable.length".
 1     //定义两条链
2 //原来的hash值新增的bit为0的链,头部和尾部
3 Node<K,V> loHead = null, loTail = null;
4 //原来的hash值新增的bit为1的链,头部和尾部
5 Node<K,V> hiHead = null, hiTail = null;
6 Node<K,V> next;
7 //循环遍历出链条链
8 do {
9 next = e.next;
10 if ((e.hash & oldCap) == 0) {
11 if (loTail == null)
12 loHead = e;
13 else
14 loTail.next = e;
15 loTail = e;
16 }
17 else {
18 if (hiTail == null)
19 hiHead = e;
20 else
21 hiTail.next = e;
22 hiTail = e;
23 }
24 } while ((e = next) != null);
25 //扩容前后位置不变的链
26 if (loTail != null) {
27 loTail.next = null;
28 newTab[j] = loHead;
29 }
30 //扩容后位置加上原数组长度的链
31 if (hiTail != null) {
32 hiTail.next = null;
33 newTab[j + oldCap] = hiHead;
34 }

LinkedHashMap

继承自HashMap, 底层额外维护了一个双向链表来维持数据有序. 可以通过设置accessOrder来实现FIFO(插入有序)或者LRU(访问有序)缓存.

put(K, V)

get(K)

accessOrder为false的时候, 直接返回元素就行了, 不需要调整位置.

accessOrder为true的时候, 需要将最近访问的元素, 放置到队尾.

removeEldestEntry 删除最老的元素

原文地址:http://www.cnblogs.com/xdecode/p/9321848.html

图解Java常用数据结构(一)【转载】的更多相关文章

  1. 【转载】图解Java常用数据结构(一)

    图解Java常用数据结构(一)  作者:大道方圆 原文:https://www.cnblogs.com/xdecode/p/9321848.html 最近在整理数据结构方面的知识, 系统化看了下Jav ...

  2. 图解Java常用数据结构(一)

    最近在整理数据结构方面的知识, 系统化看了下Java中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于jdk8, 可能会有些特性与jdk7之前不相同, 例如LinkedList Linke ...

  3. 图解Java常用数据结构

    最近在整理数据结构方面的知识, 系统化看了下 Java 中常用数据结构, 突发奇想用动画来绘制数据流转过程. 主要基于 jdk8, 可能会有些特性与 jdk7 之前不相同, 例如 LinkedList ...

  4. JAVA常用数据结构及原理分析

    JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balaba ...

  5. (6)Java数据结构-- 转:JAVA常用数据结构及原理分析

    JAVA常用数据结构及原理分析  http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balab ...

  6. Java 常用数据结构对象的实现原理 集合类 List Set Map 哪些线程安全 (美团面试题目)

    Java中的集合包括三大类,它们是Set.List和Map, 它们都处于java.util包中,Set.List和Map都是接口,它们有各自的实现类. List.Set都继承自Collection接口 ...

  7. Java 常用数据结构深入分析(Vector、ArrayList、List、Map)

    线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以 ...

  8. java 常用设计模式(转载)

    http://www.cnblogs.com/hnrainll/archive/2011/12/29/2305582.html 设计模式:一个程序员对设计模式的理解:“不懂”为什么要把很简单的东西搞得 ...

  9. Java常用数据结构之Set之TreeSet

    前言 上篇文章我们分析了HashSet,它是基于HashMap实现的,那TreeSet会是怎么实现的呢?没错!和大家想的一样,它是基于TreeMap实现的.所以,TreeSet的源码也很简单,主要还是 ...

随机推荐

  1. bzoj 1767: [Ceoi2009]harbingers

    Description 给定一颗树,树中每个结点有一个邮递员,每个邮递员要沿着唯一的路径走向capital(1号结点),每到一个城市他可以有两种选择: 1.继续走到下个城市 2.让这个城市的邮递员替他 ...

  2. 基于jQuery.i18n.properties实现前端网站语言多版本

    我是参考播客做了个demo:http://blog.csdn.net/aixiaoyang168/article/details/49336709 jQuery.i18n.properties采用.p ...

  3. springMVC学习(11)-json数据交互和RESTful支持

    一.json数据交互: json数据格式在接口调用中.html页面中较常用,json格式比较简单,解析还比较方便. 比如:webservice接口,传输json数据. springMVC进行json交 ...

  4. 【转载】如何在 Github 上发现优秀的开源项目?

    之前发过一系列有关 GitHub 的文章,有同学问了,GitHub 我大概了解了,Git 也差不多会使用了,但是还是搞不清 GitHub 如何帮助我的工作,怎么提升我的工作效率? 问到点子上了,Git ...

  5. [UE4]GetWorld()->GetDeltaSeconds()方法

    void AAvatar::Yaw(float amount) { if (Controller && amount) { // AddControllerYawInput()函数用于 ...

  6. javascript创建对象之稳妥构造函数模式(七)

    所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this的对象.稳妥对象最适合在一些安全的环境中(禁止使用this和new)或者在防止数据被其他应用程序改动时. 稳妥构造函数模式有2个特点:1.新 ...

  7. Hibernate 一对一

    一对一关系映射: 一对一关系映射即关系双方都只含有对方的一个引用(eg:人和身份证) 一对一关系映射又分为唯一外键关联映射和主键关联映射 数据库表结构: 创建实体类: public class Per ...

  8. Web 单元测试

    问题描述: The import org.junit.Test conflicts with a type defined in the same file 导入的org.junit.Test和一个相 ...

  9. ffmpeg同步

    1:ffmpeg解码流程 拆包,构建队列,解码,同步,显示 //计算视频Frame的显示时间//获取ptspts = 0;//decodec video frameavcodec_decode_vid ...

  10. python3 string

    字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可.例如: var1 = 'Hello World!' var2 ...