Java▲还不懂Java集合框架?看这一篇就够了( 三 )


但是呢 , 实际上你不能不考虑找到元素的时间啊 。。。 而且如果是在尾部操作 , 数据量大时 ArrayList 会更快的 。
所以说:

  1. 改查选择 ArrayList;
  2. 增删在尾部的选择 ArrayList;
  3. 其他情况下 , 如果时间复杂度一样 , 推荐选择 ArrayList , 因为 overhead 更小 , 或者说内存使用更有效率 。
Vector那作为 List 的最后一个知识点 , 我们来聊一下 Vector 。 这也是一个年龄暴露帖 , 用过的都是大佬 。
那 Vector 和 ArrayList 一样 , 也是继承自 java.util.AbstractList , 底层也是用数组来实现的 。
但是现在已经被弃用了 , 因为...它加了太多的 synchronized!
任何好处都是有代价的 , 线程安全的成本就是效率低 , 在某些系统里很容易成为瓶颈 , 所以现在大家不再在数据结构的层面加 synchronized , 而是把这个任务转移给我们程序员==
那么面试常问题:Vector 和 ArrayList 的区别是什么 , 只答出来这个还还不太全面 。
来看 stack overflow 上的高票回答:
一是刚才已经说过的线程安全问题;二是扩容时扩多少的区别 。
这个得看看源码:
这是 ArrayList 的扩容实现 , 这个算术右移操作是把这个数的二进制往右移动一位 , 最左边补符号位 , 但是因为容量没有负数 , 所以还是补 0.
那右移一位的效果就是除以 2 , 那么定义的新容量就是原容量的 1.5 倍 。
再来看 Vector 的:
因为通常 capacityIncrement 我们并不定义 , 所以默认情况下它是扩容两倍 。
答出来这两点 , 就肯定没问题了 。
Queue & DequeQueue 是一端进另一端出的线性数据结构;而 Deque 是两端都可以进出的 。
QueueJava 中的 这个 Queue 接口稍微有点坑 , 一般来说队列的语义都是先进先出(FIFO)的 。
但是这里有个例外 , 就是 PriorityQueue , 也叫 heap , 并不按照进去的时间顺序出来 , 而是按照规定的优先级出去 , 并且它的操作并不是 O(1) 的 , 时间复杂度的计算稍微有点复杂 , 我们之后单独开一篇来讲 。
那 Queue 的方法官网[1
都总结好了 , 它有两组 API , 基本功能是一样的 , 但是呢:
  • 一组是会抛异常的;
  • 另一组会返回一个特殊值 。
功能抛异常返回值增add(e)offer(e)删remove()poll()瞧element()peek()
为什么会抛异常呢?
  • 比如队列空了 , 那 remove() 就会抛异常 , 但是 poll() 就返回 null;element() 就会抛异常 , 而 peek() 就返回 null 就好了 。
那 add(e) 怎么会抛异常呢?
有些 Queue 它会有容量的限制 , 比如 BlockingQueue , 那如果已经达到了它最大的容量且不会扩容的 , 就会抛异常;但如果 offer(e) , 就会 return false.
那怎么选择呢?:
  • 首先 , 要用就用同一组 API , 前后要统一;
  • 其次 , 根据需求 。 如果你需要它抛异常 , 那就是用抛异常的;不过做算法题时基本不用 , 所以选那组返回特殊值的就好了 。
DequeDeque 是两端都可以进出的 , 那自然是有针对 First 端的操作和对 Last 端的操作 , 那每端都有两组 , 一组抛异常 , 一组返回特殊值:
使用时同理 , 要用就用同一组 。
Queue 和 Deque 的这些 API 都是 O(1) 的时间复杂度 , 准确来说是均摊时间复杂度 。
实现类它们的实现类有这三个:
所以说 ,