目录
一、计算机核心基础之大话数据结构
1.1 什么是数据结构?
数据结构是计算机科学中一个非常重要的一个概念,它指的是相互之间存在一种或多种特定关系的数据元素的集合,简单来说,数据结构就是组织、存储和操作数据的方式和方法。在计算机程序中合理的数据结构能够大大的提高程序的运行效率、减少存储空间的使用、并使程序更易于理解和维护。
1.2 数据结构的分类
1.2.1 线性数据结构
1.2.1.1 数组(Array)
数组:固定大小、连续存储的数据元素集合。
1.2.1.2 链表(LinkedList)
链表:由节点组成,每个节点包含数据元素和指向下一个节点的指针。
1.2.1.3 栈(Stack)
栈:先进后出(LIFO)的数据结构,只允许在一段进行插入和删除操作。
1.2.1.4 队列
队列:先进先出(FIFO)的数据结构,在一段插入元素,在另一端删除元素。
1.2.2 非线性结构
1.2.2.1 树(Tree)
树:由节点和边组成的层次结构,每个节点可以由零个或多个子节点。
二、Java核心进阶之Collection集合框架概要
2.1 什么是Java集合框架 ?
Java的集合框架(Collection Framework)是一个用于表示和操作对象的集合的统一架构。
它包含了许多接口、实现类以及算法,可以高效地存储和操作多个对象。
集合框架是Java API的一部分,它允许我们将对象组合成更大的结构,同时提供了对这些结构的高层次操作。
通俗来说:就是java已经封装好的数据结构类,我们开发可以直接用
2.2 集合框架的主要接口和类
2.2.1 Collection接口
Collection是所有集合类的根接口,定义了集合类应该具备的一些基本方法,如添加、删除、遍历等。
常见方法列表
boolean add(E e) 向集合中添加指定的元素。如果集合已经包含该元素,则此方法可能不执行任何操作(对于Set而言)。
boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素添加到此集合中(可选操作)。
void clear() 移除集合中的所有元素(可选操作)。
boolean contains(Object o) 如果此集合包含指定的元素,则返回true。
boolean containsAll(Collection<?> c)如果此集合包含指定集合中的所有元素,则返回true
boolean isEmpty() 如果此集合不包含任何元素,则返回true。
Iterator<E> iterator()返回在此集合中的元素上进行迭代的迭代器。
boolean remove(Object o)从此集合中移除指定的元素(如果存在)。
boolean removeAll(Collection<?> c)从此集合中移除指定集合中包含的所有元素(可选操作)。
boolean retainAll(Collection<?> c)仅保留此集合中也包含在指定集合中的元素(可选操作)。
int size()返回此集合中的元素数(其容量)。
2.2.2 List接口
List接口继承了Collection接⼝,代表⼀个有序集合,允许有重复的元素。
实现类有ArrayList、LinkedList、Vector等。
2.2.2.1 List接口的实现类
i. ArrayList
底层基于数组实现,查询效率⾼,增删效率低(因为需要移动元素)。
线程不安全,但性能较⾼。
适⽤于需要频繁查询的场景。
ii. LinkedList
底层基于双向链表实现,查询效率低(需要从头或尾遍历),增删效率⾼。
提供了额外的头尾操作⽅法,如 addFirst() , addLast() , getFirst() , getLast() , removeFirst() , removeLast() 等。
线程不安全。
适⽤于需要频繁增删的场景,尤其是⾸尾操作。
2.2.2.2 List接口的主要方法
void add(int index, E element) : 在指定位置插⼊元素。
E get(int index) : 返回指定位置的元素。 int indexOf(Object o) : 返回此列表中指定元素的⾸次出现的索引,如果此列表不包含该元素,则 返回-1。
int lastIndexOf(Object o) : 返回此列表中指定元素的最后⼀次出现的索引,如果此列表不包含该 元素,则返回-1。
E remove(int index) : 移除指定位置的元素。
boolean contains(Object o) : 如果此列表包含指定的元素,则返回 true 。
Iterator<E> iterator() : 返回在此列表中的元素上进⾏迭代的迭代器。
案例代码:
import java.util.ArrayList;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 添加元素
list.add("Apple");
list.add("Banana");
list.add("Cherry");
// 访问元素
System.out.println(list.get(1)); // 输出: Banana
// 插⼊元素
list.add(1, "Orange");
// 遍历元素
for (String fruit : list) {
System.out.println(fruit);
}
// 移除元素
list.remove(2); // 移除索引为2的元素,即"Cherry"
// 再次遍历元素
for (String fruit : list) {
System.out.println(fruit);
}
}
}
使用注意事项:
使⽤ List 集合时,要注意索引越界的问题,即不要访问或操作不存在的索引位置。
在多线程环境下,如果需要对 List 进⾏并发操作,需要考虑线程安全的问题,可以选择使⽤线程安全 的实现类。
根据实际需求选择合适的 List 实现类,获得更好的性能。
2.2.3 Set接口
继承了Collection接⼝,代表⼀个⽆序集合,不允许有重复的元素。
实现类有HashSet、TreeSet等。
2.2.3.1 Set集合的实现类
i. HashSet
基于哈希表实现,不保证元素的迭代顺序,也不保证元素的顺序在⻓时间内保持不变。
性能通常优于其他 Set 实现类,因为它提供了常数时间的添加、删除和查找操作.
ii. LinkedHashSet
类似于 HashSet ,但迭代顺序是元素插⼊到集合中的顺序(插⼊顺序)。
在需要保持元素插⼊顺序的场景中很有⽤.
iii. TreeSet
基于红⿊树实现,能够对元素进⾏⾃然排序或根据创建 TreeSet 时提供的 Comparator 进⾏排 序。
适⽤于需要有序集合的场景。
2.2.3.2 Set接口的主要方法
boolean add(E e) : 如果此集合尚未包含指定元素,则添加指定元素。
boolean addAll(Collection c) : 如果指定集合中的所有元素都尚未添加到此集合 中
boolean contains(Object o) : 如果此集合包含指定的元素,则返回 true 。
boolean containsAll(Collection c) : 如果此集合包含指定集合中的所有元素,则返回 true 。
boolean removeAll(Collection c) : 移除此集合中那些也包含在指定集合中的所有元素(可选 操作)。
boolean retainAll(Collection c) : 仅保留此集合中也包含在指定集合中的元素(可选操 作)。
案例代码:
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
//Set<Integer> set = new TreeSet<>()
// 添加元素
set.add("Apple");
set.add("Banana");
set.add("Cherry");
set.add("Apple"); // 重复添加,不会被加⼊集合
// 遍历集合
for (String fruit : set) {
System.out.println(fruit);
}
// 检查是否包含某个元素
if (set.contains("Banana")) {
System.out.println("Set contains Banana.");
}
// 移除元素
set.remove("Cherry");
// 再次遍历集合
for (String fruit : set) {
System.out.println(fruit);
}
}
}
注意事项:
在使⽤ Set 集合时,要注意集合中元素的唯⼀性,不要添加重复的元素。
如果需要在集合中保持元素的插⼊顺序或进⾏排序,请选择适当的 Set 实现类(如 LinkedHashSet 或 TreeSet )。
在多线程环境下使⽤ Set 集合时,需要考虑线程安全的问题。
如果需要线程安全的 Set 集合,可以使⽤ Collections.synchronizedSet() ⽅法
2.2.4 Queue接口
代表⼀个队列,⽤于保存等待处理的元素,队列是⼀种特殊的线性表。
它只允许在表的前端(front)进⾏删除操作,⽽在表的后端(rear)进⾏插⼊操作。
实现类有LinkedList(它同时实现了List和Queue接⼝)、PriorityQueue等。
2.2.5 Map接口
Map接口(没有继承Collection接口,本身就是顶级接口)代表⼀个映射关系,将键(Key)映射到值(Value),键不允许重复,但值可以重复。
实现类有HashMap、TreeMap、Hashtable等。
2.2.5.1 Map接口的实现类
i. HashMap
基于哈希表实现,允许null键和null值。
不保证映射的顺序,特别是它不保证该顺序恒久不变。
性能通常优于 Hashtable 和 TreeMap.
ii. LinkedHashMap
类似于 HashMap ,但遍历顺序是按照键值对插⼊到映射中的顺序(插⼊顺序)或最近最少使⽤ (LRU)顺序。
提供了按访问顺序(访问顺序)或插⼊顺序(插⼊顺序)遍历映射的⽅法。
iii.TreeMap
基于红⿊树实现,能够按照键的⾃然顺序或⾃定义顺序进⾏排序。
所有的元素都根据键的⾃然顺序(或创建 TreeMap 时提供的 Comparator 进⾏排序)。
适⽤于需要有序遍历的场景。
2.2.5.2 Map接口的主要方法
V put(K key, V value) : 将指定的值与此映射中的指定键关联(可选操作)。如果包含⼀个该键的 映射关系,则旧值被替换。
V get(Object key) : 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null 。
V remove(Object key) : 如果存在⼀个键的映射关系,则从此映射中移除它(可选操作)。
boolean containsKey(Object key) : 如果此映射包含指定键的映射关系,则返回 true 。
boolean containsValue(Object value) : 如果此映射将⼀个或多个键映射到指定值,则返回 true
int size() : 返回此映射中的键-值映射关系的数量。
boolean isEmpty() : 如果此映射不包含键-值映射关系,则返回 true 。
Set<K> keySet() : 返回此映射中包含的键的 Set 视图。
Collection<V> values() : 返回此映射中包含的值的 Collection 视图。
Set<Map.Entry<K,V>> entrySet() : 返回此映射中包含的映射关系的 Set 视图
案例代码:
import java.util.HashMap;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("Apple", 5);
map.put("Banana", 3);
map.put("Cherry", 7);
// 访问键值对
System.out.println(map.get("Banana")); // 输出: 3
// 遍历键
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("Key: " + entry.getKey() + ", Value: " +
entry.getValue());
}
// 移除键值对
map.remove("Cherry");
// 再次遍历键值对
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " +
entry.getValue());
}
}
}
注意事项:
在使⽤ Map 时,要注意键的唯⼀性,不要试图插⼊重复的键。
如果需要在多线程环境下使⽤ Map ,需要考虑线程安全的问题。
2.2.6 迭代器
集合框架中的⼀个重要概念,它提供了⼀种遍历集合元素的⽅式,⽽不需要了解集合底层的实现细节。
使⽤迭代器可以安全地遍历集合,并且可以在遍历过程中安全地修改集合(除了并发修改外)。
2.2.6.1 迭代器 Iterator 概述
Iterator是java中的⼀个接⼝,核⼼作⽤就是⽤来遍历容器的元素
当容器实现了Iterator接⼝后,可以通过调⽤Iterator()⽅法获取⼀个 Iterator对象
迭代器本身并不属于集合结构的⼀部分,⽽是⽤于遍历集合的⼯具
为什么要调用容器里面的Iterator方法呢?
因为容器的实现有多种,不同的容器遍历规则不⼀样,⽐如 ArrayList/LinkedList/HashSet/TreeSet等。
能够顺序地访问⼀个集合(Collection)的元素,⽽⼜不需要知道该集合的底层表示。
所以设计了Iterator接⼝,让容器本身去实现这个接⼝,实现⾥⾯的⽅法, 从⽽让开发⼈员不⽤关系容器的遍历机制,直接使⽤对应的⽅法即可
三个核心方法
boolean hashNext() :⽤于判断iterator内是否有下个元素,如果有则返回true,没有则false。
Obejct next():返回iterator的下⼀个元素,同时指针也会向后移动1位。
void remove():删除指针的上⼀个元素(容易出问题,删除元素不建议使⽤容器⾃⼰的⽅法)。
2.2.6.2 使用迭代器的步骤
i. 获取迭代器对象
通过调⽤集合的 iterator() ⽅法,我们可以获取到该集合的迭代器对象。
ElementType 是集合中元素的类型, collection 是需要遍历的集合对象。
Iterator<ElementType> iterator = collection.iterator();
ii. 判断迭代器中是否还有元素
使⽤ iterator.hasNext() ⽅法来判断迭代器中是否还有下⼀个元素
while (iterator.hasNext()) {
// 迭代器中还有元素
}
iii. 访问集合中的元素
使⽤ iterator.next() ⽅法来获取迭代器中的下⼀个元素。
在调⽤ next() ⽅法之前,必须确保迭代器中还有元素,否则会抛出 NoSuchElementException 异常。
ElementType element = iterator.next();
iv. 安全的遍历集合
在遍历集合的过程中,如果需要删除某个元素,应该使⽤迭代器的 remove() ⽅法,⽽不是集合的 remove() ⽅法。
直接使⽤集合的 remove() ⽅法会导致在并发修改集合的情况下抛出 ConcurrentModificationException 异常。
if (someCondition) {
iterator.remove(); // 删除当前元素
}
案例代码:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class IteratorExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Cherry");
// 获取迭代器
Iterator<String> iterator = list.iterator();
// 遍历集合
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println(fruit);
// 假设我们想要删除 "Banana"
if ("Banana".equals(fruit)) {
iterator.remove();
//list.remove(fruit) //ConcurrentModificationException并发修改异常
}
}
// 输出修改后的集合
System.out.println("After removal:");
for (String f : list) {
System.out.println(f);
}
}
}
注意事项:
迭代器遍历集合时,只能单向遍历,⽆法从后往前遍历。
如果在遍历过程中需要修改集合(如删除元素),应该使⽤迭代器的 remove() ⽅法,⽽不是集合的 remove() ⽅法。
不同循环找元素⽅式选择,最终看使⽤场景,性能会有轻微差别,但是可以忽略。
2.2.7 哈希表
什么是散列表(Hash table,也叫哈希表)
是根据关键码值(Key value)⽽直接进⾏访问的数据结构。
它通过把关键码值映射到表中⼀个位置来访问记录,以加快查找的速度 。
这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代⼊函数后若能得到包含该关键字的记录 在表中的地址。
则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数 散列函数 。
能使对⼀个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位
2.2.8 总结
Java的集合框架为我们提供了⼀种统⼀的⽅式来操作对象集合,它包括了多种类型的集合(如List、 Set、Queue、Map等)
以及许多⽤于操作这些集合的算法和⼯具类,掌握集合框架是Java编程中⾮常重要的⼀部分。