Java操作蓝图:常用数据结构与方法

这是为了可以快速使用各种常用数据结构和方法的蓝图集合,通过给出一个空框架,提高效率。

最近刷题陷入了迷茫,往往不知道该用什么数据结构,所以我决定写一个蓝图,方便以后使用。

数据结构及其应用
数据结构是计算机存储和组织数据的方式,在工作中,我们通常会直接调用已经封装好的集合API,这样可以更高效的存储和访问数据,提高程序效率

我们的开发学习过程中需要和大量的数据打交道,一般使用集合容器完成

目录

  1. 数组(Array)
  2. 列表(List/ArrayList)
  3. 链表(LinkedList)
  4. 栈(Stack)
  5. 队列(Queue)
  6. 优先队列(PriorityQueue)
  7. 集合(Set/HashSet)
  8. 有序集合(TreeSet)
  9. 映射(Map/HashMap)
  10. 有序映射(TreeMap)
  11. 字符串操作(String)
  12. 工具类(Collections/Arrays)

接下来我对以上12个常用数据结构的用途做下简单的描述
数组:

  • 用途:固定大小的连续内存空间,存储相同类型元素
  • 解决问题:快速随机访问,内存紧凑

列表:

  • 用途:动态数组,自动扩容
  • 解决问题:需要动态调整大小的数组

链表:

  • 用途:双向链表实现,高效插入删除
  • 解决问题:频繁在列表中间进行插入/删除操作

栈:

  • 用途:后进先出(LIFO)结构
  • 解决问题:需要后进先出逻辑的场景,如撤销操作、括号匹配

队列:

  • 用途:先进先出(FIFO)结构
  • 解决问题:任务调度、广度优先搜索等

优先队列:

  • 用途:元素按照优先级排序的队列
  • 解决问题:需要按照优先级处理元素的场景

集合:

  • 用途:存储唯一元素的集合
  • 解决问题:去重、查找

有序集合:

  • 用途:元素按照自然顺序或自定义顺序排序的集合
  • 解决问题:需要元素有序的场景

映射:

  • 用途:键值对存储
  • 解决问题:根据键快速查找值

有序映射:

  • 用途:键值对按照键的自然顺序或自定义顺序排序
  • 解决问题:需要键值对有序的场景

树:

  • 用途:有序二叉树实现,高效查找
  • 解决问题:有序键值对的集合

字符串操作:

  • 用途:处理文本数据
  • 解决问题:字符串拼接、查找、替换

工具类:

  • 用途:提供各种常用操作的静态方法
  • 解决问题:简化常见操作,如排序、查找、比较等

集合容器(collection)

集合容器是Java中用于存储和操作对象的容器,主要包括List、Set、Map等接口和它们的实现类。集合容器提供了丰富的方法来添加、删除、查找和操作元素,并且可以根据需要自动调整大小。

collection:集合类的父类(接口)包含了集合框架的基本操作

List接口:

  • 有序集合:List中的每个元素都有(下标)索引,可以根据索引访问元素
  • 允许重复元素
  • 常用实现类:ArrayList、LinkedList
    Set接口:
  • 不允许重复元素
  • 常用实现类:HashSet、TreeSet
    Map接口:
  • 键值对存储
  • 键不允许重复
  • 常用实现类:HashMap、TreeMap

collection中的常用方法

我先用个大表来整理出来方法摘要,数据类型包括在里面的,方法摘要包括返回值,方法名,参数,作用,并用所属接口来分类(List,Set,Map)。

方法摘要 返回值 方法名 参数 作用 所属接口
boolean add(E e) boolean 添加元素 E e 将指定元素添加到集合中 List,Set
void clear() void 清空集合 移除集合中的所有元素 List,Set
boolean contains(Object o) boolean 包含元素 Object o 判断集合是否包含指定元素 List,Set
boolean equals(Object o) boolean 比较相等 Object o 比较集合与指定对象是否相等 List,Set
int hashCode() int 哈希码 返回集合的哈希码值 List,Set
boolean isEmpty() boolean 为空 判断集合是否为空 List,Set
int size() int 大小 返回集合中的元素数量 List,Set
Object[] toArray() Object[] 数组 返回包含集合中所有元素的数组 List,Set
boolean remove(Object o) boolean 移除元素 Object o 移除集合中指定元素 List,Set
boolean containsAll(Collection<?> c) boolean 包含所有 Collection<?> c 判断集合是否包含指定集合的所有元素 List,Set
boolean removeAll(Collection<?> c) boolean 移除所有 Collection<?> c 移除集合中包含指定集合的所有元素 List,Set
boolean retainAll(Collection<?> c) boolean 保留所有 Collection<?> c 仅保留集合中包含指定集合的元素 List,Set
default Stream parallelStream() Stream 并行流操作 返回集合的并行流,用于并发操作 List,Set
default Stream stream() Stream 顺序流操作 返回集合的顺序流,用于顺序操作 List,Set
default void forEach(Consumer<? super E> action) void 遍历操作 Consumer<? super E> action 对集合中的每个元素执行指定操作 List,Set
default Spliterator spliterator() Spliterator 拆分迭代器 返回集合的拆分迭代器,用于并行操作 List,Set
default boolean removeIf(Predicate<? super E> filter) boolean 移除满足条件 Predicate<? super E> filter 移除满足指定条件的元素 List

