提交 2f286d02 编写于 作者: 沉默王二's avatar 沉默王二 💬

集合框架

上级 160524da
---
title: Java ArrayList详解(附源码分析)
shortTitle: Java ArrayList详解
category:
- Java核心
tag:
- Java
- 集合框架(容器)
description: Java程序员进阶之路,小白的零基础Java教程,Java ArrayList详解
head:
- - meta
- name: keywords
content: Java,Java SE,Java 基础,Java 教程,Java 程序员进阶之路,Java 入门,Java ArrayList,ArrayList 源码
---
# Java集合ArrayList详解
“二哥,听说今天我们开讲 ArrayList 了?好期待哦!”三妹明知故问,这个托配合得依然天衣无缝。
“是的呀,三妹。”我肯定地点了点头,继续说道,“ArrayList 可以称得上是集合框架方面最常用的类了,可以和 HashMap 一较高下。”
......@@ -18,6 +22,8 @@ tag:
Java 这门编程语言和 C语言的不同之处就在这里,如果是 C语言的话,就必须动手实现自己的 ArrayList,原生的库函数里面是没有的。
## 创建 ArrayList
“二哥,**如何创建一个 ArrayList 啊**?”三妹问。
```java
......@@ -40,6 +46,8 @@ List<String> alist = new ArrayList<>(20);
这样做的好处是,可以有效地避免在添加新的元素时进行不必要的扩容。但通常情况下,我们很难确定 ArrayList 中元素的个数,因此一般不指定初始大小。
## 向 ArrayList 中添加元素
“二哥,**那怎么向 ArrayList 中添加一个元素呢**?”三妹继续问。
可以通过 `add()` 方法向 ArrayList 中添加一个元素,如果不指定下标的话,就默认添加在末尾。
......@@ -201,6 +209,8 @@ public void add(int index, E element) {
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/collection/arraylist-01.png)
## 更新 ArrayList 中的元素
“二哥,那怎么**更新 ArrayList 中的元素**呢?”三妹继续问。
......@@ -226,6 +236,8 @@ public E set(int index, E element) {
该方法会先对指定的下标进行检查,看是否越界,然后替换新值并返回旧值。
## 删除 ArrayList 中的元素
“二哥,那怎么**删除 ArrayList 中的元素**呢?”三妹继续问。
`remove(int index)` 方法用于删除指定下标位置上的元素,`remove(Object o)` 方法用于删除指定值的元素。
......@@ -298,7 +310,7 @@ private void fastRemove(int index) {
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/collection/arraylist-02.png)
## 查找 ArrayList 中的元素
“二哥,那怎么**查找 ArrayList 中的元素**呢?”三妹继续问。
......@@ -365,6 +377,8 @@ System.out.println(copy);
int index = Collections.binarySearch(copy, "b");
```
## ArrayList 增删改查的时间复杂度
“最后,三妹,我来简单总结一下 ArrayList 的时间复杂度吧,方便后面学习 LinkedList 时对比。”我喝了一口水后补充道。
1)通过下标(也就是 `get(int index)`)访问一个元素的时间复杂度为 O(1),因为是直达的,无论数据增大多少倍,耗时都不变。
......@@ -383,7 +397,7 @@ public E get(int index) {
4)查找一个未排序的列表时间复杂度为 O(n)(调用 `indexOf()` 或者 `lastIndexOf()` 方法时),因为要遍历列表;查找排序过的列表时间复杂度为 O(log n),因为可以使用二分查找法,当数据增大 n 倍时,耗时增大 logn 倍(这里的 log 是以 2 为底的,每找一次排除一半的可能)。
-------
## 总结
ArrayList,如果有个中文名的话,应该叫动态数组,也就是可增长的数组,可调整大小的数组。动态数组克服了静态数组的限制,静态数组的容量是固定的,只能在首次创建的时候指定。而动态数组会随着元素的增加自动调整大小,更符合实际的开发需求。
......@@ -393,4 +407,10 @@ ArrayList,如果有个中文名的话,应该叫动态数组,也就是可
计算机内部是如何表示十进制数的,右移时又发生了什么,静下心来去研究一下,你就会发现,哦,原来这么有趣呢?
----
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
\ No newline at end of file
---
title: Java 集合框架(容器)体系结构
shortTitle: Java集合框架体系结构
category:
- Java核心
tag:
- Java
- 集合框架(容器)
description: Java程序员进阶之路,小白的零基础Java教程,Java 集合框架(容器)体系结构
head:
- - meta
- name: keywords
content: Java,Java SE,Java 基础,Java 教程,Java 程序员进阶之路,Java 入门,Java 集合框架,java 容器
---
# Java集合框架
眼瞅着三妹的王者荣耀杀得正嗨,我趁机喊到:“别打了,三妹,我们来一起学习 Java 的集合框架吧。”
......@@ -30,23 +35,23 @@ Java 集合框架可以分为两条大的支线:
“接下来,我们再来过一遍。”
### 01、List
## 01、List
>List 的特点是存取有序,可以存放重复的元素,可以用下标对元素进行操作
**1)ArrayList**
### **1)ArrayList**
- ArrayList 是由数组实现的,支持随机存取,也就是可以通过下标直接存取元素;
- 从尾部插入和删除元素会比较快捷,从中间插入和删除元素会比较低效,因为涉及到数组元素的复制和移动;
- 如果内部数组的容量不足时会自动扩容,因此当元素非常庞大的时候,效率会比较低。
**2)LinkedList**
### **2)LinkedList**
- LinkedList 是由双向链表实现的,不支持随机存取,只能从一端开始遍历,直到找到需要的元素后返回;
- 任意位置插入和删除元素都很方便,因为只需要改变前一个节点和后一个节点的引用即可,不像 ArrayList 那样需要复制和移动数组元素;
- 因为每个元素都存储了前一个和后一个节点的引用,所以相对来说,占用的内存空间会比 ArrayList 多一些。
**3)Vector 和 Stack**
### **3)Vector 和 Stack**
List 的实现类还有一个 Vector,是一个元老级的类,比 ArrayList 出现得更早。ArrayList 和 Vector 非常相似,只不过 Vector 是线程安全的,像 get、set、add 这些方法都加了 `synchronized` 关键字,就导致执行执行效率会比较低,所以现在已经很少用了。
......@@ -56,11 +61,11 @@ Stack 是 Vector 的一个子类,本质上也是由动态数组实现的,只
不过,由于 Stack 执行效率比较低(方法上同样加了 synchronized 关键字),就被双端队列 ArrayDeque 取代了。
### 02、Set
## 02、Set
> Set 的特点是存取无序,不可以存放重复的元素,不可以用下标对元素进行操作,和 List 有很多不同
**1)HashSet**
## **1)HashSet**
HashSet 其实是由 HashMap 实现的,只不过值由一个固定的 Object 对象填充,而键用于操作。
......@@ -88,7 +93,7 @@ public class HashSet<E>
}
```
**2)LinkedHashSet**
### **2)LinkedHashSet**
LinkedHashSet 继承自 HashSet,其实是由 LinkedHashMap 实现的,LinkedHashSet 的构造方法调用了 HashSet 的一个特殊的构造方法:
......@@ -98,7 +103,7 @@ HashSet(int initialCapacity, float loadFactor, boolean dummy) {
}
```
**3)TreeSet**
### **3)TreeSet**
“二哥,不用你讲了,我能猜到,TreeSet 是由 TreeMap 实现的,只不过同样操作的键位,值由一个固定的 Object 对象填充。”
......@@ -114,11 +119,11 @@ HashSet(int initialCapacity, float loadFactor, boolean dummy) {
“是的,你这水平长进了呀,三妹。”
### 03、Queue
## 03、Queue
> Queue,也就是队列,通常遵循先进先出(FIFO)的原则,新元素插入到队列的尾部,访问元素返回队列的头部。
**1)ArrayDeque**
### **1)ArrayDeque**
从名字上可以看得出,ArrayDeque 是一个基于数组实现的双端队列,为了满足可以同时在数组两端插入或删除元素的需求,数组必须是循环的,也就是说数组的任何一点都可以被看作是起点或者终点。
......@@ -128,21 +133,21 @@ HashSet(int initialCapacity, float loadFactor, boolean dummy) {
head 指向队首的第一个有效的元素,tail 指向队尾第一个可以插入元素的空位,因为是循环数组,所以 head 不一定从是从 0 开始,tail 也不一定总是比 head 大。
**2)LinkedList**
### **2)LinkedList**
LinkedList 一般都归在 List 下,只不过,它也实现了 Deque 接口,可以作为队列来使用。等于说,LinkedList 同时实现了 Stack、Queue、PriorityQueue 的所有功能。
**3)PriorityQueue**
### **3)PriorityQueue**
PriorityQueue 是一种优先级队列,它的出队顺序与元素的优先级有关,执行 remove 或者 poll 方法,返回的总是优先级最高的元素。
要想有优先级,元素就需要实现 Comparable 接口或者 Comparator 接口。
### 04、Map
## 04、Map
> Map 保存的是键值对,键要求保持唯一性,值可以重复。
**1)HashMap**
### **1)HashMap**
HashMap 实现了 Map 接口,根据键的 HashCode 值来存储数据,具有很快的访问速度,最多允许一个 null 键。
......@@ -183,7 +188,7 @@ final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
一旦 HashMap 发生哈希冲突,就把相同键位的地方改成链表,如果链表的长度超过 8,就该用红黑树。
**2)LinkedHashMap**
### **2)LinkedHashMap**
大多数情况下,只要不涉及线程安全问题,Map基本都可以使用HashMap,不过HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。HashMap的这一缺点往往会带来困扰,因为有些场景,我们期待一个有序的Map。
......@@ -191,104 +196,16 @@ final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
LinkedHashMap 可以看作是 HashMap + LinkedList 的合体,它使用了 哈希表来存储数据,又用了双向链表来维持顺序。
**3)TreeMap**
### **3)TreeMap**
HashMap 是无序的,所以遍历的时候元素的顺序也是不可测的。TreeMap 是有序的,它在内部会对键进行排序,所以遍历的时候就可以得到预期的顺序。
为了保证顺序,TreeMap 的键必须要实现 Comparable 接口或者 Comparator 接口。
### 05、时间复杂度
“二哥,为什么要讲时间复杂度呀?”三妹问。
“因为接下来要用到啊。后面我们学习 ArrayList、LinkedList 的时候,会比较两者在增删改查时的执行效率,而时间复杂度是衡量执行效率的一个重要标准。”我说。
“到时候跑一下代码,统计一下前后的时间差不更准确吗?”三妹反问道。
“实际上,你说的是另外一种评估方法,这种评估方法可以得出非常准确的数值,但也有很大的局限性。”我不急不慢地说。
第一,测试结果会受到测试环境的影响。你比如说,同样的代码,在我这台 iMac 上跑出来的时间和在你那台华为的 MacBook 上抛出的时间可能就差别很大。
第二,测试结果会受到测试数据的影响。你比如说,一个排序后的数组和一个没有排序后的数组,调用了同一个查询方法,得出来的结果可能会差别特别大。
“因此,我们需要这种不依赖于具体测试环境和测试数据就能粗略地估算出执行效率的方法,时间复杂度就是其中的一种,还有一种是空间复杂度。”我继续补充道。
来看下面这段代码:
```java
public static int sum(int n) {
int sum = 0; // 第 1 行
for (int i=0;i<n;i++) { // 第 2 行
sum = sum + 1; // 第 3 行
} // 第 4 行
return sum; // 第 5 行
}
```
这段代码非常简单,方法体里总共 5 行代码,包括“}”那一行。每段代码的执行时间可能都不大一样,但假设我们认为每行代码的执行时间是一样的,比如说 unit_time,那么这段代码总的执行时间为多少呢?
“这个我知道呀!”三妹喊道,“第 1、5 行需要 2 个 unit_time,第 2、3 行需要 2*n*unit_time,总的时间就是 2(n+1)*unit_time。”
“对,一段代码的执行时间 T(n) 和总的执行次数成正比,也就是说,代码执行的次数越多,花费的时间就越多。”我总结道,“这个规律可以用一个公式来表达:”
> T(n) = O(f(n))
f(n) 表示代码总的执行次数,大写 O 表示代码的执行时间 T(n) 和 f(n) 成正比。
这也就是大 O 表示法,它不关心代码具体的执行时间是多少,它关心的是代码执行时间的变化趋势,这也就是时间复杂度这个概念的由来。
对于上面那段代码 `sum()` 来说,影响时间复杂度的主要是第 2 行代码,其余的,像系数 2、常数 2 都是可以忽略不计的,我们只关心影响最大的那个,所以时间复杂度就表示为 `O(n)`
常见的时间复杂度有这么 3 个:
1)`O(1)`
代码的执行时间,和数据规模 n 没有多大关系。
括号中的 1 可以是 3,可以是 5,可以 100,我们习惯用 1 来表示,表示这段代码的执行时间是一个常数级别。比如说下面这段代码:
```java
int i = 0;
int j = 0;
int k = i + j;
```
实际上执行了 3 次,但我们也认为这段代码的时间复杂度为 `O(1)`
2)`O(n)`
时间复杂度和数据规模 n 是线性关系。换句话说,数据规模增大 K 倍,代码执行的时间就大致增加 K 倍。
3)`O(logn)`
时间复杂度和数据规模 n 是对数关系。换句话说,数据规模大幅增加时,代码执行的时间只有少量增加。
来看一下代码示例,
```java
public static void logn(int n) {
int i = 1;
while (i < n) {
i *= 2;
}
}
```
换句话说,当数据量 n 从 2 增加到 2^64 时,代码执行的时间只增加 64 倍。
```
遍历次数 | i
----------+-------
0 | i
1 | i*2
2 | i*4
... | ...
... | ...
k | i*2^k
```
----
“好了,三妹,这节就讲到这吧,理解了上面 3 个时间复杂度,后面我们学习 ArrayList、LinkedList 的时候,两者在增删改查时的执行效率就很容易对比清楚了。”我伸了个懒腰后对三妹说,“整体上,集合框架就这么多东西了,随后我们会一一展开来讲,比如说 ArrayList、LinkedList、HashMap 等。”。
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
“好的,二哥。”三妹重新回答沙发上,一盘王者荣耀即将开始
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
---
title: 海康威视一面:Java中Iterator和Iterable有什么区别?
shortTitle: ArrayList和LinkedList的区别
category:
- Java核心
tag:
- Java
- 集合框架(容器)
description: Java程序员进阶之路,小白的零基础Java教程,Java中Iterator和Iterable有什么区别?
head:
- - meta
- name: keywords
content: Java,Java SE,Java 基础,Java 教程,Java 程序员进阶之路,Java 入门,Java LinkedList,Java ArrayList,linkedlist arraylist
---
# Java中的Iterator和Iterable区别
那天,小二去海康威视面试,面试官老王一上来就甩给了他一道面试题:请问 Iterator与Iterable有什么区别?
-----
----
在 Java 中,我们对 List 进行遍历的时候,主要有这么三种方式。
......
---
title: Java LinkedList详解(附源码分析)
shortTitle: Java LinkedList详解
category:
- Java核心
tag:
- Java
- 集合框架(容器)
description: Java程序员进阶之路,小白的零基础Java教程,Java LinkedList详解
head:
- - meta
- name: keywords
content: Java,Java SE,Java 基础,Java 教程,Java 程序员进阶之路,Java 入门,Java LinkedList,LinkedList源码
---
# Java集合LinkedList详解
### 一、LinkedList 的剖白
## 一、LinkedList 的剖白
大家好,我是 LinkedList,和 ArrayList 是同门师兄弟,但我俩练的内功却完全不同。师兄练的是动态数组,我练的是链表。
......@@ -36,7 +41,7 @@ tag:
但我现在的功力还达不到第三层,不过师父说我有这个潜力,练成神功是早晚的事。
### 二、LinkedList 的内功心法
## 二、LinkedList 的内功心法
好了,经过我这么样的一个剖白后,大家对我应该已经不陌生了。那么接下来,我给大家展示一下我的内功心法。
......@@ -72,7 +77,7 @@ private static class Node<E> {
我的内功心法就这么简单,其实我早已经牢记在心了。但师父叮嘱我,每天早上醒来的时候,每天晚上睡觉的时候,一定要默默地背诵一遍。虽然我有些厌烦,但我对师父的教诲从来都是言听计从。
### 03、LinkedList 的招式
## 03、LinkedList 的招式
和师兄 ArrayList 一样,我的招式也无外乎“增删改查”这 4 种。在此之前,我们都必须得初始化。
......@@ -82,7 +87,7 @@ LinkedList<String> list = new LinkedList();
师兄在初始化的时候,默认大小为 10,也可以指定大小,依据要存储的元素数量来。我就不需要。
**1)招式一:增**
### **1)招式一:增**
可以调用 add 方法添加元素:
......@@ -173,7 +178,7 @@ private void linkFirst(E e) {
addLast 的内核其实和 addFirst 差不多,就交给大家自行理解了。
**2)招式二:删**
### **2)招式二:删**
我这个删的招式还挺多的:
......@@ -280,7 +285,7 @@ private E unlinkFirst(Node<E> f) {
}
```
**3)招式三:改**
### **3)招式三:改**
可以调用 `set()` 方法来更新元素:
......@@ -326,7 +331,7 @@ Node<E> node(int index) {
找到指定下标的节点就简单了,直接把原有节点的元素替换成新的节点就 OK 了,prev 和 next 都不用改动。
**4)招式四:查**
### **4)招式四:查**
我这个查的招式可以分为两种:
......@@ -372,7 +377,7 @@ public E get(int index) {
- `pollLast()` 方法用于删除并返回最后一个元素;
- `peekFirst()` 方法用于返回但不删除第一个元素。
### 四、LinkedList 的挑战
## 四、LinkedList 的挑战
说句实在话,我不是很喜欢和师兄 ArrayList 拿来比较,因为我们各自修炼的内功不同,没有孰高孰低。
......@@ -384,4 +389,10 @@ public E get(int index) {
无论外人怎么看待我们,在我眼里,师兄永远都是一哥,我敬重他,他也愿意保护我。
----
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
\ No newline at end of file
---
title: 面试官问我Java中ArrayList和LinkedList的区别,我和他扯了半小时
shortTitle: ArrayList和LinkedList的区别
category:
- Java核心
tag:
- Java
- 集合框架(容器)
description: Java程序员进阶之路,小白的零基础Java教程,Java中ArrayList和LinkedList的区别
head:
- - meta
- name: keywords
content: Java,Java SE,Java 基础,Java 教程,Java 程序员进阶之路,Java 入门,Java LinkedList,Java ArrayList,linkedlist arraylist
---
# Java中ArrayList和LinkedList的区别
### 01、ArrayList 是如何实现的?
## 01、ArrayList 是如何实现的?
ArrayList 实现了 List 接口,继承了 AbstractList 抽象类。
......@@ -139,7 +144,7 @@ private void writeObject(java.io.ObjectOutputStream s)
此处应该有掌声啊!不是为我,为 Java 源码的作者们,他们真的是太厉害了,可以用两个词来形容他们——殚精竭虑、精益求精。
### 02、LinkedList 是如何实现的?
## 02、LinkedList 是如何实现的?
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/collection/list-war-2-02.png)
......@@ -230,11 +235,11 @@ void linkLast(E e) {
和 ArrayList 相比,LinkedList 没有实现 RandomAccess 接口,这是因为 LinkedList 存储数据的内存地址是不连续的,所以不支持随机访问。
### 03、ArrayList 和 LinkedList 新增元素时究竟谁快?
## 03、ArrayList 和 LinkedList 新增元素时究竟谁快?
前面我们已经从多个维度了解了 ArrayList 和 LinkedList 的实现原理和各自的特点。那接下来,我们就来聊聊 ArrayList 和 LinkedList 在新增元素时究竟谁快?
**1)ArrayList**
### **1)ArrayList**
ArrayList 新增元素有两种情况,一种是直接将元素添加到数组末尾,一种是将元素插入到指定位置。
......@@ -277,7 +282,7 @@ public void add(int index, E element) {
先检查插入的位置是否在合理的范围之内,然后判断是否需要扩容,再把该位置以后的元素复制到新添加元素的位置之后,最后通过索引将元素添加到指定的位置。这种情况是非常伤的,性能会比较差。
**2)LinkedList**
### **2)LinkedList**
LinkedList 新增元素也有两种情况,一种是直接将元素添加到队尾,一种是将元素插入到指定位置。
......@@ -499,9 +504,9 @@ ArrayList 花费的时间比 LinkedList 要少一些。
当然了,如果涉及到数组扩容的话,ArrayList 的性能就没那么可观了,因为扩容的时候也要复制数组。
### 04、ArrayList 和 LinkedList 删除元素时究竟谁快?
## 04、ArrayList 和 LinkedList 删除元素时究竟谁快?
**1)ArrayList**
### **1)ArrayList**
ArrayList 删除元素的时候,有两种方式,一种是直接删除元素(`remove(Object)`),需要直先遍历数组,找到元素对应的索引;一种是按照索引删除元素(`remove(int)`)。
......@@ -551,7 +556,7 @@ private void fastRemove(Object[] es, int i) {
从源码可以看得出,只要删除的不是最后一个元素,都需要数组重组。删除的元素位置越靠前,代价就越大。
**2)LinkedList**
### **2)LinkedList**
LinkedList 删除元素的时候,有四种常用的方式:
......@@ -672,9 +677,9 @@ ArrayList从集合尾部位置删除元素花费的时间8
LinkedList从集合尾部位置删除元素花费的时间12
```
### 05、ArrayList 和 LinkedList 遍历元素时究竟谁快?
## 05、ArrayList 和 LinkedList 遍历元素时究竟谁快?
**1)ArrayList**
### **1)ArrayList**
遍历 ArrayList 找到某个元素的话,通常有两种形式:
......@@ -718,7 +723,7 @@ int indexOfRange(Object o, int start, int end) {
根据元素找索引的话,就需要遍历整个数组了,从头到尾依次找。
**2)LinkedList**
### **2)LinkedList**
遍历 LinkedList 找到某个元素的话,通常也有两种形式:
......@@ -837,8 +842,13 @@ private class ListItr implements ListIterator<E> {
也就是说,for 循环遍历的时候,ArrayList 花费的时间远小于 LinkedList;迭代器遍历的时候,两者性能差不多。
### 06、总结
花了两天时间,终于肝完了!相信看完这篇文章后,再有面试官问你 ArrayList 和 LinkedList 有什么区别的话,你一定会胸有成竹地和他扯上半小时了。
----
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
---
title: 衡量Java集合框架执行效率的重要标准:时间复杂度
shortTitle: 时间复杂度
category:
- Java核心
tag:
- 集合框架(容器)
description: Java程序员进阶之路,小白的零基础Java教程,Java 时间复杂度
head:
- - meta
- name: keywords
content: Java,Java SE,Java 基础,Java 教程,Java 程序员进阶之路,Java 入门,Java 时间复杂度
---
“二哥,为什么要讲时间复杂度呀?”三妹问。
“因为接下来要用到啊。后面我们学习 ArrayList、LinkedList 的时候,会比较两者在增删改查时的执行效率,而时间复杂度是衡量执行效率的一个重要标准。”我说。
“到时候跑一下代码,统计一下前后的时间差不更准确吗?”三妹反问道。
“实际上,你说的是另外一种评估方法,这种评估方法可以得出非常准确的数值,但也有很大的局限性。”我不急不慢地说。
第一,测试结果会受到测试环境的影响。你比如说,同样的代码,在我这台 iMac 上跑出来的时间和在你那台华为的 MacBook 上抛出的时间可能就差别很大。
第二,测试结果会受到测试数据的影响。你比如说,一个排序后的数组和一个没有排序后的数组,调用了同一个查询方法,得出来的结果可能会差别特别大。
“因此,我们需要这种不依赖于具体测试环境和测试数据就能粗略地估算出执行效率的方法,时间复杂度就是其中的一种,还有一种是空间复杂度。”我继续补充道。
来看下面这段代码:
```java
public static int sum(int n) {
int sum = 0; // 第 1 行
for (int i=0;i<n;i++) { // 第 2 行
sum = sum + 1; // 第 3 行
} // 第 4 行
return sum; // 第 5 行
}
```
这段代码非常简单,方法体里总共 5 行代码,包括“}”那一行。每段代码的执行时间可能都不大一样,但假设我们认为每行代码的执行时间是一样的,比如说 unit_time,那么这段代码总的执行时间为多少呢?
“这个我知道呀!”三妹喊道,“第 1、5 行需要 2 个 unit_time,第 2、3 行需要 2*n*unit_time,总的时间就是 2(n+1)*unit_time。”
“对,一段代码的执行时间 T(n) 和总的执行次数成正比,也就是说,代码执行的次数越多,花费的时间就越多。”我总结道,“这个规律可以用一个公式来表达:”
> T(n) = O(f(n))
f(n) 表示代码总的执行次数,大写 O 表示代码的执行时间 T(n) 和 f(n) 成正比。
这也就是大 O 表示法,它不关心代码具体的执行时间是多少,它关心的是代码执行时间的变化趋势,这也就是时间复杂度这个概念的由来。
对于上面那段代码 `sum()` 来说,影响时间复杂度的主要是第 2 行代码,其余的,像系数 2、常数 2 都是可以忽略不计的,我们只关心影响最大的那个,所以时间复杂度就表示为 `O(n)`
常见的时间复杂度有这么 3 个:
## 1)`O(1)`
代码的执行时间,和数据规模 n 没有多大关系。
括号中的 1 可以是 3,可以是 5,可以 100,我们习惯用 1 来表示,表示这段代码的执行时间是一个常数级别。比如说下面这段代码:
```java
int i = 0;
int j = 0;
int k = i + j;
```
实际上执行了 3 次,但我们也认为这段代码的时间复杂度为 `O(1)`
## 2)`O(n)`
时间复杂度和数据规模 n 是线性关系。换句话说,数据规模增大 K 倍,代码执行的时间就大致增加 K 倍。
## 3)`O(logn)`
时间复杂度和数据规模 n 是对数关系。换句话说,数据规模大幅增加时,代码执行的时间只有少量增加。
来看一下代码示例,
```java
public static void logn(int n) {
int i = 1;
while (i < n) {
i *= 2;
}
}
```
换句话说,当数据量 n 从 2 增加到 2^64 时,代码执行的时间只增加 64 倍。
```
遍历次数 | i
----------+-------
0 | i
1 | i*2
2 | i*4
... | ...
... | ...
k | i*2^k
```
“好了,三妹,这节就讲到这吧,理解了上面 3 个时间复杂度,后面我们学习 ArrayList、LinkedList 的时候,两者在增删改查时的执行效率就很容易对比清楚了。”我伸了个懒腰后对三妹说,“整体上,集合框架就这么多东西了,随后我们会一一展开来讲,比如说 ArrayList、LinkedList、HashMap 等。”。
“好的,二哥。”三妹重新回答沙发上,一盘王者荣耀即将开始。
----
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
关注二哥的原创公众号 **沉默王二**,回复**111** 即可免费领取。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png)
\ No newline at end of file
......@@ -150,15 +150,14 @@ head:
- [一万字彻底搞懂 Java 继承(三大特征之一)](oo/extends-bigsai.md)
- [几句话,直观解释清楚 Java 多态(三大特征之一)](oo/polymorphism.md)
### 集合框架(容器)
- [Java集合框架](collection/gailan.md)
- [Java集合ArrayList详解](collection/arraylist.md)
- [Java集合LinkedList详解](collection/linkedlist.md)
- [Java中ArrayList和LinkedList的区别](collection/list-war-2.md)
- [Java中的Iterator和Iterable区别](collection/iterator-iterable.md)
- [Java 集合框架(容器)体系结构](collection/gailan.md)
- [衡量Java集合框架执行效率的重要标准:时间复杂度](collection/time-complexity.md)
- [Java ArrayList详解(附源码分析)](collection/arraylist.md)
- [Java LinkedList详解(附源码分析)](collection/linkedlist.md)
- [面试官问我Java中ArrayList和LinkedList的区别,我和他扯了半小时](collection/list-war-2.md)
- [Java中Iterator和Iterable区别](collection/iterator-iterable.md)
- [为什么阿里巴巴强制不要在foreach里执行删除操作](collection/fail-fast.md)
- [Java8系列之重新认识HashMap](collection/hashmap.md)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册