声明:本文主要作为作者的复习笔记,由于作者水平有限,难免有错误和不准确之处,欢迎读者批评指正。
ArrayList => 底层是基于动态数组的实现
LinkedList => 底层是基于双向链表的实现
| 不同点 | ArrayList | LinkedList |
|---|---|---|
| 存储空间上 | 物理上一定连续 | 逻辑上连续,但物理上不一定连续 |
| 随机访问 | 支持;O(1) | 不支持;O(N) |
| 头插 | 需要搬移元素,效率低O(N) | 只需修改引用的指向,时间复杂度为O(1) |
| 插入 | 空间不够时需要扩容 | 没有容量的概念 |
| 应用场景 | 元素高效存储+频繁访问 | 任意位置插入和删除(频繁) |
若ArrayList和LinkedList都默认调用add方法进行插入,这两个结构都在进行尾插;其实数组的尾插比链表还快elementData[size++] = val;
栈和队列都是添加和删除元素操作受限的线性表,本质上栈和队列没什么不同,可以相互转换,都是线性表的一种;
栈:树型结构的dfs(深度优先遍历 - 前中后序)
队列:树型结构的bfs(广度优先遍历 - 层序遍历)
应用场景
可以使用栈来模拟队列,同样的,也可以使用队列来模拟栈的实现;
一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

操作受限的线性表,只能从队列的一端添加元素(队尾),从队列的另一端删除元素(队首);

循环队列使用定长数组来实现,数组的首尾相连就构成了循环队列(就是走到数组最后一个元素时,下一个访问的就是数组的首地址);循环队列一般用在os生存消费者模型。
判断循环队列是否为空:head == tail
判断循环队列是否已满:(tail + 1)% num.length == head;
在循环队列中,浪费空间的位置不是固定的,每次(tail + 1)% num.length到head之前的那个空间是浪费的。
在任意时刻
int lastIndex = tail == 0 ?num.length - 1 : tail - 1;
队列中的有效元素 [head…lastIndex];
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque是“double ended queue”的简称;
Deque接口的使用
//使用Deque作为栈,方法名都不变 push pop peek
Deque<Integer> stack = new LinkedList<>();
stack.push(1);
stack.push(3);
stack.push(5);
stack.push(7);
System.out.println(stack);
//输出7
System.out.println(stack.pop());
//使用Deque作为队列,方法名不变 offer poll peek
Deque<Integer> queue = new ArrayDeque<>();
queue.offer(2);
queue.offer(4);
queue.offer(6);
queue.offer(8);
System.out.println(queue);
//输出2
System.out.println(queue.poll());
数组,链表,栈,队列,字符串(char[ ] 多个字符呈线性排列);