不行再去查api文档喔

由于collection是接口无法使用,并且List,set,map都是collection的子接口,所以我们在使用的时候都是用它的实现类。ArrayList,LinkedList,HashSet,TreeSet,HashMap,TreeMap等。

info 由于collection是接口无法使用,并且List,set,map都是collection的子接口,所以我们在使用的时候都是用它的实现类。ArrayList,LinkedList,HashSet,TreeSet,HashMap,TreeMap等。

List

List接口:有序集合,每个元素都有索引,可以根据索引访问元素。常用实现类有ArrayList和LinkedList,Vector。

  • ArrayList:基于动态数组实现,支持随机访问,适用于频繁读取元素。
  • LinkedList:基于双向链表实现,适用于频繁插入/删除元素。
  • Vector:与ArrayList类似,但线程安全,适用于多线程环境

简单使用方法的蓝图:

在使用List时候,请尽量避免在一个方法中使用多种数据类型,用泛型进行限定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 创建一个ArrayList
List<String> list = new ArrayList<>();
// 添加元素
list.add("元素1");
list.add("元素2");
// 获取元素
String element = list.get(0);
//检查是否为空
if(list.isEmpty()){
System.out.println("列表为空");
}
//集合中元素的数量
int size = list.size();
//判断包含某个元素
boolean contains = list.contains("元素1");
//遍历列表
for (String item : list) {
System.out.println(item);
}
//遍历列表(2)
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//删除元素
list.remove("元素1");
//将列表转换为数组
Object[] array = list.toArray();
//数组排序
Arrays.sort(array);
//数组转换为列表
List<String> sortedList = Arrays.asList(array);


自定义泛型(想看就看,不看也就讲究理解下)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.ListConom;

import com.classTestingPackage.Class.MyDate;

public class CustomGeneric<E> {
// 数组容器
private static final int DEFAULT_CAPACITY = 10;
// 定义Object数组
private Object[] array;
// 当前元素数量
private int size = 0;

// 构造函数
public CustomGeneric() {
this.array = new Object[DEFAULT_CAPACITY];
}

public CustomGeneric(int capacity) {
this.array = new Object[capacity > 0 ? capacity : DEFAULT_CAPACITY];
}

// 指定位置插入数据
public void add(int index, E element) {
checkIndexForAdd(index);
ensureCapacity(size + 1);
// 移动元素
System.arraycopy(array, index, array, index + 1, size - index);
array[index] = element;
size++;
}

// 数组末尾添加数据
public void add(E element) {
ensureCapacity(size + 1);
array[size++] = element;
}

// 数组中获得数据
public E get(int index) {
checkIndex(index);
return (E) array[index];
}

// 获取当前元素数量
public int size() {
return this.size;
}

// 扩容检查
private void ensureCapacity(int minCapacity) {
if (minCapacity > array.length) {
int newCapacity = array.length * 2;
Object[] newArray = new Object[newCapacity];
System.arraycopy(array, 0, newArray, 0, size);
array = newArray;
}
}

// 索引检查
private void checkIndex(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}

// 添加操作的索引检查
private void checkIndexForAdd(int index) {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}

public static void main(String[] args) {
// 自定义集合
CustomGeneric<String> array = new CustomGeneric<>();
// 插入数据
array.add(0, "jack");
array.add(1, "tom");
array.add("jerry");

System.out.println(array.get(0)); // 输出: jack
System.out.println(array.size()); // 输出: 3
}
}

Set

Set接口:不允许重复元素,常用实现类有HashSet和TreeSet。

  • HashSet:基于哈希表实现,不保证有序,不允许重复元素。
  • TreeSet:基于红黑树实现,有序集合,不允许重复元素。

Map

