Java集合基本概述
Java集合实现了接口和实现类相分离,同时支持泛型。
在数据结构课上,我们可能对物理结构和逻辑结构有所了解。
物理结构:顺序表
、链表
…
逻辑结构:线性表
、队列
、栈
…
在Java中数据的物理结构对应着实现类,逻辑结构对应着接口。
如下图所示
- 黄色框为物理结构,对应着实现类。
- 绿色框为逻辑结构,对应着接口。
因为接口的可操作范围较小,所以通常用接口来接管实现类,这样在编译期间就可以避免一些错误,如下:
// 我们明确需要使用一个队列 (Java中没有实现顺序队列,因为队列大部分操作都是插入与删除,链表会快很多)
LinkedList<Integer> queue = new LinkedList<>();
queue.set(0, 2); // 不允许从队列中插入,但是此时编译器不会报错
Queue<Integer> queue2 = new LinkedList<>();
queue2.set(0, 3); // 编译器报错
Java常用集合的一些操作方法
List --> 线性表
// 创建一个线性表
List<Integer> arrayList = new ArrayList<>();
// 创建一个链表
List<Integer> linkedList = new LinkedList<>();
// 在方法层面,arrayList和linkedList是一致。
arrayList.size();
arrayList.isEmpty();
arrayList.get(i);
arrayList.set(i, x);
arrayList.add(i, x);
arrayList.remove(i);
arrayList.indexOf(x); // 第一个值为x的索引
arrayList.lastIndexOf(x); // 最后一个值为x的索引
arrayList.subList(fromIndex, toIndex); // 获取子串
Queue --> 队列
// 创建一个队列
Queue<Integer> queue = new LinkedList<>();
// 入队
queue.add(x); // 插入后超出队列界限的时候,会抛出异常
queue.offer(x); // 插入后超出队列界限的时候,返回false
// 出队
int e1 = queue.remove(); // 队列为空时,会抛出异常
int e2 = queue.poll(); // 队列为空时,返回null
// 获取队头元素
int e3 = queue.element(); // 队列为空时,会抛出异常
int e4 = queue.peek(); // 队列为空时,返回null
Deque --> 栈 or 双端队列
在Java中,栈可以用Deque
来实现。
注意,当Deque
用作栈时,只调用push()
,pop()
,peek()
方法,避免调用其他方法。
不要使用老式基于Vector
的Stack
。
// 误区,直接new接口来创建一个栈
Deque<Integer> stack = new Deque<>(); // 接口不能用new来创建实例。
// 正确创建一个栈
Deque<Integer> stack = new LinkedList<>();
// 入栈
stack.push(x); // 若入栈后,超出界限,会抛出异常。
// 出栈
int x = stack.pop(); // 若栈为空,抛出异常
// 获取栈顶元素
int x = stack.peek(); // 若栈为空,抛出异常
双端队列参考 : 廖雪峰 Deque
PriorityQueue --> 优先队列
PriorityQueue是一个优先队列,其内部结构为 “堆”,是有序的。
遍历时,元素递增。 删除元素时,始终删除最小的元素。
时间复杂度:
建堆时间:O(N)
插入与删除:O(logN) -> logN为树的高度,向下调整次数为树的高度。
// 方法名与队列基本一致
// 创建一个队列
PriorityQueue <Integer> priorityQueue = new PriorityQueue<>();
// 入队
priorityQueue.add(x); // 插入后超出队列界限的时候,会抛出异常
priorityQueue.offer(x); // 插入后超出队列界限的时候,返回false
// 出队
int e1 = priorityQueue.remove(); // 队列为空时,会抛出异常
int e2 = priorityQueue.poll(); // 队列为空时,返回null
// 获取队头元素
int e3 = priorityQueue.element(); // 队列为空时,会抛出异常
int e4 = priorityQueue.peek(); // 队列为空时,返回null
// 遍历
for (int v : priorityQueue) {
System.out.println(v);
}
Set
Set
用于存储不重复的元素集合
// 创建Set
Set<String> set = new HashSet<>();
// 添加元素
set.add("Marry"); // 若Marry已存在,返回false
// 查找某个元素是否存在
set.contain("Marry") // 返回true,因为元素存在
// 删除某个元素
set.remove("Marry"); // 若元素存在返回true,否则返回false
// 获取元素个数
set.size();
// 遍历
for (String str : set) {
System.out.println(str);
}
Map
Map
是一个key-value对,实现类有基于哈希表的HashMap
、基于红黑树的TreeMap
。Map的key与Set一样,无法重复。
HashMap
:key无序,插入元素可在O(1)完成TreeMap
:key是有序的,插入元素时间复杂度为O(logN)
// 创建一个HashMap
Map<String, Integer> hashMap = new HashMap<>();
// 创建一个TreeMap
Map<String, Integer> treeMap = new TreeMap<>();
// 添加
map.put("we", 1);
map.put("we", 2); // 在同一个key上put,会替换原来的value。 此时{"we" : 2}
map.size(); // 1
// 获得
map.get("we"); // we存在,返回其值2。
map.get("our") // our不存在,返回null。
// 删除
map.remove("we"); // 删除成功,返回2.
map.remove("our"); // 删除失败,返回null。
// 遍历
for (String key : map.keyset()) {
System.out.println(key);
}
for (Integer value : map.values()) {
System.out.println(value);
}