数据结构(data structure):数据在计算机中的存储与组织形式;其主要目的是为了对数据进行高效地访问和修改;数据结构包含数组、链表这样的线性数据结构,也包含树、图这样的复杂数据结构。
算法(algorithm):在特定的计算模型下,旨在解决特定问题的一系列指令。
程序 = 数据结构 + 算法
一、列表(Lists)
List接口的常见实现类有ArrayList和LinkedList。
List<Integer> arrayList = new ArrayList<>();
List<Integer> linkedList = new LinkedList<>();
ArrayList:
- 特点: 动态数组,可变大小。
- 优点: 高效的随机访问和快速尾部插入。
- 缺点: 中间插入和删除相对较慢。
LinkedList:
- 特点: 双向链表,元素之间通过指针连接。
- 优点: 插入和删除元素高效,迭代器性能好。
- 缺点: 随机访问相对较慢。
在编程时,通常建议使用接口类型来声明变量,而不是具体的实现类。这样做有几个好处:
- 更好的封装:使用接口类型声明变量,可以将变量类型与实现类分离,从而提高代码的灵活性和可维护性。
- 降低耦合度:接口类型的变量只关心方法的签名,而不关心具体的实现细节,因此可以轻松地切换不同的实现类而不影响其他部分的代码。
- 符合面向接口编程的原则:面向接口编程是一种良好的编程实践,它能够提高代码的可复用性和可测试性。
List常用方法
方法 | 描述 |
---|---|
add(E e) | 在列表末尾添加指定的元素 |
get(int index) | 返回列表中指定位置的元素 |
set(int index, E element) | 将列表中指定位置的元素替换为指定的元素 |
remove(int index) | 移除列表中指定位置的元素,并返回被移除的元素 |
size() | 返回列表中的元素数 |
isEmpty() | 判断列表是否为空 |
contains(Object o) | 判断列表是否包含指定的元素 |
indexOf(Object o) | 返回列表中指定元素第一次出现的索引 |
lastIndexOf(Object o) | 返回列表中指定元素最后一次出现的索引 |
subList(int fromIndex, int toIndex) | 返回列表中指定范围的部分视图 |
二、集合(Sets)
集合(Sets)用于存储不重复的元素,常见的实现有 HashSet 和 TreeSet。
Set<String> hashSet = new HashSet<>();
Set<Integer> treeSet = new TreeSet<>();
Set判断两个对象是否相等用equals,而不是使用==。
HashSet:
- 特点: 无序集合,基于HashMap实现。
- 优点: 高效的查找和插入操作。
- 缺点: 不保证顺序。
TreeSet:
- 特点:TreeSet 是有序集合,底层基于红黑树实现,不允许重复元素。
- 优点: 提供自动排序功能,适用于需要按顺序存储元素的场景。
- 缺点: 性能相对较差,不允许插入 null 元素。
HashSet集合元素值允许是null,但是最多只能有一个。
TreeSet类使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序。
三、映射(Maps)
映射(Maps)
映射(Maps)用于存储键值对,常见的实现有 HashMap 和 TreeMap。
Map<String, Integer> hashMap = new HashMap<>();
Map<String, Integer> treeMap = new TreeMap<>();
HashMap:
- 特点: 基于哈希表实现的键值对存储结构。
- 优点: 高效的查找、插入和删除操作。
- 缺点: 无序,不保证顺序。
TreeMap:
- 特点: 基于红黑树实现的有序键值对存储结构。
- 优点: 有序,支持按照键的顺序遍历。
- 缺点: 插入和删除相对较慢。
HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。其允许存放null的key和null的value。
键值对映射是一对一或一对多,当我们 put 的时候,如果 key 存在了,那么新的 value 会代替旧的 value,并且如果 key 存在的情况下,该方法返回的是旧的 value,如果 key 不存在,那么返回 null。
四、数组(Arrays)
数组(Arrays)是一种基本的数据结构,可以存储固定大小的相同类型的元素。
数组定义有三种方法:
//1.动态初始化:在创建数组时,只定义数组中元素的个数,并未给里面的元素进行赋值
int[] array1 = new int[10];//前面的int[]为数组的类型,后面的int[10]为其能够存放的大小,array1为其数组名称。
//2.静态初始化:在创建数组时不定义数据元素个数,而直接将数组里的数据内容进行赋值,编译器会自己判定数组有几个元素, 后面的数据必须与前面定义的数据类型一致
int[] array2 = {1,2,3,4,5};
//初始化能分为两步,分步的第二步中new int[]不能省略
int[] array3;
array3 = new int[]{1,2,3,4,5};
- 特点: 固定大小,存储相同类型的元素。
- 优点: 随机访问元素效率高。
- 缺点: 大小固定,插入和删除元素相对较慢。
根据可以下标遍历元素,注意下标是从0开始。
五、栈(Stack)
栈(Stack)是一种线性数据结构,它按照后进先出(Last In, First Out,LIFO)的原则管理元素。在栈中,新元素被添加到栈的顶部,而只能从栈的顶部移除元素。这就意味着最后添加的元素是第一个被移除的。
Stack<Integer> stack = new Stack<>();
Stack 类:
- 特点: 代表一个栈,通常按照后进先出(LIFO)的顺序操作元素。
方法:
方法 | 描述 |
---|---|
E push(E e) | 将e入栈,并返回e |
E pop() | 将栈顶元素出栈并返回 |
E peek() | 获取栈顶元素 |
int size() | 获取栈中有效元素个数 |
boolean empty() | 检测栈是否为空 |
六、队列(Queue)
队列(Queue)遵循先进先出(FIFO)原则,常见的实现有 LinkedList 和 PriorityQueue。
Queue<String> queue = new LinkedList<>();
Queue 接口:
- 特点: 代表一个队列,通常按照先进先出(FIFO)的顺序操作元素。
- 实现类: LinkedList, PriorityQueue, ArrayDeque。
方法:
方法 | 描述 |
---|---|
boolean offer(E e) | 入队列 |
E poll() | 出队列 |
peek() | 获取队头元素 |
int size() | 获取队列中有效元素个数 |
boolean isEmpty() | 检测队列是否为空 |
七、堆(Heap)
堆(Heap)优先队列的基础,可以实现最大堆和最小堆。
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
- 堆逻辑上是一棵完全二叉树
- 堆物理上是保存在数组中
- 满足任意结点的值都大于其子树中结点的值,叫做大堆,或者大根堆,或者最大堆
反之,则是小堆,或者小根堆,或者最小堆 - 堆的基本作用是快速找集合中的最值
八、树(Trees)
Java 提供了 TreeNode 类型,可以用于构建二叉树等数据结构。
树是由节点和边构成的一种层次结构。它包含一个根节点,根节点下可以有多个子节点,每个子节点又可以有自己的子节点,以此类推。树的基本概念包括以下几个要点:
- 根节点:树的起始节点,没有父节点。
- 子节点:根节点下的节点称为子节点。
- 父节点:一个节点下面的直接连接节点称为父节点。
- 叶子节点:没有子节点的节点称为叶子节点。
- 子树:一个节点及其所有子节点、子节点的子节点等构成的树称为子树。
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
八、图(Graphs)
图的表示通常需要自定义数据结构或使用图库,Java 没有内建的图类。