Map接口:键值对存储,键不允许重复,常用实现类有HashMap和TreeMap。

  • HashMap:基于哈希表实现,键无序,不允许重复键。
  • TreeMap:基于红黑树实现,键有序,不允许重复键。
  • Hashtable:和HashMap类似,但线程安全,不允许null键或值。F

三个非常近似的数据结构(数组,列表,链表)

表格区分下这几个结构的区别:

数据结构 存储方式 插入/删除效率 查找效率 适用场景
数组 连续内存 固定大小,随机访问
列表 离散内存 动态大小,顺序访问
链表 离散内存 动态大小,任意访问

说人话理解就是:

数组:就像一排整齐的盒子,每个盒子都有固定的位置。你可以根据盒子的编号(索引)快速找到特定的盒子。但是,如果你需要在中间添加或删除盒子,效率会很低,因为你需要移动其他盒子的位置。
列表:就像一个队伍,每个人都有自己的位置,但不一定是按顺序排的。如果你需要找排在第3位的人,你只能一个一个人往后面数。但是,如果你需要在队伍中间加入一个人,你可以直接让他站在第3位,而其他人不需要改变位置。
链表:就像一列火车,每节车厢都有自己的位置,但是车厢之间通过钩钩连接。你可以随时在任何车厢之间加入或移除车厢,而不需要改变其他车厢的位置。

那么我什么时候用什么呢?

info 提示块标签

数组(Array)

数组是一种线性数据结构,用于存储相同类型的元素。数组的特点是:

  1. 元素有序:数组中的元素按照索引顺序存储,每个元素都有一个唯一的位置。
  2. 固定大小:数组一旦创建,其大小就不能改变。
  3. 随机访问:可以通过索引直接访问数组中的任意元素。

和链表和列表做出区别:

  1. 存储方式:数组在内存中是连续存储的,而链表和列表通常是离散存储的。
  2. 插入/删除效率:在数组中间插入或删除元素需要移动后续元素,效率较低,而链表和列表可以在常数时间内完成这些操作。
  3. 查找效率:数组支持随机访问,通过索引可以在常数时间内找到任意元素,而链表和列表通常需要线性查找。

用途:固定大小的连续内存空间,存储相同类型元素
解决问题:快速随机访问,内存紧凑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 声明与初始化
int[] arr = new int[10]; // 声明长度为10的整型数组
int[] arr2 = {1, 2, 3}; // 声明并初始化

// 常用操作
arr[0] = 5; // 赋值
int length = arr.length; // 获取长度(不是方法,是属性)

// 遍历数组
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}

// 增强for循环
for (int num : arr) {
System.out.println(num);
}

// 多维数组
int[][] matrix = new int[3][3];
matrix[0][0] = 1;

//扩容操作
int[] arr = {1, 2, 3};
arr = Arrays.copyOf(arr, arr.length * 2); // 扩容到当前长度的2倍

//如果用循环的方式来实现扩容操作
int[] arr = {1, 2, 3};
int[] newArr = new int[arr.length * 2]; // 新数组长度为旧数组的倍
for (int i = 0; i < arr.length; i++) {
newArr[i] = arr[i]; // 复制旧数组元素
}
arr = newArr; // 新数组替换旧数组

// 常用方法
Arrays.sort(arr); // 数组排序
Arrays.equals(arr1, arr2); // 比较数组内容
Arrays.toString(arr); // 数组转字符串
System.arraycopy(arr1, 0, arr2, 0, arr1.length); // 数组复制
Arrays.binarySearch(arr, 5); // 二分查找 (数组必须有序)

// 数组转换为列表
List<Integer> list = Arrays.asList(1, 2, 3);
// 注意:转换后的列表不能添加或删除元素,否则会抛出UnsupportedOperationException异常
// 如果需要修改列表,建议先复制到新列表
List<Integer> modifiableList = new ArrayList<>(list);
modifiableList.add(4); // 添加元素

ArrayList底层使用数组来存储元素,所以它的随机访问效率高,但在列表中间插入/删除元素的效率较低。线程不安全

从代码可以发现底层使用Object数组来存储元素,初始化长度大小为10,ArrayList的存储操作都是围绕着这个数组来进行的,但是数组的长度固定,为了无需指定长度,每次添加元素时,都需要判断数组是否已满,如果已满则需要扩容,扩容的大小为原来的1.5倍,然后将原数组的元素复制到新数组中,来实现扩容。


列表(List/ArrayList)

列表是一种有序的集合,允许重复元素。列表的主要实现类是ArrayList,它提供了动态数组的功能。

和数组做出区别:

  1. 长度可变:数组长度固定,而列表长度可变。
  2. 存储类型:数组可以存储基本类型和引用类型,而列表只能存储引用类型。
  3. 性能:在列表中间插入/删除元素的性能通常比数组差,因为需要移动后续元素。而随机访问元素的性能与数组相同。

用途:动态数组,自动扩容
解决问题:需要动态调整大小的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 创建ArrayList
List<String> list = new ArrayList<>(); // 推荐使用接口类型声明

// 添加元素
list.add("Apple");
list.add(0, "Banana"); // 在指定位置插入

// 获取元素
String fruit = list.get(0);

// 修改元素
list.set(0, "Orange");

// 删除元素
list.remove(0); // 按索引删除
list.remove("Orange"); // 按元素删除

// 大小检查
int size = list.size();
boolean isEmpty = list.isEmpty();

// 包含检查
boolean contains = list.contains("Apple");

// 遍历
for (String item : list) {
System.out.println(item);
}

// 使用迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}

// 转换为数组
String[] array = list.toArray(new String[0]);

// 常用方法
list.add("Cherry"); // 添加元素
list.remove("Apple"); // 删除元素
list.contains("Banana"); // 检查元素是否存在
list.size(); // 获取大小
list.isEmpty(); // 检查是否为空
list.get(0); // 获取元素
list.set(0, "New"); // 修改元素
list.indexOf("Cherry"); // 查找元素索引
list.subList(1, 3); // 获取子列表
list.clear(); // 清空列表
list.add("Apple"); // 添加元素
list.add("Banana"); // 添加元素
list.add("Cherry"); // 添加元素
list.add("Apple"); // 添加元素
list.remove("Apple"); // 删除第一个匹配项
list.removeAll(Collections.singleton("Apple")); // 删除所有匹配项


链表(LinkedList)

链表是一种常见的动态数据结构,由节点组成,每个节点包含数据和指向下一个节点的引用。把它当成火车皮,每一个节点可以接在其他节点后

和列表的区别:

  1. 存储方式:链表节点离散存储,而列表通常是连续存储的。
  2. 插入/删除效率:在链表中间插入或删除元素只需改变引用,而列表需要移动后续元素。
  3. 查找效率:链表通常需要线性查找,而列表支持随机访问。

用途:双向链表实现,高效插入删除
解决问题:频繁在列表中间进行插入/删除操作

下面是代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 创建LinkedList
List<String> linkedList = new LinkedList<>();

// 添加元素 (与ArrayList类似)
linkedList.add("A");
linkedList.addFirst("B"); // 特有方法
linkedList.addLast("C"); // 特有方法

// 获取元素
String first = linkedList.getFirst();
String last = linkedList.getLast();

// 删除元素
linkedList.removeFirst();
linkedList.removeLast();

// 作为队列使用
Queue<String> queue = new LinkedList<>();
queue.offer("A"); // 入队
queue.poll(); // 出队

// 作为栈使用 (推荐)
Deque<String> stack = new ArrayDeque<>();
stack.push("A"); // 压栈
stack.pop(); // 出栈

// 常用方法
linkedList.contains("B"); // 检查元素是否存在
linkedList.size(); // 获取大小
linkedList.isEmpty(); // 检查是否为空
linkedList.get(0); // 获取元素 (性能低,不推荐)
linkedList.set(0, "New"); // 修改元素 (性能低,不推荐)
linkedList.indexOf("B"); // 查找元素索引 (性能低,不推荐)
linkedList.subList(1, 3); // 获取子列表 (性能低,不推荐)
linkedList.clear(); // 清空列表
linkedList.add("Apple"); // 添加元素
linkedList.remove("Apple"); // 删除第一个匹配项
linkedList.removeAll(Collections.singleton("Apple")); // 删除所有匹配项


栈(Stack)

弹匣结构理解

栈结构:
栈是一种线性数据结构,它的特点是只能在栈顶进行插入和删除操作。栈的操作只能从栈顶进行,这意味着最后一个放入栈中的元素是第一个被弹出的。栈通常用于需要后进先出(LIFO)逻辑的场景,如撤销操作、括号匹配等。

栈的主要操作包括:

  1. 压栈(Push):将元素放入栈顶。
  2. 弹栈(Pop):移除栈顶元素。
  3. 查看栈顶元素(Peek):返回栈顶元素,但不弹出。

用途:后进先出(LIFO)结构
解决问题:需要后进先出逻辑的场景,如撤销操作、括号匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 创建栈 (推荐使用Deque实现)
Deque<Integer> stack = new ArrayDeque<>();

// 压栈
stack.push(1);
stack.push(2);

// 弹栈
int top = stack.pop();

// 查看栈顶元素
int peek = stack.peek();

// 检查是否为空
boolean empty = stack.isEmpty();

// 栈大小
int size = stack.size();

// 遍历栈 (不推荐)
for (int item : stack) {
System.out.println(item);
}

// 清空栈
stack.clear();

队列(Queue)

水管结构理解

队列结构:
队列是一种线性数据结构,它的特点是只能在队尾插入元素,在队首删除元素。队列的操作只能从队首进行,这意味着最早进入队列的元素是第一个被移除的。队列通常用于需要先进先出(FIFO)逻辑的场景,如任务调度、广度优先搜索等。

用途:先进先出(FIFO)结构
解决问题:任务调度、广度优先搜索等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 创建队列 (LinkedList实现)
Queue<String> queue = new LinkedList<>();

// 入队
queue.offer("A"); // 推荐使用offer而不是add(不抛异常)
queue.add("B"); // 可能抛出异常

// 出队
String item = queue.poll(); // 返回并移除队首,队列为空返回null
String item2 = queue.remove(); // 队列为空抛出异常

// 查看队首
String head = queue.peek(); // 队列为空返回null
String head2 = queue.element(); // 队列为空抛出异常

// 大小
int size = queue.size();

// 遍历队列 (不推荐)
for (String item : queue) {
System.out.println(item);
}

// 清空队列
queue.clear();

// 常用方法
queue.contains("B"); // 检查元素是否存在
queue.size(); // 获取大小
queue.isEmpty(); // 检查是否为空
queue.offer("C"); // 入队
queue.poll(); // 出队
queue.peek(); // 查看队首 (不删除)

优先队列(PriorityQueue)

优先队列结构:
优先队列是一种特殊的队列,它的元素按照优先级进行排序。每个元素都有一个与之关联的优先级,当从队列中取出元素时,具有最高优先级的元素先被取出。优先队列通常用于需要按优先级顺序处理元素的场景,如任务调度、最短路径算法等。

用途:按优先级出队的队列
解决问题:需要按特定顺序处理元素的场景,如任务调度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 创建优先队列 (默认最小堆)
PriorityQueue<Integer> pq = new PriorityQueue<>();

// 自定义比较器 (最大堆)
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);

// 添加元素
pq.offer(5);
pq.add(3);

// 获取并移除队首(最小元素)
int min = pq.poll();

// 查看队首
int peek = pq.peek();

// 大小
int size = pq.size();

// 遍历 (不推荐)
for (int item : pq) {
System.out.println(item);
}

// 清空队列
pq.clear();

// 常用方法
pq.contains(3); // 检查元素是否存在
pq.size(); // 获取大小
pq.isEmpty(); // 检查是否为空
pq.offer(4); // 入队
pq.poll(); // 出队
pq.peek(); // 查看队首 (不删除)
pq.remove(3); // 删除元素


集合(Set/HashSet)

集合结构:
集合是一种用于存储不重复元素的数据结构。集合通常用于需要去重或快速成员检查的场景。

用途:不包含重复元素的集合
解决问题:去重、快速成员检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// 创建HashSet
Set<String> set = new HashSet<>();

// 添加元素
set.add("Apple");
set.add("Banana");

// 检查存在
boolean hasApple = set.contains("Apple");

// 删除元素
set.remove("Apple");

// 大小
int size = set.size();

// 遍历
for (String item : set) {
System.out.println(item);
}
//迭代器
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
//增强for循环和迭代器结合
for (Iterator<String> iter = set.iterator(); iter.hasNext();) {
String item = iter.next();
System.out.println(item);
}

// 集合运算
Set<String> otherSet = new HashSet<>(Arrays.asList("Banana", "Orange"));

set.retainAll(otherSet); // 交集
set.addAll(otherSet); // 并集
set.removeAll(otherSet); // 差集

// 清空集合
set.clear();

// 常用方法
set.contains("Apple"); // 检查元素是否存在
set.size(); // 获取大小
set.isEmpty(); // 检查是否为空
set.add("Cherry"); // 添加元素
set.remove("Apple"); // 删除元素

// 遍历 (不推荐)
for (String item : set) {
System.out.println(item);
}

如果我要在HashSet中比较两个对象是否相等,我需要重写equals方法,因为默认的equals方法是比较对象的地址是否相等

以下是equals方法的重写,针对setHashSet,作用是判断两个对象是否相等,相等的标准是对象的属性值是否相等,
如果不重写equals方法,那么默认是比较对象的地址是否相等,即是否是同一个对象,
如果重写equals方法,那么就可以比较对象的属性值是否相等,即是否是同一个对象。

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    public class equalreturn {
private String name;
private int age;

public equalreturn() {

}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public equalreturn(String name, int age) {
this.name = name;
this.age = age;
}

//重写equals方法
@Override
public boolean equals(Object o) {//判断是否为同一个对象
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;//判断对象是否为对应类型
equalreturn that = (equalreturn) o;//类型转换
return age == that.age && Objects.equals(name, that.name);
}

@Override
public int hashCode() {
return Objects.hash(name, age);
}

@Override
public String toString() {
return "equalreturn{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}


有序集合(TreeSet)

有序集合结构:
有序集合是一种特殊的集合,它的元素按照自然顺序或自定义顺序进行排序。有序集合中的元素是唯一的,不允许重复。有序集合通常用于需要有序遍历或范围查询的场景,如字典、排行榜等。

用途:保持元素有序的集合
解决问题:需要有序遍历或范围查询的场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建TreeSet
Set<Integer> treeSet = new TreeSet<>();

// 自定义排序
Set<Integer> descSet = new TreeSet<>((a, b) -> b - a);

// 添加元素 (自动排序)
treeSet.add(3);
treeSet.add(1);
treeSet.add(2);

// 获取第一个和最后一个
int first = ((TreeSet<Integer>) treeSet).first();
int last = ((TreeSet<Integer>) treeSet).last();

// 范围查询
Set<Integer> subset = ((TreeSet<Integer>) treeSet).subSet(1, 3);

映射(Map/HashMap)

映射是一种键值对存储结构,每个元素包含一个键和一个对应的值。通过键可以找到值,Map存储的是键值对,键和值可以是任意类型的对象,键是唯一的,不能重复,如果插入重复的键,则会将其原有的键覆盖掉,值可以重复

用途:键值对存储结构
解决问题:快速键值查找、关联数据存储

Map不能直接使用迭代器遍历,得转换为Set集合,才能使用迭代器遍历

1
Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 创建HashMap
Map<String, Integer> map = new HashMap<>();

// 添加键值对
map.put("Apple", 10);
map.put("Banana", 20);

// 获取值
int appleCount = map.get("Apple");

// 检查键存在
boolean hasApple = map.containsKey("Apple");

// 获取全部的键
Set<String> keys = map.keySet();

//获取键值对所有的键值对的集合
Set<Map.Entry<K,V>>entrySet();

// 检查值存在
boolean has10 = map.containsValue(10);

//判断是否为空
boolean empty = map.isEmpty();

// 删除键值对
map.remove("Apple");//删除键,会将值返回给你一次

// 遍历键
for (String key : map.keySet()) {
System.out.println(key);
}

// 遍历值
for (Integer value : map.values()) {
System.out.println(value);
}

// 遍历键值对
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}

// 获取或默认值
int count = map.getOrDefault("Orange", 0);

// 合并操作
map.merge("Apple", 1, Integer::sum); // 如果存在则相加,否则put 1

Entry键值对对象

在Map集合中提供了获取所有Entry(每个键值对对象)对象的方法,获取所有键值对对象的集合。

1
2
3
4
5
6
7
8
9
// entrySet 所有的键值对对象,返回的是一个Set集合
Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
// 遍历entrySet集合,得到里面的每个键值对对象(Entry对象)
for (Map.Entry<String,Integer> entry : entrySet){
String Key = entry.getKey();
// 从entry中获取键值对
Integer value = entry.getValue();
System.out.println(Key + "\t" + value);
}

有序映射(TreeMap)

SortedMap是接口,TreeMap是它的实现类。

用途:保持键有序的映射
解决问题:需要按键顺序遍历或范围查询的场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 创建TreeMap
Map<String, Integer> treeMap = new TreeMap<>();

// 自定义排序
Map<String, Integer> descMap = new TreeMap<>(Comparator.reverseOrder());

// 添加元素 (按键排序)
treeMap.put("Banana", 20);
treeMap.put("Apple", 10);

// 获取第一个和最后一个键
String firstKey = ((TreeMap<String, Integer>) treeMap).firstKey();
String lastKey = ((TreeMap<String, Integer>) treeMap).lastKey();

// 范围视图
Map<String, Integer> subMap = ((TreeMap<String, Integer>) treeMap).subMap("A", "C");

哈希表(HashTable)

哈希表(Hash Table)是一种根据键(Key)直接访问值(Value)的数据结构。它通过哈希函数将键映射到数组的索引位置,实现快速的插入、删除和查找操作。哈希表通常用于需要快速查找、插入和删除操作的数据场景,如缓存、索引和字典等。

用途:快速查找、插入和删除
解决问题:需要快速查找、插入和删除操作的数据场景

这玩意和HashMap的用法基本一致,只是Hashtable是线程安全的,HashMap不是线程安全的。

它添加了synchronizd关键字,所以在多线程环境下,它是安全的。但是在单线程环境下,它的效率比HashMap低。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 创建Hashtable
Hashtable<String, Integer> hashTable = new Hashtable<>();

// 添加键值对
hashTable.put("Apple", 10);
hashTable.put("Banana", 20);

// 获取值
int appleCount = hashTable.get("Apple");

// 检查键存在
boolean hasApple = hashTable.containsKey("Apple");

// 删除键值对
hashTable.remove("Apple");

// 遍历键
for (String key : hashTable.keySet()) {
System.out.println(key);
}

// 遍历值
for (Integer value : hashTable.values()) {
System.out.println(value);
}

// 遍历键值对
for (Map.Entry<String, Integer> entry : hashTable.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}

树(Tree)

树是一种非线性数据结构,由节点和边组成。每个节点可以有零个或多个子节点,除了根节点外,每个节点都有一个父节点。树的顶部是根节点,底部是叶节点。
用途:表示层次关系、有序集合
解决问题:组织和导航数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// 树节点定义
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}

// 树示例
TreeNode root = new TreeNode(1);
root.left = new TreeNode(2);
root.right = new TreeNode(3);
root.left.left = new TreeNode(4);
root.left.right = new TreeNode(5);

// 树遍历示例
// 中序遍历
void inorderTraversal(TreeNode root) {
if (root != null) {
inorderTraversal(root.left);
System.out.print(root.val + " ");
inorderTraversal(root.right);
}
}
// 前序遍历
void preorderTraversal(TreeNode root) {
if (root != null) {
System.out.print(root.val + " ");
preorderTraversal(root.left);
preorderTraversal(root.right);
}
}
// 后序遍历
void postorderTraversal(TreeNode root) {
if (root != null) {
postorderTraversal(root.left);
postorderTraversal(root.right);
System.out.print(root.val + " ");
}
}
// 层序遍历
void levelOrderTraversal(TreeNode root) {
if (root == null) return;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);

while (!queue.isEmpty()) {
TreeNode node = queue.poll();
System.out.print(node.val + " ");

if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
// 树高度
int getTreeHeight(TreeNode root) {
if (root == null) return 0;
int leftHeight = getTreeHeight(root.left);
int rightHeight = getTreeHeight(root.right);
return Math.max(leftHeight, rightHeight) + 1;
}
// 树节点数量
int getNodeCount(TreeNode root) {
if (root == null) return 0;
return 1 + getNodeCount(root.left) + getNodeCount(root.right);
}

这要下去没完没了了QAQ

辨析几种树去吧:
红黑树,B树,二叉树,AVL树,B+树,B-树,Trie树,哈夫曼树,字典树,后缀树区分(用表格描述):
| 树类型 | 特点 | 应用场景 |
| ——— | —— | ———— |
| 红黑树 | 自平衡二叉查找树,每个节点有颜色(红黑) | Java 中的 TreeMap 和 TreeSet |
| B 树 | 多路自平衡搜索树,适用于外存索引 | 数据库索引、文件系统 |
| 二叉树 | 每个节点最多有两个子节点 | 表达式树、二叉堆 |
| AVL 树 | 自平衡二叉查找树,通过旋转保持平衡 | 数据库索引 |
| B+ 树 | 多路自平衡搜索树,适用于外存索引 | 数据库索引、文件系统 |

一句话总结特点:

  • 红黑树:自平衡,每个节点颜色表示,适用于外存索引
  • B树:多路自平衡搜索树,适用于外存索引
  • 二叉树:每个节点最多有两个子节点,适用于表达式树、二叉堆
  • AVL树:自平衡二叉查找树,通过旋转保持平衡,适用于数据库索引
  • B+树:多路自平衡搜索树,适用于外存索引,数据库索引、文件系统
  • B-树:多路自平衡搜索树,适用于数据库索引
  • Trie树:前缀树,适用于文本搜索
  • 哈夫曼树:用于数据压缩,根据字符频率构建编码树

请针对对应词条前往浏览器搜索其特性
我这里只对红黑树进行细节描述:红黑树特征就是:

  1. 每个节点非红即黑
  2. 根节点总是黑色的
  3. 如果节点是红色的,则它的子节点必须是黑色的(反之不一定)
  4. 从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)

非常适合索引,内存中快速访问数据等

字符串操作(String)

用途:文本处理和操作
解决问题:各种字符串处理需求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 创建字符串
String str = "Hello, World!";

// 基本操作
int length = str.length();
char ch = str.charAt(0);
String sub = str.substring(0, 5); // "Hello"

// 查找
int index = str.indexOf("World"); // 7
int lastIndex = str.lastIndexOf("o"); // 8

// 替换
String newStr = str.replace("World", "Java");

// 分割
String[] parts = str.split(","); // ["Hello", " World!"]

// 连接
String joined = String.join("-", "A", "B", "C"); // "A-B-C"

// 格式化
String formatted = String.format("Name: %s, Age: %d", "Alice", 25);

// 大小写转换
String upper = str.toUpperCase();
String lower = str.toLowerCase();

// 去除空格
String trimmed = " hello ".trim();

// 构建字符串 (高效)
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(", ");
sb.append("World!");
String result = sb.toString();

工具类(Collections/Arrays)

用途:提供集合和数组的常用工具方法
解决问题:简化集合和数组操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Arrays工具类
int[] nums = {3, 1, 2};

Arrays.sort(nums); // 排序
int index = Arrays.binarySearch(nums, 2); // 二分查找
int[] copy = Arrays.copyOf(nums, nums.length);
boolean equal = Arrays.equals(nums, new int[]{1, 2, 3});
String str = Arrays.toString(nums); // "[1, 2, 3]"

// Collections工具类
//可以如此安排
ArrayList<Object> list = new ArrayList<>();
//标准化格式
List<Integer> list = new ArrayList<>(Arrays.asList(3, 1, 2));

Collections.sort(list); // 排序
Collections.reverse(list); // 反转
Collections.shuffle(list); // 随机打乱
int max = Collections.max(list);
int min = Collections.min(list);
Collections.fill(list, 0); // 填充
Collections.swap(list, 0, 1); // 交换
Collection.addAll(list,1,2,3,4,5);//添加多个元素
Collection.add(lise,1);//添加

// 不可变集合
List<Integer> unmodifiable = Collections.unmodifiableList(list);
Set<Integer> singleton = Collections.singleton(1); // 单元素集合

Iterator迭代器

用途:遍历集合元素
解决问题:统一访问集合元素的方式

1
2
3
4
5
6
// 迭代器遍历
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
}

Comparable和Comparator比较器

比较器是用来定义对象比较规则的,比较器有两种:

  • Comparable接口:定义在类本身,在类本身实现接口,类实现Comparable接口,重写compareTo方法,是内部比较器
  • Comparator接口:定义在外部,需要时传入比较器对象,重写compare方法

实现接口名称也不同

  • Comparable接口:compareTo(UserInfo o)
  • Comparator接口:compare(UserInfo o1,UserInfo o2)

所属的包也不同

  • Comparable接口:java.lang.Comparable
  • Comparator接口:java.util.Comparator

用途:定义对象比较规则
解决问题:排序、集合元素比较等

典型实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    // Comparable
public class Test2 {
public static class UserInfo implements Comparable<UserInfo>{

private int uid;
private int age;
private String name;


public UserInfo() {

}

public UserInfo(int uid, int age, String name) {

}

@Override
public String toString() {
return "UserInfo{" +
"uid=" + uid +
", age=" + age +
", name='" + name + '\'' +
'}';
}
//具体实现方法部分
@Override
public int compareTo(UserInfo o) {
return this.age-o.age;
}

public int getUid() {
return uid;
}

public void setUid(int uid) {
this.uid = uid;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
}

//Comparator
public class Test3 implements Comparator<Test2.UserInfo> {


@Override
public int compare(Test2.UserInfo o1, Test2.UserInfo o2) {
return o1.getName().compareTo(o2.getName());
}
}

//测试类调用
public class Test2_1 {
public static void main(String[] args) {
List<Test2.UserInfo> list = new ArrayList<>();

Collections.addAll(list,
new Test2.UserInfo(1,21,"jack"),
new Test2.UserInfo(2,34,"tom")
);
Collections.sort(list);
for (Test2.UserInfo user :list){
System.out.println(user);
}
}
}

后续持续更新………………