马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
数据结构详解
目次
- 数据结构概述
- 1.1 什么是数据结构
- 1.2 数据结构的重要性
- 1.3 数据结构分类
- 基本数据结构
- 2.1 数组(Array)
- 2.1.1 数组的基本概念
- 2.1.2 数组的特点
- 2.1.3 数组的基本操作
- 2.1.4 数组的常见问题
- 2.1.5 多维数组
- 2.1.6 数组的优缺点
- 2.1.7 数组的应用场景
- 2.2 链表(Linked List)
- 2.2.1 链表的基本概念
- 2.2.2 链表的特点
- 2.2.3 链表的范例
- 2.2.4 链表的基本操作
- 2.2.5 链表的常见问题
- 2.2.6 链表的优缺点
- 2.2.7 链表的应用场景
- 2.3 栈(Stack)
- 2.3.1 栈的特点
- 2.3.2 栈的基本操作
- 2.3.3 栈的实现方式
- 2.3.4 栈的应用场景
- 2.3.5 高级应用
- 2.3.6 性能分析
- 2.3.7 注意事项
- 2.4 队列(Queue)
- 2.4.1 队列的特点
- 2.4.2 队列的基本操作
- 2.4.3 队列的范例
- 2.4.4 队列的应用场景
- 2.4.5 队列的性能分析
- 2.4.6 注意事项
- 高级数据结构
- 3.1 树(Tree)
- 3.1.0 通俗明确树
- 3.1.1 基本概念
- 3.1.2 树的范例
- 3.1.3 树的遍历方式
- 3.1.4 树的基本操作
- 3.1.5 树的常见问题
- 3.1.6 树的应用场景
- 3.2 图(Graph)
- 3.2.1 基本概念
- 3.2.2 邻接矩阵实现
- 3.2.3 邻接表实现
- 3.2.4 应用场景
- 3.3 堆(Heap)
- 3.3.1 基本概念
- 3.3.2 最大堆实现
- 3.3.3 应用场景
- 3.4 散列表(Hash Table)
- 3.4.1 基本概念
- 3.4.2 冲突处理策略
- 3.4.3 实现示例
- 3.4.4 开放寻址法实现示例
- 3.4.5 散列表的应用场景
- 3.4.6 散列表的优缺点
- 3.4.7 散列表与其他数据结构的比较
- 3.4.8 散列表的变种
- 算法复杂度分析
- 4.1 时间复杂度
- 4.1.1 通俗明确
- 4.1.2 常见复杂度
- 4.1.3 分析方法
- 4.2 空间复杂度
- 4.2.1 通俗明确
- 4.2.2 影响因素
- 4.2.3 常见空间复杂度
- 4.2.4 常见算法的空间复杂度
- 4.2.5 实际应用中的思量因素
- 4.3 实际应用中的思量因素
- 数据结构应用
- 5.1 数据库体系
- 5.1.1 索引结构
- B+树索引
- 哈希索引
- 位图索引
- 全文索引
- LSM树(Log-Structured Merge Tree)
- R树
- 5.1.2 查询优化
- 索引选择
- 毗连优化
- 排序优化
- 缓存策略
- 并行查询
- 物化视图
- 5.1.3 事务处理
- 5.2 操作体系
- 5.2.1 内存管理
- 页表
- 段表
- 空闲内存管理
- 假造内存
- 内存映射
- 内存保护
- 5.2.2 进程管理
- 进程调度
- 进程同步
- 进程通信
- 线程管理
- 进程状态
- 及时调度
- 5.2.3 文件体系
- 文件构造
- 目次结构
- 文件保护
- 日记文件体系
- 分布式文件体系
- 文件体系性能
- 5.2.4 网络体系
- 5.2.5 编译体系
- 5.2.6 人工智能和机器学习
- 5.2.7 游戏开发
- 5.3 网络编程
- 数据结构与算法计划
- 6.1 计划原则
- 6.1.1 精确性
- 6.1.2 可维护性
- 6.1.3 可扩展性
- 6.1.4 服从
- 6.1.5 资源使用
- 6.1.6 可测试性
- 6.1.7 安全性
- 6.1.8 可读性
- 6.2 计划模式
- 6.2.1 迭代器模式
- 6.2.2 组合模式
- 6.2.3 策略模式
- 6.2.4 适配器模式
- 6.2.5 工厂模式
- 6.2.6 观察者模式
- 6.2.7 下令模式
- 6.2.8 状态模式
- 6.2.9 署理模式
- 6.2.10 模板方法模式
- 6.3 优化本领
- 6.3.1 空间换时间
- 6.3.2 预处理
- 6.3.3 缓存
- 6.3.4 并行化
- 6.3.5 数据结构选择
- 6.3.6 算法改进
- 6.3.7 位运算优化
- 6.3.8 内存管理优化
- 6.3.9 I/O优化
- 6.3.10 代码级优化
- 6.4 算法策略
- 6.4.1 分治策略
- 6.4.2 动态规划
- 6.4.3 贪心策略
- 6.4.4 回溯法
- 6.4.5 分支限界法
- 6.4.6 随机化算法
- 6.4.7 近似算法
- 6.4.8 在线算法
- 6.4.9 并行算法
- 6.4.10 量子算法
- 6.5 代码实现
- 6.5.1 代码风格
- 6.5.2 错误处理
- 6.5.3 代码复用
- 6.5.4 性能优化
- 6.5.5 测试驱动开发
- 6.5.6 代码文档
- 6.5.7 版本控制
- 6.5.8 持续集成
- 6.5.9 代码审查
- 6.5.10 重构
- 6.6 测试与验证
- 数据结构实战案例
- 7.1 电商体系
- 7.2 交际网络
- 7.3 搜索引擎
- 数据结构与性能优化
- 数据结构与并发编程
- 9.1 并发数据结构
- 9.1.1 线程安全集合
- 9.1.2 无锁数据结构
- 9.2 并发控制
- 数据结构与内存管理
- 数据结构与数据库
- 数据结构与网络编程
- 12.1 网络协议
- 12.2 网络应用
- 12.2.1 服务器实现
- 12.2.2 客户端实现
- 数据结构与分布式体系
- 数据结构与大数据处理
- 数据结构与人工智能
1. 数据结构概述
1.1 什么是数据结构
数据结构是计算机存储、构造数据的方式,它形貌了数据元素之间的逻辑关系。好的数据结构计划可以提高步伐的运行服从,降低资源斲丧。
1.2 数据结构的重要性
- 提高步伐服从
- 优化内存使用
- 简化步伐计划
- 提升代码可维护性
1.3 数据结构分类
2. 基本数据结构
2.1 数组(Array)
2.1.1 数组的基本概念
数组是最底子的数据结构,它是一块连续的内存空间,用来存储相同范例的数据。
想象一下:
- 就像一排座位,每个座位都有编号(索引)
- 所有座位巨细相同(相同数据范例)
- 座位是连续的,没有隔断(连续内存)
2.1.2 数组的特点
- 固定巨细
- 创建时必须指定巨细
- 巨细不能动态改变
- 比方:int[] arr = new int[5]; // 创建巨细为5的整型数组
- 随机访问
- 可以直接通过索引访问元素
- 访问时间复杂度:O(1)
- 比方:arr[0] 直接访问第一个元素
- 连续内存
- 所有元素在内存中连续存储
- 有利于CPU缓存
- 可能导致内存碎片
- 范例一致
- 所有元素必须是相同范例
- 比方:int[] 只能存储整数
- 对象数组可以存储相同范例的对象
2.1.3 数组的基本操作
- // 方式1:指定大小
- int[] arr1 = new int[5];
- // 方式2:直接初始化
- int[] arr2 = {1, 2, 3, 4, 5};
- // 方式3:先声明后初始化
- int[] arr3;
- arr3 = new int[]{1, 2, 3};
复制代码- // 读取元素
- int first = arr[0]; // 获取第一个元素
- int last = arr[arr.length - 1]; // 获取最后一个元素
- // 修改元素
- arr[0] = 10; // 修改第一个元素
复制代码- // 方式1:for循环
- for (int i = 0; i < arr.length; i++) {
- System.out.println(arr[i]);
- }
- // 方式2:增强for循环
- for (int num : arr) {
- System.out.println(num);
- }
- // 方式3:Arrays工具类
- Arrays.stream(arr).forEach(System.out::println);
复制代码- // 线性查找
- public static int linearSearch(int[] arr, int target) {
- for (int i = 0; i < arr.length; i++) {
- if (arr[i] == target) {
- return i;
- }
- }
- return -1; // 未找到
- }
- // 二分查找(要求数组有序)
- public static int binarySearch(int[] arr, int target) {
- int left = 0;
- int right = arr.length - 1;
-
- while (left <= right) {
- int mid = left + (right - left) / 2;
- if (arr[mid] == target) {
- return mid;
- } else if (arr[mid] < target) {
- left = mid + 1;
- } else {
- right = mid - 1;
- }
- }
- return -1; // 未找到
- }
复制代码 2.1.4 数组的常见问题
- int[] arr = new int[5];
- arr[5] = 10; // ArrayIndexOutOfBoundsException
复制代码- int[] arr = null;
- arr[0] = 10; // NullPointerException
复制代码- // 方式1:System.arraycopy
- int[] source = {1, 2, 3, 4, 5};
- int[] dest = new int[5];
- System.arraycopy(source, 0, dest, 0, source.length);
- // 方式2:Arrays.copyOf
- int[] copy = Arrays.copyOf(source, source.length);
- // 方式3:clone方法
- int[] clone = source.clone();
复制代码 2.1.5 多维数组
- // 创建二维数组
- int[][] matrix = new int[3][4]; // 3行4列
- // 初始化二维数组
- int[][] grid = {
- {1, 2, 3},
- {4, 5, 6},
- {7, 8, 9}
- };
- // 访问元素
- int value = grid[1][2]; // 访问第2行第3列的元素
复制代码- // 创建不规则数组
- int[][] irregular = new int[3][];
- irregular[0] = new int[3]; // 第一行3个元素
- irregular[1] = new int[4]; // 第二行4个元素
- irregular[2] = new int[2]; // 第三行2个元素
复制代码 2.1.6 数组的优缺点
优点:
- 随机访问速率快(O(1))
- 内存连续,有利于CPU缓存
- 实现简单,使用方便
- 适合存储固定巨细的数据
缺点:
- 巨细固定,不能动态扩展
- 插入和删除操作慢(O(n))
- 可能造成内存浪费
- 必要连续的内存空间
2.1.7 数组的应用场景
2.2 链表(Linked List)
2.2.1 链表的基本概念
链表是一种线性数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。
想象一下:
- 就像一列火车,每节车厢(节点)都毗连着下一节
- 每节车厢可以装载差别的货品(数据)
- 车厢之间通过毗连器(指针)相连
- 可以随时添加或移除车厢(动态巨细)
2.2.2 链表的特点
- 动态巨细
- 可以根据必要增加或减少节点
- 不必要预先分配固定巨细的内存
- 比方:可以不停添加新朋友到挚友列表中
- 内存不连续
- 节点可以分散在内存的差别位置
- 通过指针毗连各个节点
- 不会造成内存碎片
- 插入和删除服从高
- 只需修改指针,不必要移动数据
- 插入和删除的时间复杂度:O(1)(在已知位置)
- 比方:在挚友列表中删除一个朋友只需改变毗连关系
- 随机访问服从低
- 必须重新开始遍历才华找到特定位置的元素
- 访问的时间复杂度:O(n)
- 比方:要找到第10个朋友,必须从第1个开始数到第10个
2.2.3 链表的范例
- 单链表(Singly Linked List)
- 每个节点只有一个指针,指向下一个节点
- 最后一个节点指向null
- 只能向前遍历
- 比方:单向播放的音乐列表
- 双链表(Doubly Linked List)
- 每个节点有两个指针,分别指向前一个和后一个节点
- 可以向前和向后遍历
- 比方:可从前进和退却的浏览器汗青记录
- 循环链表(Circular Linked List)
- 最后一个节点指向第一个节点,形成环
- 可以是单向循环或双向循环
- 比方:循环播放的音乐列表
- 双向循环链表(Doubly Circular Linked List)
- 结合了双链表和循环链表的特点
- 每个节点有两个指针,并且首尾相连
- 比方:可以双向循环浏览的图片轮播
2.2.4 链表的基本操作
- // 单链表节点
- class Node<T> {
- T data; // 数据
- Node<T> next; // 指向下一个节点的指针
-
- Node(T data) {
- this.data = data;
- this.next = null;
- }
- }
- // 双链表节点
- class DoublyNode<T> {
- T data; // 数据
- DoublyNode<T> prev; // 指向前一个节点的指针
- DoublyNode<T> next; // 指向下一个节点的指针
-
- DoublyNode(T data) {
- this.data = data;
- this.prev = null;
- this.next = null;
- }
- }
复制代码- // 在单链表头部插入节点
- public void insertAtHead(T data) {
- Node<T> newNode = new Node<>(data);
- newNode.next = head;
- head = newNode;
- size++;
- }
- // 在单链表尾部插入节点
- public void insertAtTail(T data) {
- Node<T> newNode = new Node<>(data);
- if (head == null) {
- head = newNode;
- } else {
- Node<T> current = head;
- while (current.next != null) {
- current = current.next;
- }
- current.next = newNode;
- }
- size++;
- }
- // 在单链表指定位置插入节点
- public void insertAtPosition(T data, int position) {
- if (position < 0 || position > size) {
- throw new IllegalArgumentException("Position is invalid");
- }
-
- if (position == 0) {
- insertAtHead(data);
- return;
- }
-
- Node<T> newNode = new Node<>(data);
- Node<T> current = head;
- for (int i = 0; i < position - 1; i++) {
- current = current.next;
- }
- newNode.next = current.next;
- current.next = newNode;
- size++;
- }
复制代码- // 删除单链表头部节点
- public T deleteFromHead() {
- if (head == null) {
- throw new NoSuchElementException("List is empty");
- }
- T data = head.data;
- head = head.next;
- size--;
- return data;
- }
- // 删除单链表尾部节点
- public T deleteFromTail() {
- if (head == null) {
- throw new NoSuchElementException("List is empty");
- }
-
- if (head.next == null) {
- T data = head.data;
- head = null;
- size--;
- return data;
- }
-
- Node<T> current = head;
- while (current.next.next != null) {
- current = current.next;
- }
- T data = current.next.data;
- current.next = null;
- size--;
- return data;
- }
- // 删除单链表指定位置的节点
- public T deleteFromPosition(int position) {
- if (position < 0 || position >= size) {
- throw new IllegalArgumentException("Position is invalid");
- }
-
- if (position == 0) {
- return deleteFromHead();
- }
-
- Node<T> current = head;
- for (int i = 0; i < position - 1; i++) {
- current = current.next;
- }
- T data = current.next.data;
- current.next = current.next.next;
- size--;
- return data;
- }
复制代码- // 在单链表中查找元素
- public int find(T data) {
- Node<T> current = head;
- int position = 0;
-
- while (current != null) {
- if (current.data.equals(data)) {
- return position;
- }
- current = current.next;
- position++;
- }
-
- return -1; // 未找到
- }
- // 获取单链表指定位置的元素
- public T get(int position) {
- if (position < 0 || position >= size) {
- throw new IllegalArgumentException("Position is invalid");
- }
-
- Node<T> current = head;
- for (int i = 0; i < position; i++) {
- current = current.next;
- }
-
- return current.data;
- }
复制代码- // 遍历单链表
- public void traverse() {
- Node<T> current = head;
- while (current != null) {
- System.out.print(current.data + " -> ");
- current = current.next;
- }
- System.out.println("null");
- }
- // 递归遍历单链表
- public void traverseRecursive(Node<T> node) {
- if (node == null) {
- System.out.println("null");
- return;
- }
- System.out.print(node.data + " -> ");
- traverseRecursive(node.next);
- }
复制代码 2.2.5 链表的常见问题
- 检测环
概念:检测环是指在一个数据结构(通常是链表)中,判定是否存在循环引用或循环路径的过程。
- // 使用快慢指针检测单链表中的环
- public boolean hasCycle() {
- if (head == null || head.next == null) {
- return false;
- }
-
- Node<T> slow = head;
- Node<T> fast = head;
-
- while (fast != null && fast.next != null) {
- slow = slow.next;
- fast = fast.next.next;
-
- if (slow == fast) {
- return true; // 发现环
- }
- }
-
- return false; // 无环
- }
复制代码
- 反转链表
概念:反转链表是将链表中的节点顺序完全颠倒过来,使原来的头节点变成尾节点,原来的尾节点变成头节点,中间所有节点的指向也都反向。
- // 反转单链表
- public void reverse() {
- Node<T> prev = null;
- Node<T> current = head;
- Node<T> next = null;
-
- while (current != null) {
- next = current.next; // 保存下一个节点
- current.next = prev; // 反转指针
- prev = current; // 移动prev指针
- current = next; // 移动current指针
- }
-
- head = prev; // 更新头节点
- }
- // 递归反转单链表
- public Node<T> reverseRecursive(Node<T> current) {
- if (current == null || current.next == null) {
- return current;
- }
-
- Node<T> rest = reverseRecursive(current.next);
- current.next.next = current;
- current.next = null;
-
- return rest;
- }
复制代码
- 归并有序链表
概念:归并有序链表是指将两个已经排序的链表归并成一个新的有序链表,保持所有节点的顺序。
- // 合并两个有序单链表
- public static <T extends Comparable<T>> Node<T> mergeSortedLists(Node<T> list1, Node<T> list2) {
- Node<T> dummy = new Node<>(null);
- Node<T> current = dummy;
-
- while (list1 != null && list2 != null) {
- if (list1.data.compareTo(list2.data) <= 0) {
- current.next = list1;
- list1 = list1.next;
- } else {
- current.next = list2;
- list2 = list2.next;
- }
- current = current.next;
- }
-
- if (list1 != null) {
- current.next = list1;
- }
-
- if (list2 != null) {
- current.next = list2;
- }
-
- return dummy.next;
- }
复制代码- // 使用快慢指针找到单链表的中间节点
- public Node<T> findMiddle() {
- if (head == null) {
- return null;
- }
-
- Node<T> slow = head;
- Node<T> fast = head;
-
- while (fast != null && fast.next != null) {
- slow = slow.next;
- fast = fast.next.next;
- }
-
- return slow;
- }
复制代码 2.2.6 链表的优缺点
优点:
- 动态巨细,可以根据必要扩展或收缩
- 插入和删除操作服从高(在已知位置)
- 不会造成内存碎片
- 不必要连续的内存空间
缺点:
- 随机访问服从低,必须重新遍历
- 额外的内存开销(存储指针)
- 缓存使用率低(内存不连续)
- 反向遍历困难(单链表)
2.2.7 链表的应用场景
- 内存管理
- 文件体系
- 浏览器功能
- 编辑器功能
- 音乐播放器
- 游戏开发
- 网络协议
- 数据库体系
2.3 栈(Stack)
栈是一种特殊的线性数据结构,它遵循"后进先出"(LIFO, Last In First Out)的原则。可以将其想象为一个垂直堆叠的盘子,你只能从顶部添加或移除盘子。
2.3.1 栈的特点
- 后进先出(LIFO):最后放入的元素开始被取出
- 受限的访问:只能从栈顶举行插入和删除操作
- 动态巨细:可以根据必要动态增长或缩小
- 简单高效:操作简单,时间复杂度为O(1)
2.3.2 栈的基本操作
- 入栈(Push):将元素添加到栈顶
- 出栈(Pop):移除并返回栈顶元素
- 查看栈顶元素(Peek/Top):返回栈顶元素但不移除
- 判定栈是否为空(IsEmpty):查抄栈中是否有元素
- 获取栈的巨细(Size):返回栈中元素的数量
2.3.3 栈的实现方式
- public class ArrayStack<T> {
- private T[] elements;
- private int size;
-
- @SuppressWarnings("unchecked")
- public ArrayStack(int capacity) {
- elements = (T[]) new Object[capacity];
- size = 0;
- }
-
- public void push(T element) {
- if (size == elements.length) {
- resize();
- }
- elements[size++] = element;
- }
-
- public T pop() {
- if (isEmpty()) {
- throw new IllegalStateException("栈为空");
- }
- T element = elements[--size];
- elements[size] = null;
- return element;
- }
-
- public T peek() {
- if (isEmpty()) {
- throw new IllegalStateException("栈为空");
- }
- return elements[size - 1];
- }
-
- public boolean isEmpty() {
- return size == 0;
- }
-
- private void resize() {
- T[] newElements = (T[]) new Object[elements.length * 2];
- System.arraycopy(elements, 0, newElements, 0, size);
- elements = newElements;
- }
- }
复制代码- public class LinkedStack<T> {
- private Node<T> top;
- private int size;
-
- private static class Node<T> {
- T data;
- Node<T> next;
-
- Node(T data) {
- this.data = data;
- }
- }
-
- public void push(T element) {
- Node<T> newNode = new Node<>(element);
- newNode.next = top;
- top = newNode;
- size++;
- }
-
- public T pop() {
- if (isEmpty()) {
- throw new IllegalStateException("栈为空");
- }
- T element = top.data;
- top = top.next;
- size--;
- return element;
- }
-
- public T peek() {
- if (isEmpty()) {
- throw new IllegalStateException("栈为空");
- }
- return top.data;
- }
-
- public boolean isEmpty() {
- return top == null;
- }
- }
复制代码 2.3.4 栈的应用场景
- 函数调用栈
- 管理函数的调用和返回
- 保存局部变量和参数
- 处理递归调用
- 表达式求值
- public int evaluateExpression(String expression) {
- Stack<Integer> operands = new Stack<>();
- Stack<Character> operators = new Stack<>();
-
- for (char c : expression.toCharArray()) {
- if (Character.isDigit(c)) {
- operands.push(c - '0');
- } else if (c == '(') {
- operators.push(c);
- } else if (c == ')') {
- while (!operators.isEmpty() && operators.peek() != '(') {
- operands.push(calculate(operators.pop(), operands.pop(), operands.pop()));
- }
- operators.pop();
- } else if (isOperator(c)) {
- while (!operators.isEmpty() && precedence(operators.peek()) >= precedence(c)) {
- operands.push(calculate(operators.pop(), operands.pop(), operands.pop()));
- }
- operators.push(c);
- }
- }
-
- while (!operators.isEmpty()) {
- operands.push(calculate(operators.pop(), operands.pop(), operands.pop()));
- }
-
- return operands.pop();
- }
复制代码- public boolean isBalanced(String expression) {
- Stack<Character> stack = new Stack<>();
-
- for (char c : expression.toCharArray()) {
- if (c == '(' || c == '[' || c == '{') {
- stack.push(c);
- } else if (c == ')' || c == ']' || c == '}') {
- if (stack.isEmpty()) {
- return false;
- }
- char open = stack.pop();
- if (!isMatching(open, c)) {
- return false;
- }
- }
- }
-
- return stack.isEmpty();
- }
复制代码- public class BrowserHistory {
- private Stack<String> backStack;
- private Stack<String> forwardStack;
- private String currentPage;
-
- public BrowserHistory(String homepage) {
- backStack = new Stack<>();
- forwardStack = new Stack<>();
- currentPage = homepage;
- }
-
- public void visit(String url) {
- backStack.push(currentPage);
- currentPage = url;
- forwardStack.clear();
- }
-
- public String back() {
- if (backStack.isEmpty()) {
- return currentPage;
- }
- forwardStack.push(currentPage);
- currentPage = backStack.pop();
- return currentPage;
- }
-
- public String forward() {
- if (forwardStack.isEmpty()) {
- return currentPage;
- }
- backStack.push(currentPage);
- currentPage = forwardStack.pop();
- return currentPage;
- }
- }
复制代码 2.3.5 高级应用
- public class MinStack {
- private Stack<Integer> mainStack;
- private Stack<Integer> minStack;
-
- public MinStack() {
- mainStack = new Stack<>();
- minStack = new Stack<>();
- }
-
- public void push(int x) {
- mainStack.push(x);
- if (minStack.isEmpty() || x <= minStack.peek()) {
- minStack.push(x);
- }
- }
-
- public void pop() {
- if (mainStack.pop().equals(minStack.peek())) {
- minStack.pop();
- }
- }
-
- public int top() {
- return mainStack.peek();
- }
-
- public int getMin() {
- return minStack.peek();
- }
- }
复制代码- public class StackQueue<T> {
- private Stack<T> stack1;
- private Stack<T> stack2;
-
- public StackQueue() {
- stack1 = new Stack<>();
- stack2 = new Stack<>();
- }
-
- public void enqueue(T element) {
- stack1.push(element);
- }
-
- public T dequeue() {
- if (stack2.isEmpty()) {
- while (!stack1.isEmpty()) {
- stack2.push(stack1.pop());
- }
- }
- return stack2.pop();
- }
- }
复制代码 2.3.6 性能分析
- 时间复杂度
- 入栈(Push):O(1)
- 出栈(Pop):O(1)
- 查看栈顶(Peek):O(1)
- 判定空栈(IsEmpty):O(1)
- 空间复杂度
2.3.7 注意事项
- 栈溢出:注意处理栈满的环境
- 空栈操作:查抄栈是否为空再举行操作
- 内存管理:及时释放不必要的元素
- 线程安全:在多线程环境下必要同步处理
2.4 队列(Queue)
队列是一种特殊的线性数据结构,它遵循"先进先出"(FIFO, First In First Out)的原则。可以将其想象为列队买票,先到的人先买票,后到的人后买票。
2.4.1 队列的特点
- 先进先出(FIFO):开始加入队列的元素开始被移除
- 受限的访问:只能在队尾添加元素,在队首移除元素
- 动态巨细:可以根据必要动态增长或缩小
- 有序性:保持元素的相对顺序
2.4.2 队列的基本操作
- 入队(Enqueue):将元素添加到队尾
- 出队(Dequeue):移除并返回队首元素
- 查看队首元素(Peek/Front):返回队首元素但不移除
- 判定队列是否为空(IsEmpty):查抄队列中是否有元素
- 获取队列的巨细(Size):返回队列中元素的数量
2.4.3 队列的范例
- 平凡队列
平凡队列是最基本的队列范例,它严格遵循"先进先出"(FIFO)原则。元素只能从队尾入队,从队首出队,就像列队买票一样,先到的人先买票,后到的人后买票。
- public class ArrayQueue<T> {
- private T[] elements;
- private int front;
- private int rear;
- private int size;
-
- @SuppressWarnings("unchecked")
- public ArrayQueue(int capacity) {
- elements = (T[]) new Object[capacity];
- front = 0;
- rear = -1;
- size = 0;
- }
-
- public void enqueue(T element) {
- if (size == elements.length) {
- resize();
- }
- rear = (rear + 1) % elements.length;
- elements[rear] = element;
- size++;
- }
-
- public T dequeue() {
- if (isEmpty()) {
- throw new IllegalStateException("队列为空");
- }
- T element = elements[front];
- elements[front] = null;
- front = (front + 1) % elements.length;
- size--;
- return element;
- }
-
- public T peek() {
- if (isEmpty()) {
- throw new IllegalStateException("队列为空");
- }
- return elements[front];
- }
-
- public boolean isEmpty() {
- return size == 0;
- }
-
- private void resize() {
- T[] newElements = (T[]) new Object[elements.length * 2];
- for (int i = 0; i < size; i++) {
- newElements[i] = elements[(front + i) % elements.length];
- }
- elements = newElements;
- front = 0;
- rear = size - 1;
- }
- }
复制代码
- 循环队列
循环队列是一种特殊的队列实现,它将队列的存储空间视为一个环形结构。当队尾指针到达数组末尾时,它会回到数组的开始位置,这样可以更有效地使用存储空间,克制平凡队列中可能出现的"假溢出"问题。
- public class CircularQueue<T> {
- private T[] elements;
- private int front;
- private int rear;
- private int size;
-
- @SuppressWarnings("unchecked")
- public CircularQueue(int capacity) {
- elements = (T[]) new Object[capacity];
- front = rear = 0;
- size = 0;
- }
-
- public void enqueue(T element) {
- if (isFull()) {
- resize();
- }
- elements[rear] = element;
- rear = (rear + 1) % elements.length;
- size++;
- }
-
- public T dequeue() {
- if (isEmpty()) {
- throw new IllegalStateException("队列为空");
- }
- T element = elements[front];
- elements[front] = null;
- front = (front + 1) % elements.length;
- size--;
- return element;
- }
-
- public boolean isEmpty() {
- return size == 0;
- }
-
- public boolean isFull() {
- return size == elements.length;
- }
-
- private void resize() {
- T[] newElements = (T[]) new Object[elements.length * 2];
- for (int i = 0; i < size; i++) {
- newElements[i] = elements[(front + i) % elements.length];
- }
- elements = newElements;
- front = 0;
- rear = size;
- }
- }
复制代码
- 双端队列(Deque)
双端队列(Double-ended Queue)是一种允许从两端举行插入和删除操作的队列。它结合了队列和栈的特性,既可以从队首和队尾举行入队操作,也可以从队首和队尾举行出队操作,提供了更灵活的数据操作方式。
- public class Deque<T> {
- private Node<T> front;
- private Node<T> rear;
- private int size;
-
- private static class Node<T> {
- T data;
- Node<T> prev;
- Node<T> next;
-
- Node(T data) {
- this.data = data;
- }
- }
-
- public void addFirst(T element) {
- Node<T> newNode = new Node<>(element);
- if (isEmpty()) {
- front = rear = newNode;
- } else {
- newNode.next = front;
- front.prev = newNode;
- front = newNode;
- }
- size++;
- }
-
- public void addLast(T element) {
- Node<T> newNode = new Node<>(element);
- if (isEmpty()) {
- front = rear = newNode;
- } else {
- newNode.prev = rear;
- rear.next = newNode;
- rear = newNode;
- }
- size++;
- }
-
- public T removeFirst() {
- if (isEmpty()) {
- throw new IllegalStateException("队列为空");
- }
- T element = front.data;
- front = front.next;
- if (front == null) {
- rear = null;
- } else {
- front.prev = null;
- }
- size--;
- return element;
- }
-
- public T removeLast() {
- if (isEmpty()) {
- throw new IllegalStateException("队列为空");
- }
- T element = rear.data;
- rear = rear.prev;
- if (rear == null) {
- front = null;
- } else {
- rear.next = null;
- }
- size--;
- return element;
- }
-
- public boolean isEmpty() {
- return size == 0;
- }
- }
复制代码
- 优先队列
优先队列是一种特殊的队列,其中的元素按照优先级排序,而不是按照入队顺序。优先级高的元素会先出队,即使它是在优先级低的元素之后入队的。优先队列通常使用堆(Heap)数据结构来实现,以包管高效的优先级操作。
- public class PriorityQueue<T extends Comparable<T>> {
- private ArrayList<T> heap;
-
- public PriorityQueue() {
- heap = new ArrayList<>();
- }
-
- public void enqueue(T element) {
- heap.add(element);
- heapifyUp(heap.size() - 1);
- }
-
- public T dequeue() {
- if (isEmpty()) {
- throw new IllegalStateException("队列为空");
- }
-
- T root = heap.get(0);
- T lastElement = heap.remove(heap.size() - 1);
-
- if (!heap.isEmpty()) {
- heap.set(0, lastElement);
- heapifyDown(0);
- }
-
- return root;
- }
-
- private void heapifyUp(int index) {
- int parent = (index - 1) / 2;
-
- while (index > 0 && heap.get(parent).compareTo(heap.get(index)) > 0) {
- swap(parent, index);
- index = parent;
- parent = (index - 1) / 2;
- }
- }
-
- private void heapifyDown(int index) {
- int minIndex = index;
- int leftChild = 2 * index + 1;
- int rightChild = 2 * index + 2;
-
- if (leftChild < heap.size() && heap.get(leftChild).compareTo(heap.get(minIndex)) < 0) {
- minIndex = leftChild;
- }
-
- if (rightChild < heap.size() && heap.get(rightChild).compareTo(heap.get(minIndex)) < 0) {
- minIndex = rightChild;
- }
-
- if (minIndex != index) {
- swap(index, minIndex);
- heapifyDown(minIndex);
- }
- }
-
- private void swap(int i, int j) {
- T temp = heap.get(i);
- heap.set(i, heap.get(j));
- heap.set(j, temp);
- }
-
- public boolean isEmpty() {
- return heap.isEmpty();
- }
- }
复制代码 2.4.4 队列的应用场景
- 任务调度
- 进程调度队列
- 打印任务队列
- 任务优先级管理
- 资源分配
- 消息队列
- public class MessageQueue<T> {
- private Queue<T> queue;
- private final int capacity;
-
- public MessageQueue(int capacity) {
- this.queue = new LinkedList<>();
- this.capacity = capacity;
- }
-
- public synchronized void send(T message) throws InterruptedException {
- while (queue.size() == capacity) {
- wait(); // 队列满时等待
- }
- queue.offer(message);
- notifyAll(); // 通知等待的消费者
- }
-
- public synchronized T receive() throws InterruptedException {
- while (queue.isEmpty()) {
- wait(); // 队列空时等待
- }
- T message = queue.poll();
- notifyAll(); // 通知等待的生产者
- return message;
- }
- }
复制代码- public class BufferQueue<T> {
- private CircularQueue<T> buffer;
- private final int capacity;
-
- public BufferQueue(int capacity) {
- this.buffer = new CircularQueue<>(capacity);
- this.capacity = capacity;
- }
-
- public void write(T data) throws InterruptedException {
- synchronized (buffer) {
- while (buffer.isFull()) {
- buffer.wait();
- }
- buffer.enqueue(data);
- buffer.notifyAll();
- }
- }
-
- public T read() throws InterruptedException {
- synchronized (buffer) {
- while (buffer.isEmpty()) {
- buffer.wait();
- }
- T data = buffer.dequeue();
- buffer.notifyAll();
- return data;
- }
- }
- }
复制代码- public void bfs(Graph graph, int start) {
- boolean[] visited = new boolean[graph.getVertexCount()];
- Queue<Integer> queue = new LinkedList<>();
-
- visited[start] = true;
- queue.offer(start);
-
- while (!queue.isEmpty()) {
- int vertex = queue.poll();
- System.out.print(vertex + " ");
-
- for (int neighbor : graph.getNeighbors(vertex)) {
- if (!visited[neighbor]) {
- visited[neighbor] = true;
- queue.offer(neighbor);
- }
- }
- }
- }
复制代码 2.4.5 队列的性能分析
- 时间复杂度
- 入队(Enqueue):O(1)
- 出队(Dequeue):O(1)
- 查看队首(Peek):O(1)
- 判定空队列(IsEmpty):O(1)
- 空间复杂度
- 数组实现:O(n)
- 链表实现:O(n)
- 循环队列:O(n)
2.4.6 注意事项
- 队列溢出:处理队列满的环境
- 空队列操作:查抄队列是否为空再操作
- 内存管理:及时释放不必要的元素
- 并发安全:在多线程环境下必要同步处理
3. 高级数据结构
3.1 树(Tree)
3.1.0 通俗明确树
想象一下家属族谱或者公司的构造架构图,这就是树的一个很好的例子:
- 根节点:就像家属的祖先或者公司的CEO,是整个树的起点
- 子节点:就像家属中的子女或者公司的部门经理,他们都有上级
- 父节点:就像家属中的父母或者公司的上级领导,他们管理着下级
- 叶子节点:就像家属中没有子女的成员或者公司中没有下属的员工,他们是树的末了
- 兄弟节点:就像家属中的兄弟姐妹或者公司中同级的同事,他们有相同的上级
树的特点:
- 每个节点(除了根节点)都只有一个父节点
- 一个父节点可以有多个子节点
- 从根节点到任何叶子节点只有一条唯一的路径
- 树是分层的,就像公司的层级结构一样
生活中的树结构例子:
- 文件体系:文件夹可以包含子文件夹和文件,形成一个树状结构
- 网页导航菜单:主菜单下有子菜单,子菜单下还可以有子菜单
- 家谱:记录家属成员关系的族谱图
- 公司构造架构:从CEO到部门经理再到平凡员工的层级关系
- 动物分类:界、门、纲、目、科、属、种的生物分类体系
3.1.1 基本概念
树是一种非线性数据结构,由节点和边组成,具有以下特点:
- 节点(Node):存储数据的元素
- 根节点(Root):树的起始节点
- 叶子节点(Leaf):没有子节点的节点
- 父节点(Parent):直接毗连到子节点的节点
- 子节点(Child):直接毗连到父节点的节点
- 兄弟节点(Sibling):具有相同父节点的节点
- 深度(Depth):从根节点到该节点的路径长度
- 高度(Height):从该节点到叶子节点的最长路径长度
- 度(Degree):节点的子节点数量
- 层(Level):具有相同深度的节点集合
3.1.2 树的范例
- 二叉树(Binary Tree)
- 定义:每个节点最多有两个子节点的树结构
- 特点:
- 每个节点最多有两个子节点(左子节点和右子节点)
- 子节点分为左子节点和右子节点,顺序不能颠倒
- 空树也是二叉树
- 实现:
- class TreeNode {
- int data;
- TreeNode left;
- TreeNode right;
-
- TreeNode(int data) {
- this.data = data;
- this.left = null;
- this.right = null;
- }
- }
复制代码
- 应用:
- 表达式树:用于表示数学表达式
- 决策树:用于分类和决策
- 语法树:用于编译器中的语法分析
- 优缺点:
- 优点:结构简单,易于实现和明确
- 缺点:查找服从不高,可能不平衡
- 二叉搜索树(Binary Search Tree, BST)
- 定义:一种特殊的二叉树,其中左子树所有节点值小于根节点,右子树所有节点值大于根节点
- 特点:
- 左子树所有节点值小于根节点
- 右子树所有节点值大于根节点
- 左右子树也是二叉搜索树
- 实现:
- class BSTNode {
- int data;
- BSTNode left;
- BSTNode right;
-
- BSTNode(int data) {
- this.data = data;
- this.left = null;
- this.right = null;
- }
- }
- class BinarySearchTree {
- private BSTNode root;
-
- public void insert(int data) {
- root = insertRec(root, data);
- }
-
- private BSTNode insertRec(BSTNode node, int data) {
- if (node == null) {
- return new BSTNode(data);
- }
-
- if (data < node.data) {
- node.left = insertRec(node.left, data);
- } else if (data > node.data) {
- node.right = insertRec(node.right, data);
- }
-
- return node;
- }
-
- public boolean search(int data) {
- return searchRec(root, data);
- }
-
- private boolean searchRec(BSTNode node, int data) {
- if (node == null || node.data == data) {
- return node != null;
- }
-
- if (data < node.data) {
- return searchRec(node.left, data);
- }
-
- return searchRec(node.right, data);
- }
- }
复制代码
- 应用:
- 数据排序:中序遍历可以得到有序序列
- 数据查找:平均时间复杂度为O(log n)
- 范围查询:可以高效查找某个范围内的所有值
- 优缺点:
- 优点:查找、插入、删除的平均时间复杂度为O(log n)
- 缺点:最坏环境下可能退化为链表,时间复杂度变为O(n)
- 平衡二叉树(AVL树)
- 定义:一种自平衡的二叉搜索树,任何节点的左右子树高度差不超过1
- 特点:
- 左右子树高度差不超过1
- 通过旋转操作保持平衡
- 查找、插入、删除的时间复杂度稳固在O(log n)
- 平衡因子:节点的左子树高度减去右子树高度
- 旋转操作:
- 左旋:将节点的右子树变为根节点,原根节点变为左子树
- 右旋:将节点的左子树变为根节点,原根节点变为右子树
- 左右旋:先对左子树左旋,再对根节点右旋
- 右左旋:先对右子树右旋,再对根节点左旋
- 实现:
- 应用:
- 必要频繁查找的场景
- 必要包管查找性能稳固的体系
- 数据库索引
- 优缺点:
- 优点:查找、插入、删除的时间复杂度稳固在O(log n)
- 缺点:维护平衡必要额外的旋转操作,实现复杂
- 红黑树(Red-Black Tree)
- 定义:一种自平衡的二叉搜索树,通过节点颜色标记来保持平衡
- 特点:
- 每个节点是红色或玄色
- 根节点和叶子节点(NIL节点)是玄色
- 如果一个节点是红色,则其子节点必须是玄色
- 从任一节点到其每个叶子节点的所有路径都包含相同数量的玄色节点
- 实现:
- 应用:
- Java TreeMap和TreeSet的实现
- Linux内核的进程调度
- 数据库索引
- 优缺点:
- 优点:查找、插入、删除的时间复杂度稳固在O(log n),比AVL树更少的旋转操作
- 缺点:实现复杂,必要额外的颜色标记
- B树(B-Tree)
- 定义:一种多路平衡搜索树,每个节点可以有多个子节点
- 特点:
- 所有叶子节点在同一层
- 每个节点可以有多个子节点(通常为2-4个)
- 节点中的数据按顺序分列
- 所有数据都存储在节点中
- 实现:
- class BTreeNode {
- int[] keys;
- BTreeNode[] children;
- int numKeys;
- boolean isLeaf;
-
- BTreeNode(int t, boolean isLeaf) {
- this.keys = new int[2 * t - 1];
- this.children = new BTreeNode[2 * t];
- this.numKeys = 0;
- this.isLeaf = isLeaf;
- }
- }
- class BTree {
- private BTreeNode root;
- private int t; // 最小度数
-
- public BTree(int t) {
- this.root = null;
- this.t = t;
- }
-
- public void insert(int key) {
- if (root == null) {
- root = new BTreeNode(t, true);
- root.keys[0] = key;
- root.numKeys = 1;
- } else {
- if (root.numKeys == 2 * t - 1) {
- BTreeNode s = new BTreeNode(t, false);
- s.children[0] = root;
- splitChild(s, 0, root);
- int i = 0;
- if (s.keys[0] < key) {
- i++;
- }
- insertNonFull(s.children[i], key);
- root = s;
- } else {
- insertNonFull(root, key);
- }
- }
- }
-
- private void insertNonFull(BTreeNode node, int key) {
- int i = node.numKeys - 1;
-
- if (node.isLeaf) {
- while (i >= 0 && node.keys[i] > key) {
- node.keys[i + 1] = node.keys[i];
- i--;
- }
- node.keys[i + 1] = key;
- node.numKeys++;
- } else {
- while (i >= 0 && node.keys[i] > key) {
- i--;
- }
- if (node.children[i + 1].numKeys == 2 * t - 1) {
- splitChild(node, i + 1, node.children[i + 1]);
- if (node.keys[i + 1] < key) {
- i++;
- }
- }
- insertNonFull(node.children[i + 1], key);
- }
- }
-
- private void splitChild(BTreeNode parent, int i, BTreeNode child) {
- BTreeNode z = new BTreeNode(t, child.isLeaf);
- z.numKeys = t - 1;
-
- for (int j = 0; j < t - 1; j++) {
- z.keys[j] = child.keys[j + t];
- }
-
- if (!child.isLeaf) {
- for (int j = 0; j < t; j++) {
- z.children[j] = child.children[j + t];
- }
- }
-
- child.numKeys = t - 1;
-
- for (int j = parent.numKeys; j > i; j--) {
- parent.children[j + 1] = parent.children[j];
- }
-
- parent.children[i + 1] = z;
-
- for (int j = parent.numKeys - 1; j >= i; j--) {
- parent.keys[j + 1] = parent.keys[j];
- }
-
- parent.keys[i] = child.keys[t - 1];
- parent.numKeys++;
- }
- }
复制代码
- 应用:
- 优缺点:
- 优点:适合磁盘存储,减少磁盘I/O次数
- 缺点:内存中操作服从不如二叉搜索树
- B+树(B+ Tree)
- 定义:B树的变种,所有数据都存储在叶子节点,非叶子节点只存储键值
- 特点:
- 所有数据都存储在叶子节点,非叶子节点只存储键值
- 所有叶子节点通过链表毗连,便于范围查询
- 非叶子节点可以有多个子节点
- 所有叶子节点在同一层
- 实现:
- class BPlusTreeNode {
- int[] keys;
- BPlusTreeNode[] children;
- BPlusTreeNode next; // 指向下一个叶子节点
- int numKeys;
- boolean isLeaf;
-
- BPlusTreeNode(int t, boolean isLeaf) {
- this.keys = new int[2 * t - 1];
- this.children = new BPlusTreeNode[2 * t];
- this.next = null;
- this.numKeys = 0;
- this.isLeaf = isLeaf;
- }
- }
- class BPlusTree {
- private BPlusTreeNode root;
- private BPlusTreeNode head; // 指向第一个叶子节点
- private int t; // 最小度数
-
- public BPlusTree(int t) {
- this.root = null;
- this.head = null;
- this.t = t;
- }
-
- public void insert(int key) {
- if (root == null) {
- root = new BPlusTreeNode(t, true);
- root.keys[0] = key;
- root.numKeys = 1;
- head = root;
- } else {
- if (root.numKeys == 2 * t - 1) {
- BPlusTreeNode s = new BPlusTreeNode(t, false);
- s.children[0] = root;
- splitChild(s, 0, root);
- int i = 0;
- if (s.keys[0] < key) {
- i++;
- }
- insertNonFull(s.children[i], key);
- root = s;
- } else {
- insertNonFull(root, key);
- }
- }
- }
-
- private void insertNonFull(BPlusTreeNode node, int key) {
- int i = node.numKeys - 1;
-
- if (node.isLeaf) {
- while (i >= 0 && node.keys[i] > key) {
- node.keys[i + 1] = node.keys[i];
- i--;
- }
- node.keys[i + 1] = key;
- node.numKeys++;
- } else {
- while (i >= 0 && node.keys[i] > key) {
- i--;
- }
- if (node.children[i + 1].numKeys == 2 * t - 1) {
- splitChild(node, i + 1, node.children[i + 1]);
- if (node.keys[i + 1] < key) {
- i++;
- }
- }
- insertNonFull(node.children[i + 1], key);
- }
- }
-
- private void splitChild(BPlusTreeNode parent, int i, BPlusTreeNode child) {
- BPlusTreeNode z = new BPlusTreeNode(t, child.isLeaf);
- z.numKeys = t - 1;
-
- for (int j = 0; j < t - 1; j++) {
- z.keys[j] = child.keys[j + t];
- }
-
- if (!child.isLeaf) {
- for (int j = 0; j < t; j++) {
- z.children[j] = child.children[j + t];
- }
- }
-
- child.numKeys = t - 1;
-
- for (int j = parent.numKeys; j > i; j--) {
- parent.children[j + 1] = parent.children[j];
- }
-
- parent.children[i + 1] = z;
-
- for (int j = parent.numKeys - 1; j >= i; j--) {
- parent.keys[j + 1] = parent.keys[j];
- }
-
- parent.keys[i] = child.keys[t - 1];
- parent.numKeys++;
-
- // 如果是叶子节点,需要维护链表
- if (child.isLeaf) {
- z.next = child.next;
- child.next = z;
- }
- }
-
- // 范围查询
- public List<Integer> rangeQuery(int start, int end) {
- List<Integer> result = new ArrayList<>();
- BPlusTreeNode leaf = findLeaf(root, start);
-
- while (leaf != null) {
- for (int i = 0; i < leaf.numKeys; i++) {
- if (leaf.keys[i] >= start && leaf.keys[i] <= end) {
- result.add(leaf.keys[i]);
- }
- if (leaf.keys[i] > end) {
- return result;
- }
- }
- leaf = leaf.next;
- }
-
- return result;
- }
-
- private BPlusTreeNode findLeaf(BPlusTreeNode node, int key) {
- if (node.isLeaf) {
- return node;
- }
-
- int i = 0;
- while (i < node.numKeys && key >= node.keys[i]) {
- i++;
- }
-
- return findLeaf(node.children[i], key);
- }
- }
复制代码
- 应用:
- 数据库索引(MySQL的InnoDB引擎)
- 文件体系(NTFS、ReiserFS)
- 范围查询频繁的场景
- 优缺点:
- 优点:范围查询服从高,适合数据库索引
- 缺点:实现复杂,插入和删除操作必要维护叶子节点链表
- 字典树(Trie)
- 定义:一种树形数据结构,专门用于高效地存储和检索字符串
- 特点:
- 每个节点代表一个字符
- 从根节点到某一节点的路径上的字符毗连起来,就是该节点对应的字符串
- 共享前缀,节省空间
- 查找时间复杂度与字符串长度相干,与数据集巨细无关
- 实现:
- class TrieNode {
- TrieNode[] children;
- boolean isEndOfWord;
-
- TrieNode() {
- children = new TrieNode[26]; // 假设只处理小写字母
- isEndOfWord = false;
- }
- }
- class Trie {
- private TrieNode root;
-
- public Trie() {
- root = new TrieNode();
- }
-
- public void insert(String word) {
- TrieNode node = root;
-
- for (int i = 0; i < word.length(); i++) {
- int index = word.charAt(i) - 'a';
- if (node.children[index] == null) {
- node.children[index] = new TrieNode();
- }
- node = node.children[index];
- }
-
- node.isEndOfWord = true;
- }
-
- public boolean search(String word) {
- TrieNode node = searchNode(word);
- return node != null && node.isEndOfWord;
- }
-
- public boolean startsWith(String prefix) {
- return searchNode(prefix) != null;
- }
-
- private TrieNode searchNode(String word) {
- TrieNode node = root;
-
- for (int i = 0; i < word.length(); i++) {
- int index = word.charAt(i) - 'a';
- if (node.children[index] == null) {
- return null;
- }
- node = node.children[index];
- }
-
- return node;
- }
- }
复制代码
- 应用:
- 优缺点:
- 优点:查找服从高,适合前缀匹配
- 缺点:空间斲丧大,不适合处理长字符串
- 堆(Heap)
- 定义:一种特殊的完全二叉树,满意堆属性
- 特点:
- 完全二叉树结构
- 堆属性:父节点总是大于或小于其子节点
- 最大堆:父节点大于子节点
- 最小堆:父节点小于子节点
- 实现:
- class MaxHeap {
- private int[] heap;
- private int size;
- private int capacity;
-
- public MaxHeap(int capacity) {
- this.capacity = capacity;
- this.size = 0;
- this.heap = new int[capacity];
- }
-
- private int parent(int i) {
- return (i - 1) / 2;
- }
-
- private int leftChild(int i) {
- return 2 * i + 1;
- }
-
- private int rightChild(int i) {
- return 2 * i + 2;
- }
-
- private void swap(int i, int j) {
- int temp = heap[i];
- heap[i] = heap[j];
- heap[j] = temp;
- }
-
- private void heapifyUp(int i) {
- while (i > 0 && heap[parent(i)] < heap[i]) {
- swap(parent(i), i);
- i = parent(i);
- }
- }
-
- private void heapifyDown(int i) {
- int maxIndex = i;
- int left = leftChild(i);
- int right = rightChild(i);
-
- if (left < size && heap[left] > heap[maxIndex]) {
- maxIndex = left;
- }
-
- if (right < size && heap[right] > heap[maxIndex]) {
- maxIndex = right;
- }
-
- if (i != maxIndex) {
- swap(i, maxIndex);
- heapifyDown(maxIndex);
- }
- }
-
- public void insert(int value) {
- if (size == capacity) {
- // 扩容
- int[] newHeap = new int[capacity * 2];
- System.arraycopy(heap, 0, newHeap, 0, size);
- heap = newHeap;
- capacity *= 2;
- }
-
- heap[size] = value;
- heapifyUp(size);
- size++;
- }
-
- public int extractMax() {
- if (size == 0) {
- throw new IllegalStateException("堆为空");
- }
-
- int max = heap[0];
- heap[0] = heap[size - 1];
- size--;
- heapifyDown(0);
-
- return max;
- }
-
- public int getMax() {
- if (size == 0) {
- throw new IllegalStateException("堆为空");
- }
- return heap[0];
- }
- }
复制代码
- 应用:
- 优先队列
- 堆排序
- 任务调度
- 图算法(如Dijkstra最短路径)
- 优缺点:
- 优点:插入和删除最大/最小元素的时间复杂度为O(log n)
- 缺点:不支持随机访问,只能访问最大/最小元素
3.1.3 树的遍历方式
- // 前序遍历(根-左-右)
- public void preorder(Node node) {
- if (node != null) {
- System.out.print(node.data + " ");
- preorder(node.left);
- preorder(node.right);
- }
- }
- // 中序遍历(左-根-右)
- public void inorder(Node node) {
- if (node != null) {
- inorder(node.left);
- System.out.print(node.data + " ");
- inorder(node.right);
- }
- }
- // 后序遍历(左-右-根)
- public void postorder(Node node) {
- if (node != null) {
- postorder(node.left);
- postorder(node.right);
- System.out.print(node.data + " ");
- }
- }
复制代码- public void levelOrder(Node root) {
- if (root == null) return;
-
- Queue<Node> queue = new LinkedList<>();
- queue.offer(root);
-
- while (!queue.isEmpty()) {
- Node node = queue.poll();
- System.out.print(node.data + " ");
-
- if (node.left != null) {
- queue.offer(node.left);
- }
- if (node.right != null) {
- queue.offer(node.right);
- }
- }
- }
复制代码 3.1.4 树的基本操作
- public void insert(int data) {
- root = insertRec(root, data);
- }
- private Node insertRec(Node node, int data) {
- if (node == null) {
- return new Node(data);
- }
-
- if (data < node.data) {
- node.left = insertRec(node.left, data);
- } else if (data > node.data) {
- node.right = insertRec(node.right, data);
- }
-
- return node;
- }
复制代码- public void delete(int data) {
- root = deleteRec(root, data);
- }
- private Node deleteRec(Node node, int data) {
- if (node == null) return null;
-
- if (data < node.data) {
- node.left = deleteRec(node.left, data);
- } else if (data > node.data) {
- node.right = deleteRec(node.right, data);
- } else {
- // 找到要删除的节点
- if (node.left == null) {
- return node.right;
- } else if (node.right == null) {
- return node.left;
- }
-
- // 有两个子节点的情况
- node.data = minValue(node.right);
- node.right = deleteRec(node.right, node.data);
- }
-
- return node;
- }
- private int minValue(Node node) {
- int minv = node.data;
- while (node.left != null) {
- minv = node.left.data;
- node = node.left;
- }
- return minv;
- }
复制代码- public Node search(int data) {
- return searchRec(root, data);
- }
- private Node searchRec(Node node, int data) {
- if (node == null || node.data == data) {
- return node;
- }
-
- if (data < node.data) {
- return searchRec(node.left, data);
- }
-
- return searchRec(node.right, data);
- }
复制代码 3.1.5 树的常见问题
- public int height(Node node) {
- if (node == null) return 0;
- return Math.max(height(node.left), height(node.right)) + 1;
- }
复制代码- public boolean isBalanced(Node node) {
- if (node == null) return true;
-
- int leftHeight = height(node.left);
- int rightHeight = height(node.right);
-
- return Math.abs(leftHeight - rightHeight) <= 1
- && isBalanced(node.left)
- && isBalanced(node.right);
- }
复制代码- public boolean isBST(Node node) {
- return isBSTUtil(node, Integer.MIN_VALUE, Integer.MAX_VALUE);
- }
- private boolean isBSTUtil(Node node, int min, int max) {
- if (node == null) return true;
-
- if (node.data < min || node.data > max) return false;
-
- return isBSTUtil(node.left, min, node.data - 1)
- && isBSTUtil(node.right, node.data + 1, max);
- }
复制代码- public Node findLCA(Node root, int n1, int n2) {
- if (root == null) return null;
-
- if (root.data == n1 || root.data == n2) {
- return root;
- }
-
- Node left = findLCA(root.left, n1, n2);
- Node right = findLCA(root.right, n1, n2);
-
- if (left != null && right != null) {
- return root;
- }
-
- return left != null ? left : right;
- }
复制代码 3.1.6 树的应用场景
- 文件体系
- 数据库体系
- 编译器
- 游戏开发
- 网络应用
- 机器学习
- 图像处理
- 文本处理
3.2 图(Graph)
3.2.1 基本概念
- 通俗明确:
- 图就像一张地图或交际网络,由所在(顶点)和毗连这些所在的门路(边)组成
- 想象一个城市地图:城市中的各个所在(如商场、学校、医院)是顶点,毗连这些所在的门路是边
- 或者想象一个交际网络:每个人是顶点,朋友关系是边
- 有向图就像单向街道,只能朝一个方向走;无向图就像双向街道,可以往返走
- 加权图就像每条门路有差别的距离或通行时间
- 定义:图是由顶点(Vertex)和边(Edge)组成的非线性数据结构
- 组成部门:
- 顶点(Vertex/Node):图中的数据元素
- 边(Edge/Arc):毗连顶点的线,表示顶点之间的关系
- 度(Degree):与顶点相连的边的数量
- 入度(In-degree):指向顶点的边的数量
- 出度(Out-degree):从顶点出发的边的数量
- 图的范例:
- 有向图(Directed Graph):边有方向,表示单向关系
- 无向图(Undirected Graph):边无方向,表示双向关系
- 加权图(Weighted Graph):边有权重,表示关系的强度或成本
- 完全图(Complete Graph):任意两个顶点之间都有边毗连
- 连通图(Connected Graph):任意两个顶点之间都存在路径
- 强连通图(Strongly Connected Graph):有向图中任意两个顶点之间都存在双向路径
- 路径与环:
- 路径(Path):从一个顶点到另一个顶点的边的序列
- 简单路径(Simple Path):不重复经过顶点的路径
- 环(Cycle):起点和终点相同的路径
- 简单环(Simple Cycle):除了起点和终点外,不重复经过顶点的环
- 子图(Subgraph):由图的顶点和边的子集组成的图
3.2.2 图的表示方法
- 邻接矩阵(Adjacency Matrix)
- 定义:使用二维数组表示顶点之间的毗连关系
- 特点:
- 对于无向图,矩阵是对称的
- 对于有向图,矩阵不一定对称
- 对于加权图,矩阵元素表示权重
- 实现:
- public class AdjacencyMatrixGraph {
- private int[][] matrix;
- private int vertices;
-
- public AdjacencyMatrixGraph(int vertices) {
- this.vertices = vertices;
- matrix = new int[vertices][vertices];
- }
-
- // 添加无向边
- public void addEdgeUndirected(int source, int destination) {
- matrix[source][destination] = 1;
- matrix[destination][source] = 1; // 无向图是对称的
- }
-
- // 添加有向边
- public void addEdgeDirected(int source, int destination) {
- matrix[source][destination] = 1;
- }
-
- // 添加加权边
- public void addWeightedEdge(int source, int destination, int weight) {
- matrix[source][destination] = weight;
- }
-
- // 删除边
- public void removeEdge(int source, int destination) {
- matrix[source][destination] = 0;
- }
-
- // 检查边是否存在
- public boolean hasEdge(int source, int destination) {
- return matrix[source][destination] != 0;
- }
-
- // 获取顶点的度(无向图)
- public int getDegree(int vertex) {
- int degree = 0;
- for (int i = 0; i < vertices; i++) {
- if (matrix[vertex][i] != 0) {
- degree++;
- }
- }
- return degree;
- }
-
- // 获取顶点的入度(有向图)
- public int getInDegree(int vertex) {
- int inDegree = 0;
- for (int i = 0; i < vertices; i++) {
- if (matrix[i][vertex] != 0) {
- inDegree++;
- }
- }
- return inDegree;
- }
-
- // 获取顶点的出度(有向图)
- public int getOutDegree(int vertex) {
- int outDegree = 0;
- for (int i = 0; i < vertices; i++) {
- if (matrix[vertex][i] != 0) {
- outDegree++;
- }
- }
- return outDegree;
- }
-
- // 打印图
- public void printGraph() {
- for (int i = 0; i < vertices; i++) {
- System.out.print("Vertex " + i + " is connected to: ");
- for (int j = 0; j < vertices; j++) {
- if (matrix[i][j] != 0) {
- System.out.print(j + " ");
- }
- }
- System.out.println();
- }
- }
- }
复制代码
- 优缺点:
- 优点:查找边的时间复杂度为O(1),适合稠密图
- 缺点:空间复杂度为O(V²),不适合稀疏图
- 邻接表(Adjacency List)
- 定义:使用数组和链表表示顶点之间的毗连关系
- 特点:
- 每个顶点维护一个链表,存储与之相连的顶点
- 对于有向图,可以只存储出边或入边
- 对于加权图,链表节点必要存储权重
- 实现:
- import java.util.*;
- public class AdjacencyListGraph {
- private int vertices;
- private LinkedList<Integer>[] adjList;
-
- @SuppressWarnings("unchecked")
- public AdjacencyListGraph(int vertices) {
- this.vertices = vertices;
- adjList = new LinkedList[vertices];
-
- for (int i = 0; i < vertices; i++) {
- adjList[i] = new LinkedList<>();
- }
- }
-
- // 添加无向边
- public void addEdgeUndirected(int source, int destination) {
- adjList[source].add(destination);
- adjList[destination].add(source); // 无向图需要添加双向边
- }
-
- // 添加有向边
- public void addEdgeDirected(int source, int destination) {
- adjList[source].add(destination);
- }
-
- // 删除边
- public void removeEdge(int source, int destination) {
- adjList[source].remove(Integer.valueOf(destination));
- }
-
- // 检查边是否存在
- public boolean hasEdge(int source, int destination) {
- return adjList[source].contains(destination);
- }
-
- // 获取顶点的度(无向图)
- public int getDegree(int vertex) {
- return adjList[vertex].size();
- }
-
- // 获取顶点的入度(有向图)
- public int getInDegree(int vertex) {
- int inDegree = 0;
- for (int i = 0; i < vertices; i++) {
- if (adjList[i].contains(vertex)) {
- inDegree++;
- }
- }
- return inDegree;
- }
-
- // 获取顶点的出度(有向图)
- public int getOutDegree(int vertex) {
- return adjList[vertex].size();
- }
-
- // 打印图
- public void printGraph() {
- for (int i = 0; i < vertices; i++) {
- System.out.print("Vertex " + i + " is connected to: ");
- for (Integer neighbor : adjList[i]) {
- System.out.print(neighbor + " ");
- }
- System.out.println();
- }
- }
- }
复制代码
- 优缺点:
- 优点:空间复杂度为O(V+E),适合稀疏图
- 缺点:查找边的时间复杂度为O(degree),不适合稠密图
- 边集(Edge List)
- 定义:使用数组或链表存储图中的所有边
- 特点:
- 实现:
- import java.util.*;
- class Edge {
- int source;
- int destination;
- int weight;
-
- Edge(int source, int destination, int weight) {
- this.source = source;
- this.destination = destination;
- this.weight = weight;
- }
- }
- public class EdgeListGraph {
- private int vertices;
- private List<Edge> edges;
-
- public EdgeListGraph(int vertices) {
- this.vertices = vertices;
- this.edges = new ArrayList<>();
- }
-
- // 添加边
- public void addEdge(int source, int destination, int weight) {
- edges.add(new Edge(source, destination, weight));
- }
-
- // 删除边
- public void removeEdge(int source, int destination) {
- edges.removeIf(edge -> edge.source == source && edge.destination == destination);
- }
-
- // 检查边是否存在
- public boolean hasEdge(int source, int destination) {
- for (Edge edge : edges) {
- if (edge.source == source && edge.destination == destination) {
- return true;
- }
- }
- return false;
- }
-
- // 获取顶点的度(无向图)
- public int getDegree(int vertex) {
- int degree = 0;
- for (Edge edge : edges) {
- if (edge.source == vertex || edge.destination == vertex) {
- degree++;
- }
- }
- return degree;
- }
-
- // 打印图
- public void printGraph() {
- for (Edge edge : edges) {
- System.out.println("Edge from " + edge.source + " to " + edge.destination + " with weight " + edge.weight);
- }
- }
- }
复制代码
- 优缺点:
- 优点:空间复杂度为O(E),适合非常稀疏的图
- 缺点:查找边的时间复杂度为O(E),不适合必要频繁查找边的场景
3.2.3 图的遍历算法
- 深度优先搜索(Depth-First Search, DFS)
- 定义:沿着一条路径一直访问到底,然后回溯,再访问其他路径
- 特点:
- 使用栈(递归或显式栈)实现
- 时间复杂度:O(V+E),其中V是顶点数,E是边数
- 空间复杂度:O(V),用于存储访问标记和递归栈
- 实现:
- public class GraphTraversal {
- // 使用邻接表实现的图的DFS
- public static void dfs(LinkedList<Integer>[] adjList, int vertices) {
- boolean[] visited = new boolean[vertices];
-
- // 从每个未访问的顶点开始DFS
- for (int i = 0; i < vertices; i++) {
- if (!visited[i]) {
- dfsUtil(adjList, i, visited);
- }
- }
- }
-
- private static void dfsUtil(LinkedList<Integer>[] adjList, int vertex, boolean[] visited) {
- // 标记当前顶点为已访问
- visited[vertex] = true;
- System.out.print(vertex + " ");
-
- // 递归访问所有未访问的邻接顶点
- for (int neighbor : adjList[vertex]) {
- if (!visited[neighbor]) {
- dfsUtil(adjList, neighbor, visited);
- }
- }
- }
-
- // 使用显式栈实现的DFS(非递归)
- public static void dfsIterative(LinkedList<Integer>[] adjList, int vertices) {
- boolean[] visited = new boolean[vertices];
- Stack<Integer> stack = new Stack<>();
-
- // 从每个未访问的顶点开始DFS
- for (int i = 0; i < vertices; i++) {
- if (!visited[i]) {
- stack.push(i);
-
- while (!stack.isEmpty()) {
- int vertex = stack.pop();
-
- if (!visited[vertex]) {
- visited[vertex] = true;
- System.out.print(vertex + " ");
-
- // 将未访问的邻接顶点压入栈中(注意顺序,为了保持与递归版本相同的访问顺序)
- for (int j = adjList[vertex].size() - 1; j >= 0; j--) {
- int neighbor = adjList[vertex].get(j);
- if (!visited[neighbor]) {
- stack.push(neighbor);
- }
- }
- }
- }
- }
- }
- }
- }
复制代码
- 应用:
- 拓扑排序
- 检测图中的环
- 探求连通分量
- 办理迷宫问题
- 广度优先搜索(Breadth-First Search, BFS)
- 定义:先访问起始顶点的所有邻接顶点,然后再访问这些顶点的邻接顶点,以此类推
- 特点:
- 使用队列实现
- 时间复杂度:O(V+E),其中V是顶点数,E是边数
- 空间复杂度:O(V),用于存储访问标记和队列
- 可以找到从起始顶点到其他顶点的最短路径(对于无权图)
- 实现:
- import java.util.*;
- public class GraphTraversal {
- // 使用邻接表实现的图的BFS
- public static void bfs(LinkedList<Integer>[] adjList, int vertices, int startVertex) {
- boolean[] visited = new boolean[vertices];
- Queue<Integer> queue = new LinkedList<>();
-
- // 标记起始顶点为已访问并加入队列
- visited[startVertex] = true;
- queue.offer(startVertex);
-
- while (!queue.isEmpty()) {
- // 从队列中取出一个顶点并访问
- int vertex = queue.poll();
- System.out.print(vertex + " ");
-
- // 将所有未访问的邻接顶点加入队列
- for (int neighbor : adjList[vertex]) {
- if (!visited[neighbor]) {
- visited[neighbor] = true;
- queue.offer(neighbor);
- }
- }
- }
- }
-
- // 使用BFS找到从起始顶点到所有其他顶点的最短路径(无权图)
- public static int[] shortestPath(LinkedList<Integer>[] adjList, int vertices, int startVertex) {
- int[] distance = new int[vertices];
- Arrays.fill(distance, -1); // 初始化为-1表示不可达
- distance[startVertex] = 0; // 起始顶点到自身的距离为0
-
- boolean[] visited = new boolean[vertices];
- Queue<Integer> queue = new LinkedList<>();
-
- visited[startVertex] = true;
- queue.offer(startVertex);
-
- while (!queue.isEmpty()) {
- int vertex = queue.poll();
-
- for (int neighbor : adjList[vertex]) {
- if (!visited[neighbor]) {
- visited[neighbor] = true;
- distance[neighbor] = distance[vertex] + 1; // 距离加1
- queue.offer(neighbor);
- }
- }
- }
-
- return distance;
- }
- }
复制代码
- 应用:
- 探求最短路径(无权图)
- 交际网络中的"六度分隔"理论
- 网络爬虫
- 广播消息
3.2.4 图的最短路径算法
- Dijkstra算法
- 定义:用于办理带权有向图或无向图的单源最短路径问题
- 特点:
- 时间复杂度:O(V²),使用优先队列可优化至O(E log V)
- 不能处理负权边
- 适用于稠密图
- 实现:
- import java.util.*;
- class Node implements Comparable<Node> {
- int vertex;
- int distance;
-
- Node(int vertex, int distance) {
- this.vertex = vertex;
- this.distance = distance;
- }
-
- @Override
- public int compareTo(Node other) {
- return Integer.compare(this.distance, other.distance);
- }
- }
- public class ShortestPath {
- // 使用邻接矩阵实现的Dijkstra算法
- public static int[] dijkstra(int[][] graph, int source, int vertices) {
- int[] distance = new int[vertices];
- boolean[] visited = new boolean[vertices];
-
- // 初始化距离数组
- Arrays.fill(distance, Integer.MAX_VALUE);
- distance[source] = 0;
-
- // 找到所有顶点的最短路径
- for (int count = 0; count < vertices - 1; count++) {
- // 找到未访问顶点中距离最小的
- int u = minDistance(distance, visited, vertices);
-
- // 标记为已访问
- visited[u] = true;
-
- // 更新邻接顶点的距离
- for (int v = 0; v < vertices; v++) {
- // 如果顶点v未访问,且从u到v有边,且经过u的路径比当前路径短
- if (!visited[v] && graph[u][v] != 0 && distance[u] != Integer.MAX_VALUE
- && distance[u] + graph[u][v] < distance[v]) {
- distance[v] = distance[u] + graph[u][v];
- }
- }
- }
-
- return distance;
- }
-
- // 找到未访问顶点中距离最小的
- private static int minDistance(int[] distance, boolean[] visited, int vertices) {
- int min = Integer.MAX_VALUE;
- int minIndex = -1;
-
- for (int v = 0; v < vertices; v++) {
- if (!visited[v] && distance[v] <= min) {
- min = distance[v];
- minIndex = v;
- }
- }
-
- return minIndex;
- }
-
- // 使用优先队列优化的Dijkstra算法
- public static int[] dijkstraOptimized(List<List<Node>> adjList, int source, int vertices) {
- int[] distance = new int[vertices];
- Arrays.fill(distance, Integer.MAX_VALUE);
- distance[source] = 0;
-
- PriorityQueue<Node> pq = new PriorityQueue<>();
- pq.offer(new Node(source, 0));
-
- while (!pq.isEmpty()) {
- Node current = pq.poll();
- int u = current.vertex;
- int dist = current.distance;
-
- // 如果已经找到更短的路径,则跳过
- if (dist > distance[u]) {
- continue;
- }
-
- // 更新邻接顶点的距离
- for (Node neighbor : adjList.get(u)) {
- int v = neighbor.vertex;
- int weight = neighbor.distance;
-
- if (distance[u] != Integer.MAX_VALUE && distance[u] + weight < distance[v]) {
- distance[v] = distance[u] + weight;
- pq.offer(new Node(v, distance[v]));
- }
- }
- }
-
- return distance;
- }
- }
复制代码
- Floyd-Warshall算法
- 定义:用于办理所有顶点对之间的最短路径问题
- 特点:
- 时间复杂度:O(V³)
- 可以处理负权边,但不能处理负权环
- 适用于稠密图
- 实现:
- public class ShortestPath {
- // Floyd-Warshall算法
- public static int[][] floydWarshall(int[][] graph, int vertices) {
- int[][] dist = new int[vertices][vertices];
-
- // 初始化距离矩阵
- for (int i = 0; i < vertices; i++) {
- for (int j = 0; j < vertices; j++) {
- if (i == j) {
- dist[i][j] = 0;
- } else if (graph[i][j] != 0) {
- dist[i][j] = graph[i][j];
- } else {
- dist[i][j] = Integer.MAX_VALUE;
- }
- }
- }
-
- // 通过所有中间顶点更新距离
- for (int k = 0; k < vertices; k++) {
- for (int i = 0; i < vertices; i++) {
- for (int j = 0; j < vertices; j++) {
- // 如果经过顶点k的路径比当前路径短
- if (dist[i][k] != Integer.MAX_VALUE && dist[k][j] != Integer.MAX_VALUE
- && dist[i][k] + dist[k][j] < dist[i][j]) {
- dist[i][j] = dist[i][k] + dist[k][j];
- }
- }
- }
- }
-
- return dist;
- }
- }
复制代码
- Bellman-Ford算法
- 定义:用于办理带权有向图的单源最短路径问题,可以处理负权边
- 特点:
- 时间复杂度:O(VE),其中V是顶点数,E是边数
- 可以检测负权环
- 适用于稀疏图
- 实现:
- class Edge {
- int source;
- int destination;
- int weight;
-
- Edge(int source, int destination, int weight) {
- this.source = source;
- this.destination = destination;
- this.weight = weight;
- }
- }
- public class ShortestPath {
- // Bellman-Ford算法
- public static int[] bellmanFord(List<Edge> edges, int vertices, int source) {
- int[] distance = new int[vertices];
- Arrays.fill(distance, Integer.MAX_VALUE);
- distance[source] = 0;
-
- // 进行V-1次松弛操作
- for (int i = 0; i < vertices - 1; i++) {
- for (Edge edge : edges) {
- int u = edge.source;
- int v = edge.destination;
- int weight = edge.weight;
-
- if (distance[u] != Integer.MAX_VALUE && distance[u] + weight < distance[v]) {
- distance[v] = distance[u] + weight;
- }
- }
- }
-
- // 检测负权环
- for (Edge edge : edges) {
- int u = edge.source;
- int v = edge.destination;
- int weight = edge.weight;
-
- if (distance[u] != Integer.MAX_VALUE && distance[u] + weight < distance[v]) {
- System.out.println("图中存在负权环");
- return null;
- }
- }
-
- return distance;
- }
- }
复制代码
3.2.5 图的其他重要算法
- 拓扑排序(Topological Sort)
- 定义:对有向无环图(DAG)的顶点举行线性排序,使得对于图中的每一条有向边(u, v),u在排序中总是出如今v之前
- 应用:任务调度、依赖关系分析、编译顺序
- 实现:
- import java.util.*;
- public class TopologicalSort {
- // 使用Kahn算法实现拓扑排序
- public static List<Integer> topologicalSortKahn(List<List<Integer>> adjList, int vertices) {
- // 计算每个顶点的入度
- int[] inDegree = new int[vertices];
- for (int i = 0; i < vertices; i++) {
- for (int neighbor : adjList.get(i)) {
- inDegree[neighbor]++;
- }
- }
-
- // 将所有入度为0的顶点加入队列
- Queue<Integer> queue = new LinkedList<>();
- for (int i = 0; i < vertices; i++) {
- if (inDegree[i] == 0) {
- queue.offer(i);
- }
- }
-
- List<Integer> result = new ArrayList<>();
- int count = 0;
-
- while (!queue.isEmpty()) {
- // 取出一个入度为0的顶点
- int vertex = queue.poll();
- result.add(vertex);
- count++;
-
- // 减少所有邻接顶点的入度
- for (int neighbor : adjList.get(vertex)) {
- inDegree[neighbor]--;
- if (inDegree[neighbor] == 0) {
- queue.offer(neighbor);
- }
- }
- }
-
- // 如果访问的顶点数等于图中的顶点数,则图中没有环
- if (count == vertices) {
- return result;
- } else {
- System.out.println("图中存在环,无法进行拓扑排序");
- return new ArrayList<>();
- }
- }
-
- // 使用DFS实现拓扑排序
- public static List<Integer> topologicalSortDFS(List<List<Integer>> adjList, int vertices) {
- boolean[] visited = new boolean[vertices];
- boolean[] recStack = new boolean[vertices];
- Stack<Integer> stack = new Stack<>();
-
- // 从每个未访问的顶点开始DFS
- for (int i = 0; i < vertices; i++) {
- if (!visited[i]) {
- if (topologicalSortDFSUtil(adjList, i, visited, recStack, stack)) {
- System.out.println("图中存在环,无法进行拓扑排序");
- return new ArrayList<>();
- }
- }
- }
-
- // 将栈中的顶点依次取出,得到拓扑排序
- List<Integer> result = new ArrayList<>();
- while (!stack.isEmpty()) {
- result.add(stack.pop());
- }
-
- return result;
- }
-
- private static boolean topologicalSortDFSUtil(List<List<Integer>> adjList, int vertex,
- boolean[] visited, boolean[] recStack, Stack<Integer> stack) {
- // 标记当前顶点为已访问,并加入递归栈
- visited[vertex] = true;
- recStack[vertex] = true;
-
- // 递归访问所有邻接顶点
- for (int neighbor : adjList.get(vertex)) {
- if (!visited[neighbor]) {
- if (topologicalSortDFSUtil(adjList, neighbor, visited, recStack, stack)) {
- return true; // 检测到环
- }
- } else if (recStack[neighbor]) {
- return true; // 检测到环
- }
- }
-
- // 从递归栈中移除当前顶点
- recStack[vertex] = false;
-
- // 将当前顶点加入结果栈
- stack.push(vertex);
-
- return false; // 没有检测到环
- }
- }
复制代码
- 最小生成树(Minimum Spanning Tree, MST)
- 定义:毗连图中所有顶点的边的子集,使得这些边构成的树的总权重最小
- 应用:网络计划、聚类分析、近似算法
- 算法:
- Prim算法:从一个顶点开始,每次选择与已选顶点相连的最小权重边
- Kruskal算法:按权重排序所有边,依次选择不构成环的边
- 实现:
- import java.util.*;
- class Edge implements Comparable<Edge> {
- int source;
- int destination;
- int weight;
-
- Edge(int source, int destination, int weight) {
- this.source = source;
- this.destination = destination;
- this.weight = weight;
- }
-
- @Override
- public int compareTo(Edge other) {
- return Integer.compare(this.weight, other.weight);
- }
- }
- public class MinimumSpanningTree {
- // Prim算法
- public static List<Edge> prim(int[][] graph, int vertices) {
- List<Edge> result = new ArrayList<>();
- boolean[] visited = new boolean[vertices];
- int[] key = new int[vertices];
- int[] parent = new int[vertices];
-
- // 初始化key数组为无穷大
- Arrays.fill(key, Integer.MAX_VALUE);
-
- // 选择第一个顶点作为起始点
- key[0] = 0;
- parent[0] = -1;
-
- for (int count = 0; count < vertices - 1; count++) {
- // 找到未访问顶点中key值最小的
- int u = minKey(key, visited, vertices);
-
- // 标记为已访问
- visited[u] = true;
-
- // 更新邻接顶点的key值
- for (int v = 0; v < vertices; v++) {
- if (graph[u][v] != 0 && !visited[v] && graph[u][v] < key[v]) {
- parent[v] = u;
- key[v] = graph[u][v];
- }
- }
- }
-
- // 构建结果
- for (int i = 1; i < vertices; i++) {
- result.add(new Edge(parent[i], i, graph[i][parent[i]]));
- }
-
- return result;
- }
-
- private static int minKey(int[] key, boolean[] visited, int vertices) {
- int min = Integer.MAX_VALUE;
- int minIndex = -1;
-
- for (int v = 0; v < vertices; v++) {
- if (!visited[v] && key[v] < min) {
- min = key[v];
- minIndex = v;
- }
- }
-
- return minIndex;
- }
-
- // Kruskal算法
- public static List<Edge> kruskal(List<Edge> edges, int vertices) {
- List<Edge> result = new ArrayList<>();
-
- // 按权重排序边
- Collections.sort(edges);
-
- // 创建并查集
- int[] parent = new int[vertices];
- for (int i = 0; i < vertices; i++) {
- parent[i] = i;
- }
-
- int i = 0;
- int count = 0;
-
- // 依次选择不构成环的边
- while (count < vertices - 1 && i < edges.size()) {
- Edge edge = edges.get(i++);
- int x = find(parent, edge.source);
- int y = find(parent, edge.destination);
-
- if (x != y) {
- result.add(edge);
- union(parent, x, y);
- count++;
- }
- }
-
- return result;
- }
-
- // 并查集的查找操作
- private static int find(int[] parent, int i) {
- if (parent[i] == i) {
- return i;
- }
- return find(parent, parent[i]);
- }
-
- // 并查集的合并操作
- private static void union(int[] parent, int x, int y) {
- int xSet = find(parent, x);
- int ySet = find(parent, y);
- parent[xSet] = ySet;
- }
- }
复制代码
- 强连通分量(Strongly Connected Components, SCC)
- 定义:有向图中的一组顶点,使得这组顶点中的任意两个顶点之间都存在双向路径
- 应用:交际网络分析、编译器优化、依赖分析
- 算法:Kosaraju算法、Tarjan算法
- 实现:
- import java.util.*;
- public class StronglyConnectedComponents {
- // Kosaraju算法
- public static List<List<Integer>> kosaraju(List<List<Integer>> adjList, int vertices) {
- List<List<Integer>> result = new ArrayList<>();
- boolean[] visited = new boolean[vertices];
- Stack<Integer> stack = new Stack<>();
-
- // 第一次DFS,将顶点按完成时间入栈
- for (int i = 0; i < vertices; i++) {
- if (!visited[i]) {
- dfsFirstPass(adjList, i, visited, stack);
- }
- }
-
- // 构建图的转置
- List<List<Integer>> transpose = transposeGraph(adjList, vertices);
-
- // 重置访问标记
- Arrays.fill(visited, false);
-
- // 第二次DFS,按栈中顺序访问顶点
- while (!stack.isEmpty()) {
- int vertex = stack.pop();
- if (!visited[vertex]) {
- List<Integer> component = new ArrayList<>();
- dfsSecondPass(transpose, vertex, visited, component);
- result.add(component);
- }
- }
-
- return result;
- }
-
- private static void dfsFirstPass(List<List<Integer>> adjList, int vertex,
- boolean[] visited, Stack<Integer> stack) {
- visited[vertex] = true;
-
- for (int neighbor : adjList.get(vertex)) {
- if (!visited[neighbor]) {
- dfsFirstPass(adjList, neighbor, visited, stack);
- }
- }
-
- // 当前顶点的所有邻接顶点都已访问完毕,将其入栈
- stack.push(vertex);
- }
-
- private static void dfsSecondPass(List<List<Integer>> adjList, int vertex,
- boolean[] visited, List<Integer> component) {
- visited[vertex] = true;
- component.add(vertex);
-
- for (int neighbor : adjList.get(vertex)) {
- if (!visited[neighbor]) {
- dfsSecondPass(adjList, neighbor, visited, component);
- }
- }
- }
-
- private static List<List<Integer>> transposeGraph(List<List<Integer>> adjList, int vertices) {
- List<List<Integer>> transpose = new ArrayList<>();
- for (int i = 0; i < vertices; i++) {
- transpose.add(new ArrayList<>());
- }
-
- for (int i = 0; i < vertices; i++) {
- for (int neighbor : adjList.get(i)) {
- transpose.get(neighbor).add(i);
- }
- }
-
- return transpose;
- }
- }
复制代码
3.2.6 图的应用场景
- 交际网络
- 交通网络
- 计算机网络
- 知识图谱
- 游戏开发
- 生物信息学
- 蛋白质相互作用网络
- 基因调控网络
- 代谢通路分析
- 进化树构建
- 数据挖掘
- 编译器计划
3.2.7 图的优缺点
- 优点:
- 可以或许表示复杂的关系和依赖
- 支持多种高效的算法
- 适用于各种实际应用场景
- 可以表示有向和无向关系
- 可以表示带权和不带权的关系
- 缺点:
- 空间复杂度较高
- 某些算法的时间复杂度较高
- 实现和维护相对复杂
- 不适合表示层次结构(树更适合)
- 某些操作(如查找特定边)可能服从较低
3.3 堆(Heap)
3.3.1 基本概念
- 通俗明确:
- 堆就像是一个特殊的队列,但每次只能取出最大或最小的元素
- 想象一个按优先级排序的任务列表:最重要的任务总是在最前面
- 或者想象一个按分数排序的学生效果单:最高分的学生总是在最上面
- 最大堆就像是一个"谁最大谁先出"的队列
- 最小堆就像是一个"谁最小谁先出"的队列
- 定义:堆是一种特殊的完全二叉树,满意堆属性
- 完全二叉树:除了最后一层外,其他层都是满的,且最后一层的节点都靠左分列
- 堆属性:
- 最大堆:父节点的值总是大于或等于其子节点的值
- 最小堆:父节点的值总是小于或等于其子节点的值
- 特点:
- 堆的根节点总是最大(最大堆)或最小(最小堆)的元素
- 堆的高度为O(log n),其中n是节点数量
- 堆的插入和删除操作的时间复杂度为O(log n)
- 堆可以用数组表示,不必要额外的指针
- 堆的范例:
- 最大堆(Max Heap):父节点的值大于或等于子节点的值
- 最小堆(Min Heap):父节点的值小于或等于子节点的值
- 二叉堆(Binary Heap):每个节点最多有两个子节点
- 斐波那契堆(Fibonacci Heap):一种更高效的堆实现,支持O(1)的插入操作
- 二项堆(Binomial Heap):由多个二项树组成的堆
- 堆的基本操作:
- 插入(Insert):将新元素添加到堆的末尾,然后向上调整(上浮)
- 删除最大/最小元素(Extract-Max/Min):删除根节点,用最后一个元素更换,然后向下调整(下沉)
- 获取最大/最小元素(Find-Max/Min):返回根节点的值,不删除
- 堆化(Heapify):将一个数组转换为堆
- 归并(Merge):归并两个堆(某些堆范例支持)
3.3.2 最大堆实现
3.3.3 最小堆实现
3.3.4 堆的应用场景
- 优先队列(Priority Queue)
- 任务调度:按优先级处理任务
- 变乱处理:按时间顺序处理变乱
- 模仿体系:按时间顺序模仿变乱
- 堆排序(Heap Sort)
- 原地排序算法,不必要额外的空间
- 时间复杂度稳固在O(n log n)
- 适合大数据量的排序
- 图算法
- Dijkstra最短路径算法:使用优先队列选择距离最小的顶点
- Prim最小生成树算法:使用优先队列选择权重最小的边
- A*搜索算法:使用优先队列选择启发式值最小的节点
- 数据流处理
- 及时数据流中的中位数计算
- 滑动窗口中的最大值/最小值计算
- 数据流中的Top-K元素计算
- 归并K个有序序列
- 使用最小堆归并多个有序序列
- 时间复杂度为O(n log k),其中n是所有序列的总长度,k是序列的数量
- 定时器实现
- 操作体系中的定时器实现
- 游戏引擎中的变乱调度
- 网络协议中的超时处理
- 缓存更换策略
- LRU(最近最少使用)缓存
- LFU(最不常常使用)缓存
- 基于优先级的缓存更换
- 资源分配
3.3.5 堆的优缺点
- 优点:
- 插入和删除最大/最小元素的时间复杂度为O(log n)
- 获取最大/最小元素的时间复杂度为O(1)
- 可以用数组实现,空间服从高
- 支持高效的堆排序算法
- 适合实现优先队列
- 缺点:
- 不支持随机访问,只能访问最大/最小元素
- 不支持高效的查找操作,查找任意元素必要O(n)时间
- 不支持高效的归并操作(某些特殊堆范例除外)
- 对于频繁更新的数据,维护堆属性可能带来额外开销
3.3.6 堆与其他数据结构的比较
- 堆 vs 有序数组
- 堆的插入和删除操作更快(O(log n) vs O(n))
- 有序数组的查找操作更快(O(log n) vs O(n))
- 堆适合动态数据,有序数组适合静态数据
- 堆 vs 二叉搜索树
- 堆只包管根节点是最大/最小,二叉搜索树包管所有节点都满意排序性质
- 堆的插入和删除操作更简单,不必要平衡操作
- 二叉搜索树支持更丰富的操作,如范围查询、前驱/后继查找等
- 堆 vs 优先队列
- 堆是优先队列的一种实现方式
- 优先队列是一种抽象数据范例,定义了接口
- 堆是优先队列的具体实现,提供了高效的操作
- 堆 vs 斐波那契堆
- 斐波那契堆是堆的一种高级实现
- 斐波那契堆支持O(1)的插入操作和O(log n)的归并操作
- 斐波那契堆的实现更复杂,实际应用中较少使用
3.3.7 堆的变种
- 二项堆(Binomial Heap)
- 由多个二项树组成的堆
- 支持O(log n)的归并操作
- 适合必要频繁归并的场景
- 斐波那契堆(Fibonacci Heap)
- 一种更高效的堆实现
- 支持O(1)的插入操作和O(log n)的归并操作
- 实现复杂,实际应用中较少使用
- 配对堆(Pairing Heap)
- 一种简单的堆实现
- 理论上时间复杂度不如斐波那契堆,但实际性能通常更好
- 实现简单,适合讲授和简单应用
- 左偏堆(Leftist Heap)
- 一种支持高效归并的堆
- 通过维护"左偏"性质来包管归并操作的服从
- 适合必要频繁归并的场景
- 斜堆(Skew Heap)
- 左偏堆的一种简化版本
- 不必要额外的平衡信息
- 归并操作更简单,但理论上的时间复杂度不如左偏堆
3.4 散列表(Hash Table)
3.4.1 基本概念
- 通俗明确:
- 散列表就像是一个有编号的储物柜体系:每个物品都有一个唯一的编号(哈希值),可以直接找到对应的柜子
- 或者想象一个图书馆的索书体系:每本书都有一个索书号,可以直接找到书的位置
- 散列表就是一种"直接寻址"的数据结构,通过计算得到一个位置,然后直接访问该位置
- 理想环境下,查找、插入和删除操作的时间复杂度都是O(1)
- 定义:散列表是一种根据键(Key)直接访问内存存储位置的数据结构
- 通过哈希函数(Hash Function)将键映射到数组中的索引位置
- 支持快速的插入、删除和查找操作
- 是一种空间换时间的数据结构
- 焦点组件:
- 哈希函数(Hash Function):将键映射到数组索引的函数
- 哈希值(Hash Value):哈希函数的输出效果
- 桶(Bucket):存储键值对的数组元素
- 冲突(Collision):差别的键映射到相同的哈希值
- 冲突办理策略(Collision Resolution):处理冲突的方法
- 负载因子(Load Factor):已使用桶数与总桶数的比值
- 扩容(Resizing):当负载因子超过阈值时,增加桶的数量
- 哈希函数的要求:
- 一致性:相同的键总是产生相同的哈希值
- 均匀性:哈希值应该均匀分布在可能的范围内
- 高效性:计算哈希值的时间应该很短
- 最小冲突:尽量减少差别键产生相同哈希值的环境
- 常见的哈希函数:
- 除留余数法:h(k) = k % m,其中m是桶的数量
- 乘法哈希:h(k) = floor(m * (k * A mod 1)),其中A是一个常数
- 全域哈希:从一族哈希函数中随机选择一个
- 一致性哈希:用于分布式体系中的数据分布
3.4.2 冲突处理策略
- 开放寻址法(Open Addressing):
- 当发生冲突时,探求下一个空闲的桶
- 线性探测(Linear Probing):依次查抄下一个位置
- 二次探测(Quadratic Probing):按照二次函数查抄位置
- 双重哈希(Double Hashing):使用第二个哈希函数计算步长
- 优点:不必要额外的空间,适合数据量较小的环境
- 缺点:轻易产生聚集现象,影响性能
- 链地址法(Chaining):
- 每个桶存储一个链表,冲突的元素添加到链表中
- 优点:简单,适合数据量较大的环境
- 缺点:必要额外的空间存储链表,最坏环境下可能退化为链表
- 再哈希法(Rehashing):
- 当发生冲突时,使用另一个哈希函数
- 优点:可以减少冲突
- 缺点:必要多个哈希函数,计算开销大
- 公共溢出区法(Overflow Area):
- 为冲突的元素分配一个单独的溢出区
- 优点:实现简单
- 缺点:溢出区可能很快被填满
3.4.3 实现示例
- public class HashTable<K, V> {
- private class Entry<K, V> {
- K key;
- V value;
- Entry<K, V> next;
-
- Entry(K key, V value) {
- this.key = key;
- this.value = value;
- this.next = null;
- }
- }
-
- private Entry<K, V>[] table;
- private int size;
- private static final int DEFAULT_CAPACITY = 16;
- private static final float LOAD_FACTOR = 0.75f;
-
- @SuppressWarnings("unchecked")
- public HashTable() {
- table = new Entry[DEFAULT_CAPACITY];
- size = 0;
- }
-
- private int hash(K key) {
- return Math.abs(key.hashCode() % table.length);
- }
-
- public void put(K key, V value) {
- int index = hash(key);
-
- if (table[index] == null) {
- table[index] = new Entry<>(key, value);
- size++;
- } else {
- Entry<K, V> entry = table[index];
- while (entry != null) {
- if (entry.key.equals(key)) {
- entry.value = value;
- return;
- }
- entry = entry.next;
- }
- Entry<K, V> newEntry = new Entry<>(key, value);
- newEntry.next = table[index];
- table[index] = newEntry;
- size++;
- }
-
- if (size >= table.length * LOAD_FACTOR) {
- resize();
- }
- }
-
- public V get(K key) {
- int index = hash(key);
- Entry<K, V> entry = table[index];
-
- while (entry != null) {
- if (entry.key.equals(key)) {
- return entry.value;
- }
- entry = entry.next;
- }
-
- return null;
- }
-
- public void remove(K key) {
- int index = hash(key);
- Entry<K, V> entry = table[index];
- Entry<K, V> prev = null;
-
- while (entry != null) {
- if (entry.key.equals(key)) {
- if (prev == null) {
- table[index] = entry.next;
- } else {
- prev.next = entry.next;
- }
- size--;
- return;
- }
- prev = entry;
- entry = entry.next;
- }
- }
-
- @SuppressWarnings("unchecked")
- private void resize() {
- Entry<K, V>[] oldTable = table;
- table = new Entry[table.length * 2];
- size = 0;
-
- for (Entry<K, V> entry : oldTable) {
- while (entry != null) {
- put(entry.key, entry.value);
- entry = entry.next;
- }
- }
- }
- }
复制代码 3.4.4 开放寻址法实现示例
3.4.5 散列表的应用场景
- 数据库索引:
- 数据库中的哈希索引
- 内存数据库的快速查找
- 缓存体系
- 编译器实现:
- 符号表:存储变量、函数等标识符
- 关键字查找
- 字符串池
- 网络应用:
- 安全应用:
- 缓存体系:
- 集合实现:
- 图算法:
- 文本处理:
3.4.6 散列表的优缺点
- 优点:
- 平均环境下,查找、插入和删除操作的时间复杂度为O(1)
- 适合必要快速查找的场景
- 可以处理各种范例的键
- 实现简单,使用广泛
- 缺点:
- 最坏环境下,操作的时间复杂度可能退化为O(n)
- 不支持范围查询和有序遍历
- 哈希函数的计划很重要,不好的哈希函数会导致大量冲突
- 必要额外的空间来减少冲突
- 扩容操作开销大
3.4.7 散列表与其他数据结构的比较
- 散列表 vs 二叉搜索树:
- 散列表的平均查找时间更短,但最坏环境更差
- 二叉搜索树支持范围查询和有序遍历
- 散列表的空间使用率可能更低
- 散列表的实现通常更简单
- 散列表 vs 数组:
- 散列表可以使用任意范例的键,数组只能使用整数索引
- 散列表的空间使用率通常低于数组
- 数组的访问时间是固定的O(1),散列表在冲突环境下会变慢
- 数组支持范围查询和有序遍历,散列表不支持
- 散列表 vs 链表:
- 散列表的查找时间远快于链表
- 链表支持有序遍历,散列表不支持
- 链表的内存使用更灵活,散列表必要预分配空间
- 链表的插入和删除操作更简单,不必要处理冲突
- 散列表 vs 跳表:
- 散列表的平均查找时间更短,但最坏环境更差
- 跳表支持范围查询和有序遍历
- 跳表的空间复杂度通常高于散列表
- 跳表的实现更复杂,但理论性能更稳固
3.4.8 散列表的变种
- 完美散列(Perfect Hashing):
- 一种没有冲突的散列技能
- 适用于静态数据集
- 必要额外的空间来克制冲突
- 重要用于数据库和编译器
- 布隆过滤器(Bloom Filter):
- 一种概率性数据结构,用于判定元素是否在集合中
- 可能有假阳性,但没有假阴性
- 空间服从高,适合大数据集
- 重要用于缓存穿透防护、网络爬虫等
- 一致性散列(Consistent Hashing):
- 一种特殊的散列技能,用于分布式体系
- 当节点数量厘革时,只有少量数据必要重新分配
- 广泛应用于分布式缓存、负载平衡等
- 比方:Memcached、Redis集群
- 可扩展散列(Extendible Hashing):
- 一种动态散列技能,支持数据增长
- 通过目次结构实现动态扩容
- 适合数据库索引
- 空间使用率高,但实现复杂
- 线性散列(Linear Hashing):
- 一种增量散列技能,支持数据增长
- 不必要一次性扩容,而是逐步扩容
- 适合数据库索引
- 实现相对简单,但可能有性能颠簸
4. 算法复杂度分析
4.1 时间复杂度
4.1.1 通俗明确
- 什么是时间复杂度:
- 时间复杂度是衡量算法实验时间随输入规模增长而厘革的度量
- 简单来说,就是算法运行必要多少"步骤"
- 比方:查找一个数组中的元素,如果数组长度为n,最坏环境下必要n步
- 为什么必要分析时间复杂度:
- 资助选择最符合的算法
- 预测算法在大规模数据上的性能
- 比较差别算法的服从
- 优化步伐性能
- 时间复杂度的表示:
- 使用大O符号(O)表示
- 忽略常数项和低阶项
- 只关注增长最快的项
- 比方:3n² + 2n + 1 表示为 O(n²)
4.1.2 常见复杂度
- O(1):常数时间
- 算法的实验时间与输入规模无关
- 比方:访问数组元素、哈希表查找
- 特点:最理想的时间复杂度,但很少见
- O(log n):对数时间
- 算法的实验时间随输入规模呈对数增长
- 比方:二分查找、平衡树的查找
- 特点:非常高效,输入规模翻倍,实验时间只增加一个常数
- O(n):线性时间
- 算法的实验时间与输入规模成正比
- 比方:遍历数组、线性查找
- 特点:服从尚可,输入规模翻倍,实验时间也翻倍
- O(n log n):线性对数时间
- 算法的实验时间随输入规模呈线性对数增长
- 比方:快速排序、归并排序、堆排序
- 特点:许多高效排序算法的时间复杂度
- O(n²):平方时间
- 算法的实验时间随输入规模的平方增长
- 比方:冒泡排序、插入排序、选择排序
- 特点:服从较低,输入规模翻倍,实验时间增加4倍
- O(2ⁿ):指数时间
- 算法的实验时间随输入规模呈指数增长
- 比方:递归斐波那契数列、旅行商问题的暴力解法
- 特点:服从极低,输入规模增加1,实验时间翻倍
- O(n!):阶乘时间
- 算法的实验时间随输入规模呈阶乘增长
- 比方:旅行商问题的暴力解法、分列组合问题
- 特点:服从最低,输入规模增加1,实验时间增加n倍
- 其他常见复杂度:
- O(√n):平方根时间
- O(n³):立方时间
- O(nᵏ):多项式时间,k为常数
- O(n log log n):超线性时间
4.1.3 分析方法
- 最坏环境分析:
- 分析算法在最坏环境下的时间复杂度
- 比方:快速排序的最坏环境是O(n²)
- 优点:提供性能包管
- 缺点:可能过于灰心
- 平均环境分析:
- 分析算法在平均环境下的时间复杂度
- 必要假设输入分布
- 比方:快速排序的平均环境是O(n log n)
- 优点:更靠近实际性能
- 缺点:分析复杂,必要概率知识
- 最好环境分析:
- 分析算法在最好环境下的时间复杂度
- 比方:冒泡排序的最好环境是O(n)
- 优点:相识算法的潜力
- 缺点:实际中很少碰到
- 渐进分析:
- 分析算法在输入规模趋近无穷大时的举动
- 忽略常数项和低阶项
- 使用大O、大Ω、大Θ符号
- 优点:简化分析,关注本质
- 缺点:可能忽略小规模输入的特性
- 递归分析:
- 分析递归算法的时间复杂度
- 使用递归树或主定理
- 比方:归并排序的递归分析
- 优点:体系化分析递归算法
- 缺点:某些递归难以分析
- 摊还分析:
- 分析一系列操作的平均时间复杂度
- 比方:动态数组的扩容操作
- 优点:更准确地反映实际性能
- 缺点:分析复杂
4.1.4 常见算法的时间复杂度
- 排序算法:
- 冒泡排序:O(n²)
- 选择排序:O(n²)
- 插入排序:O(n²),最好环境O(n)
- 希尔排序:O(n log² n)
- 归并排序:O(n log n)
- 快速排序:平均O(n log n),最坏O(n²)
- 堆排序:O(n log n)
- 计数排序:O(n + k),k为元素范围
- 桶排序:O(n + n²/k),k为桶数
- 基数排序:O(d(n + k)),d为位数,k为基数
- 查找算法:
- 线性查找:O(n)
- 二分查找:O(log n)
- 哈希查找:平均O(1),最坏O(n)
- 二叉搜索树查找:平均O(log n),最坏O(n)
- 平衡树查找:O(log n)
- 图算法:
- 深度优先搜索:O(V + E)
- 广度优先搜索:O(V + E)
- Dijkstra最短路径:O(V²)或O(E log V)
- Floyd-Warshall:O(V³)
- Prim最小生成树:O(V²)或O(E log V)
- Kruskal最小生成树:O(E log E)
- 拓扑排序:O(V + E)
- 强连通分量:O(V + E)
- 字符串算法:
- 质朴字符串匹配:O(mn)
- KMP算法:O(m + n)
- Rabin-Karp算法:平均O(m + n),最坏O(mn)
- Boyer-Moore算法:平均O(n/m),最坏O(mn)
- 动态规划:
- 背包问题:O(nW),n为物品数,W为容量
- 最长公共子序列:O(mn),m和n为字符串长度
- 矩阵链乘法:O(n³),n为矩阵数
- 编辑距离:O(mn),m和n为字符串长度
- 其他算法:
- 最大子数组和:O(n)
- 归并K个有序链表:O(n log k),n为总元素数,k为链表数
- 中位数查找:O(n)
- 最近点对:O(n log n)
4.2 空间复杂度
4.2.1 通俗明确
- 什么是空间复杂度:
- 空间复杂度是衡量算法额外空间使用随输入规模增长而厘革的度量
- 简单来说,就是算法必要多少"额外内存"
- 比方:创建一个长度为n的数组,空间复杂度为O(n)
- 为什么必要分析空间复杂度:
- 资助选择最符合的算法
- 预测算法在内存受限环境中的体现
- 比较差别算法的内存使用服从
- 优化步伐内存使用
- 空间复杂度的表示:
- 使用大O符号(O)表示
- 忽略常数项和低阶项
- 只关注增长最快的项
- 比方:n + 2 表示为 O(n)
4.2.2 影响因素
- 输入空间:
- 算法输入占用的空间
- 通常不计入空间复杂度
- 比方:输入数组的长度
- 辅助空间:
- 算法实验过程中额外使用的空间
- 计入空间复杂度
- 比方:临时变量、递归调用栈
- 输出空间:
- 算法输出占用的空间
- 通常不计入空间复杂度
- 比方:返回数组的长度
- 递归深度:
- 递归算法调用栈的深度
- 计入空间复杂度
- 比方:递归斐波那契数列的空间复杂度为O(n)
- 数据结构选择:
- 差别数据结构占用的空间差别
- 影响空间复杂度
- 比方:链表vs数组,哈希表vs二叉搜索树
4.2.3 常见空间复杂度
- O(1):常数空间
- 算法的额外空间使用与输入规模无关
- 比方:原地排序算法(冒泡排序、选择排序)
- 特点:最理想的空间复杂度,但很少见
- O(log n):对数空间
- 算法的额外空间使用随输入规模呈对数增长
- 比方:递归二分查找、平衡树的递归遍历
- 特点:空间服从高,适合大规模数据
- O(n):线性空间
- 算法的额外空间使用与输入规模成正比
- 比方:归并排序、哈希表
- 特点:空间服从尚可,常见于许多算法
- O(n²):平方空间
- 算法的额外空间使用随输入规模的平方增长
- 比方:邻接矩阵表示图、动态规划表格
- 特点:空间服从较低,输入规模翻倍,空间使用增加4倍
- O(2ⁿ):指数空间
- 算法的额外空间使用随输入规模呈指数增长
- 比方:递归斐波那契数列的调用栈
- 特点:空间服从极低,输入规模增加1,空间使用翻倍
- 其他常见空间复杂度:
- O(√n):平方根空间
- O(n log n):线性对数空间
- O(n³):立方空间
4.2.4 常见算法的空间复杂度
- 排序算法:
- 冒泡排序:O(1),原地排序
- 选择排序:O(1),原地排序
- 插入排序:O(1),原地排序
- 希尔排序:O(1),原地排序
- 归并排序:O(n),必要额外数组
- 快速排序:平均O(log n),最坏O(n),递归调用栈
- 堆排序:O(1),原地排序
- 计数排序:O(n + k),k为元素范围
- 桶排序:O(n + k),k为桶数
- 基数排序:O(n + k),k为基数
- 查找算法:
- 线性查找:O(1),不必要额外空间
- 二分查找:迭代O(1),递归O(log n)
- 哈希查找:O(n),哈希表空间
- 二叉搜索树查找:O(n),树节点空间
- 平衡树查找:O(n),树节点空间
- 图算法:
- 深度优先搜索:O(V),递归调用栈或显式栈
- 广度优先搜索:O(V),队列空间
- Dijkstra最短路径:O(V),距离数组和访问标记数组
- Floyd-Warshall:O(V²),距离矩阵
- Prim最小生成树:O(V),访问标记数组和键值数组
- Kruskal最小生成树:O(E),边集合和并查集
- 拓扑排序:O(V),访问标记数组和效果数组
- 强连通分量:O(V + E),访问标记数组和效果数组
- 字符串算法:
- 质朴字符串匹配:O(1),不必要额外空间
- KMP算法:O(m),部门匹配表
- Rabin-Karp算法:O(1),不必要额外空间
- Boyer-Moore算法:O(k),k为字符集巨细
- 动态规划:
- 背包问题:O(W),W为容量
- 最长公共子序列:O(mn),m和n为字符串长度
- 矩阵链乘法:O(n²),n为矩阵数
- 编辑距离:O(mn),m和n为字符串长度
- 其他算法:
- 最大子数组和:O(1),只必要几个变量
- 归并K个有序链表:O(k),k为链表数,优先队列
- 中位数查找:O(1),原地算法
- 最近点对:O(n),递归调用栈
4.3 实际应用中的思量因素
4.3.1 时间与空间的权衡
- 时间换空间:
- 使用更多空间来减少时间
- 比方:哈希表vs二叉搜索树
- 适用场景:时间敏感,空间充足
- 空间换时间:
- 使用更多时间来减少空间
- 比方:原地排序vs归并排序
- 适用场景:空间受限,时间要求不严格
- 平衡策略:
- 在时间和空间之间找到平衡点
- 比方:快速排序,平均环境下时间和空间都较好
- 适用场景:一般应用场景
4.3.2 实际性能与理论复杂度
- 常数因子:
- 理论复杂度忽略常数因子,但实际中很重要
- 比方:O(n)算法可能比O(n log n)算法慢
- 思量因素:实现细节、硬件特性
- 缓存效应:
- 当代计算机的缓存对实际性能有庞大影响
- 比方:顺序访问比随机访问快
- 思量因素:内存访问模式、缓存巨细
- 并行性:
- 并行算法可能改变复杂度分析
- 比方:并行归并排序
- 思量因素:处理器数量、同步开销
- 输入特性:
- 输入数据的特性影响实际性能
- 比方:快速排序在有序数据上体现差
- 思量因素:数据分布、数据规模
4.3.3 优化策略
- 算法选择:
- 根据问题特性选择最符合的算法
- 比方:小规模数据用插入排序,大规模数据用快速排序
- 策略:分析问题特性,相识算法优缺点
- 数据结构选择:
- 选择符合的数据结构支持算法
- 比方:频繁查找用哈希表,范围查询用二叉搜索树
- 策略:分析操作范例,相识数据结构特性
- 实现优化:
- 优化算法实现细节
- 比方:循环睁开、位运算、内联函数
- 策略:相识编译器优化,关注热点代码
- 预处理:
- 预处理数据以提高后续操作服从
- 比方:排序、建立索引、计算前缀和
- 策略:分析操作模式,权衡预处理成本
- 近似算法:
- 使用近似算法在可担当的时间内得到近似解
- 比方:贪默算法、启发式算法
- 策略:分析精度要求,相识近似算法特性
4.3.4 实际案例分析
- 数据库查询优化:
- 索引选择:B+树vs哈希索引
- 查询筹划:选择最优实验筹划
- 毗连算法:嵌套循环vs哈希毗连
- 思量因素:数据分布、查询模式、体系资源
- 网络算法:
- 路由算法:Dijkstra vs Bellman-Ford
- 流量控制:滑动窗口vs拥塞控制
- 负载平衡:轮询vs一致性哈希
- 思量因素:网络拓扑、流量模式、延长要求
- 图像处理:
- 图像压缩:JPEG vs PNG
- 图像滤波:均值滤波vs中值滤波
- 图像辨认:模板匹配vs特征提取
- 思量因素:图像巨细、精度要求、及时性
- 机器学习:
- 训练算法:梯度下降vs随机梯度下降
- 模型选择:线性模型vs深度神经网络
- 特征工程:特征选择vs特征提取
- 思量因素:数据规模、模型复杂度、计算资源
- 游戏开发:
- 物理模仿:欧拉法vs龙格库塔法
- 碰撞检测:包围盒vs精确碰撞
- 寻路算法:A* vs Dijkstra
- 思量因素:及时性、精度要求、游戏范例
4.4 复杂度分析的进阶主题
4.4.1 平摊分析
- 基本概念:
- 分析一系列操作的平均时间复杂度
- 思量操作之间的相互影响
- 比方:动态数组的扩容操作
- 分析方法:
- 聚合分析:计算n个操作的总时间,然后平均
- 记账方法:为每个操作分配"信用",用于付出将来操作
- 势能方法:定义一个势能函数,分析操尴尬刁难势能的影响
- 应用场景:
- 动态数组:插入操作的平均时间复杂度为O(1)
- 并查集:路径压缩和按秩归并的平均时间复杂度为O(α(n))
- 斐波那契堆:插入操作的平均时间复杂度为O(1)
4.4.2 随机化算法分析
- 基本概念:
- 算法中包含随机选择的步骤
- 分析算法的期望性能
- 比方:随机快速排序
- 分析方法:
- 期望分析:计算算法的期望时间复杂度
- 概率分析:分析算法乐成的概率
- 蒙特卡洛方法:通过随机采样估计性能
- 应用场景:
- 随机快速排序:期望时间复杂度为O(n log n)
- 随机化最小割算法:Karger算法
- 随机化近似算法:随机采样、随机游走
4.4.3 在线算法分析
- 基本概念:
- 算法在不知道将来输入的环境下处理当前输入
- 分析算法的竞争比
- 比方:在线缓存更换策略
- 分析方法:
- 竞争分析:比较在线算法与最优离线算法的性能比
- 随机化竞争分析:分析随机化在线算法的期望竞争比
- 资源加强分析:分析算法在额外资源下的性能
- 应用场景:
- 缓存更换:LRU、FIFO、随机更换
- 在线调度:任务调度、资源分配
- 在线匹配:广告分配、资源分配
4.4.4 参数化复杂度分析
- 基本概念:
- 分析算法在参数化问题上的复杂度
- 参数通常是问题的一个特性,如树宽、顶点覆盖数
- 比方:固定参数可解算法
- 分析方法:
- 参数化归约:将问题归约为参数化问题
- 核化:将问题实例归约为核实例
- 分支定界:分析分支算法的复杂度
- 应用场景:
- 图算法:树宽、顶点覆盖、反馈顶点集
- 字符串算法:编辑距离、最长公共子序列
- 逻辑问题:SAT、3-SAT、CNF-SAT
4.4.5 量子算法复杂度
- 基本概念:
- 分析量子算法的时间复杂度
- 使用量子比特和量子门
- 比方:Shor算法、Grover算法
- 分析方法:
- 量子电路复杂度:分析量子电路的门数
- 查询复杂度:分析算法必要的量子查询次数
- 量子并行性:使用量子叠加态举行并行计算
- 应用场景:
- 整数分解:Shor算法,多项式时间
- 无序搜索:Grover算法,O(√n)查询复杂度
- 量子模仿:模仿量子体系,指数加速
5. 数据结构应用
5.1 数据库体系
5.1.1 索引结构
- B+树索引:
- 特点:多路平衡搜索树,所有数据存储在叶子节点
- 上风:支持范围查询,适合磁盘存储
- 应用:MySQL、PostgreSQL等关系型数据库的主键和辅助索引
- 实现:节点包含多个键值对,叶子节点通过链表毗连
- 哈希索引:
- 特点:基于哈希函数将键映射到存储位置
- 上风:等值查询服从高,靠近O(1)
- 应用:内存数据库、缓存体系、哈希表
- 实现:开放寻址法、链地址法处理冲突
- 位图索引:
- 特点:使用位图表示数据的存在性
- 上风:适合低基数列的查询,空间服从高
- 应用:数据堆栈、OLAP体系、统计分析
- 实现:每个唯一值对应一个位图,位图中1表示存在,0表示不存在
- 全文索引:
- 特点:支持文本内容的暗昧匹配和关键词搜索
- 上风:支持自然语言查询,可处理大规模文本
- 应用:搜索引擎、文档管理体系、内容检索
- 实现:倒排索引、分词技能、相干性排序
- LSM树(Log-Structured Merge Tree):
- 特点:将随机写转换为顺序写,提高写入性能
- 上风:高写入吞吐量,适合写麋集型应用
- 应用:LevelDB、RocksDB、Cassandra
- 实现:内存表(MemTable)和磁盘表(SSTable)的多层结构
- R树:
- 特点:专门用于多维空间数据的索引结构
- 上风:支持范围查询、最近邻查询等空间操作
- 应用:地理信息体系(GIS)、空间数据库
- 实现:将空间对象用最小外接矩形(MBR)表示,构建树结构
5.1.2 查询优化
- 索引选择:
- 原理:根据查询条件和数据分布选择符合的索引
- 方法:统计信息收集、代价估算、索引推荐
- 应用:优化器自动选择或DBA手动指定索引
- 工具:EXPLAIN分析、索引使用统计
- 毗连优化:
- 原理:优化多表毗连的实验顺序和方法
- 方法:嵌套循环毗连、哈希毗连、归并毗连
- 应用:复杂查询、多表关联分析
- 工具:实验计分别析、毗连顺序调整
- 排序优化:
- 原理:优化排序操作的实验方式
- 方法:内存排序、外部排序、索引排序
- 应用:ORDER BY子句、GROUP BY操作
- 工具:排序缓冲区配置、临时表使用
- 缓存策略:
- 原理:使用内存缓存减少磁盘I/O
- 方法:查询缓存、数据页缓存、效果集缓存
- 应用:热点数据访问、重复查询
- 工具:缓存命中率监控、缓存预热
- 并行查询:
- 原理:使用多核或多机并行实验查询
- 方法:数据分区、任务分解、效果归并
- 应用:大规模数据分析、复杂计算
- 工具:并行度设置、资源分配
- 物化视图:
- 原理:预先计算并存储查询效果
- 方法:增量维护、定时刷新、按需更新
- 应用:复杂报表、统计分析、OLAP查询
- 工具:物化视图创建、维护策略设置
5.1.3 事务处理
- ACID特性:
- 原子性(Atomicity):事务是不可分割的工作单位
- 一致性(Consistency):事务实验前后数据库保持一致状态
- 隔离性(Isolation):事务间互不干扰
- 持久性(Durability):事务提交后效果永世保存
- 并发控制:
- 锁机制:共享锁、排他锁、意向锁
- 时间戳:基于时间戳的并发控制
- 多版本并发控制(MVCC):为每个事务创建数据快照
- 乐观并发控制:先实验后验证,冲突时回滚
- 规复机制:
- 日记记录:重做日记、回滚日记
- 查抄点:定期将内存数据写入磁盘
- 崩溃规复:体系崩溃后的数据规复
- 介质规复:磁盘故障后的数据规复
- 分布式事务:
- 两阶段提交(2PC):和谐者和参与者两阶段提交
- 三阶段提交(3PC):增加预提交阶段提高容错性
- 最终一致性:牺牲强一致性换取可用性
- 分布式日记:基于日记的分布式事务
5.2 操作体系
5.2.1 内存管理
- 页表:
- 功能:将假造地址映射到物理地址
- 结构:多级页表、页表项(PTE)
- 操作:地址转换、缺页中断处理
- 优化:TLB(转换后备缓冲区)、大页支持
- 段表:
- 功能:管理步伐的差别段(代码段、数据段等)
- 结构:段形貌符、段选择子
- 操作:段地址转换、段保护查抄
- 应用:步伐隔离、内存保护
- 空闲内存管理:
- 方法:位图、链表、同伴体系
- 操作:内存分配、内存释放、内存碎片整理
- 优化:内存池、对象池、垃圾接纳
- 应用:动态内存分配、内存复用
- 假造内存:
- 原理:将物理内存和磁盘空间结合提供更大的地址空间
- 实现:页面置换算法(LRU、FIFO、Clock)
- 优化:预取、工作集模型、局部性原理
- 应用:大型步伐运行、多进程并发
- 内存映射:
- 功能:将文件映射到内存地址空间
- 方法:mmap体系调用、文件映射
- 上风:减少数据拷贝、共享内存
- 应用:大文件处理、进程间通信
- 内存保护:
- 机制:访问权限控制、地址空隔断离
- 实现:页表权限位、段权限查抄
- 目的:防止步伐越界访问、保护体系安全
- 应用:多用户体系、安全关键体系
5.2.2 进程管理
- 进程调度:
- 算法:先来先服务、短作业优先、时间片轮转、多级反馈队列
- 策略:抢占式调度、非抢占式调度
- 指标:周转时间、等候时间、响应时间
- 实现:调度队列、调度器、上下文切换
- 进程同步:
- 机制:互斥锁、信号量、条件变量、管程
- 问题:死锁、饥饿、优先级反转
- 办理:死锁预防、死锁克制、死锁检测与规复
- 应用:多线程编程、并发控制
- 进程通信:
- 方式:管道、消息队列、共享内存、套接字
- 模型:生产者-消费者、客户端-服务器
- 实现:体系调用、IPC机制
- 应用:分布式体系、微服务架构
- 线程管理:
- 模型:用户级线程、内核级线程、混合模型
- 操作:线程创建、线程终止、线程同步
- 上风:轻量级、共享资源、并发实验
- 应用:多线程应用、并行计算
- 进程状态:
- 状态:停当、运行、壅闭、创建、终止
- 转换:状态转换图、转换条件
- 管理:进程控制块(PCB)、进程表
- 监控:进程状态查看、性能分析
- 及时调度:
- 算法:最早停止时间优先(EDF)、速率单调(RM)
- 特性:可预测性、确定性、时间束缚
- 实现:优先级继承、优先级天花板
- 应用:嵌入式体系、及时控制体系
5.2.3 文件体系
- 文件构造:
- 结构:连续分配、链接分配、索引分配
- 管理:文件控制块、目次项、空闲空间管理
- 操作:文件创建、打开、读写、关闭
- 优化:文件缓存、预读、写缓冲
- 目次结构:
- 范例:单级目次、两级目次、树形目次、无环图目次
- 实现:目次项、硬链接、符号链接
- 操作:目次创建、删除、遍历、搜索
- 应用:文件构造、路径剖析
- 文件保护:
- 机制:访问控制列表、权限位、用户组
- 操作:权限查抄、权限修改
- 安全:文件加密、安全审计
- 应用:多用户体系、安全关键体系
- 日记文件体系:
- 原理:将文件体系操作记录为日记
- 上风:快速规复、一致性包管
- 实现:日记记录、查抄点、回滚
- 应用:高可靠性体系、数据库文件体系
- 分布式文件体系:
- 架构:客户端-服务器、对等网络
- 特性:透明访问、一致性、容错性
- 实现:NFS、CIFS、HDFS
- 应用:云计算、大数据存储
- 文件体系性能:
- 指标:吞吐量、延长、并发度
- 优化:缓存策略、预读、写归并
- 监控:性能计数器、性能分析工具
- 调优:参数调整、硬件升级
5.3 网络体系
5.3.1 路由算法
- 最短路径算法:
- Dijkstra算法:单源最短路径,适用于非负权图
- Bellman-Ford算法:可处理负权边,检测负权环
- Floyd-Warshall算法:所有节点对之间的最短路径
- 应用:路由表构建、网络规划
- 距离向量路由:
- 原理:每个节点维护到其他节点的距离和下一跳
- 算法:RIP(路由信息协议)
- 特点:简单、收敛慢、路由环路
- 应用:小型网络、自治体系内部
- 链路状态路由:
- 原理:每个节点维护整个网络的拓扑信息
- 算法:OSPF(开放最短路径优先)
- 特点:收敛快、开销大、必要更多资源
- 应用:大型网络、自治体系内部
- 路径向量路由:
- 原理:记录到达目的地的完整路径信息
- 算法:BGP(界限网关协议)
- 特点:支持策略路由、防止路由环路
- 应用:自治体系之间、互联网焦点
- QoS路由:
- 原理:思量带宽、延长、丢包率等服务质量因素
- 算法:束缚最短路径、多束缚路由
- 特点:支持差异化服务、资源优化
- 应用:多媒体传输、及时应用
- 多播路由:
- 原理:支持一对多通信
- 算法:DVMRP、PIM、MOSPF
- 特点:带宽服从高、组管理复杂
- 应用:视频会议、内容分发
5.3.2 拥塞控制
- TCP拥塞控制:
- 机制:慢启动、拥塞克制、快重传、快规复
- 算法:TCP Tahoe、TCP Reno、TCP CUBIC
- 参数:拥塞窗口、慢启动阈值、往返时间
- 应用:可靠传输、流量控制
- 自动队列管理:
- 机制:RED(随机早期检测)、WRED(加权RED)
- 原理:在队列满之前自动扬弃或标记数据包
- 上风:克制全局同步、提高链路使用率
- 应用:路由器队列管理、网络拥塞控制
- 显式拥塞通知(ECN):
- 原理:路由器通过标记数据包通知拥塞
- 机制:ECN标记、ECN回显
- 上风:克制数据包扬弃、提高吞吐量
- 应用:低延长应用、数据中心网络
- 流量整形与羁系:
- 方法:令牌桶、漏桶算法
- 目的:控制流量速率、平滑突发流量
- 应用:服务质量包管、带宽管理
- 实现:流量分类、优先级队列
- 分布式拥塞控制:
- 原理:多个节点协同控制网络拥塞
- 方法:分布式算法、反馈机制
- 上风:顺应性强、可扩展性好
- 应用:大规模网络、数据中心
- 跨层拥塞控制:
- 原理:结合应用层和传输层的拥塞控制
- 方法:应用感知的拥塞控制、跨层优化
- 上风:更好的应用性能、资源使用
- 应用:多媒体传输、及时应用
5.3.3 负载平衡
- 服务器负载平衡:
- 方法:轮询、加权轮询、最少毗连、IP哈希
- 实现:硬件负载平衡器、软件负载平衡器
- 特性:健康查抄、会话保持、动态权重
- 应用:Web服务器集群、应用服务器集群
- 全局负载平衡:
- 原理:跨地理位置的负载平衡
- 方法:DNS轮询、地理位置感知、延长感知
- 上风:高可用性、劫难规复、就近访问
- 应用:CDN、环球服务部署
- 应用层负载平衡:
- 方法:HTTP重定向、URL重写、内容路由
- 特性:应用感知、内容感知、会话感知
- 上风:更精细的控制、更好的用户体验
- 应用:Web应用、API网关
- 动态负载平衡:
- 原理:根据及时负载环境动态调整
- 方法:自顺应算法、反馈机制、预测模型
- 上风:资源使用率高、响应速率快
- 应用:云计算、弹性计算
- 一致性哈希:
- 原理:将数据和服务器映射到哈希环上
- 上风:服务器增减时数据迁徙少
- 实现:假造节点、权重调整
- 应用:分布式缓存、分布式存储
- 负载平衡策略:
- 策略:轮询、随机、权重、最少毗连、响应时间
- 选择:根据应用特性、负载特性选择
- 优化:动态调整、自顺应策略
- 监控:负载平衡效果、性能指标
5.4 编译体系
5.4.1 符号表
- 符号表结构:
- 实现:哈希表、二叉搜索树、平衡树
- 操作:插入、查找、删除、更新
- 特性:作用域管理、符号重载、符号隐蔽
- 应用:变量声明、函数定义、范例查抄
- 作用域管理:
- 方法:静态作用域、动态作用域
- 实现:作用域栈、作用域树
- 操作:进入作用域、退出作用域、符号查找
- 应用:变量可见性、定名冲突办理
- 符号表优化:
- 方法:哈希冲突处理、表巨细调整
- 策略:延长创建、符号归并、符号消除
- 目的:减少内存使用、提高查找服从
- 工具:符号表分析、内存分析
- 符号表与范例体系:
- 关系:符号表存储范例信息
- 操作:范例查抄、范例推导、范例转换
- 实现:范例图、范例束缚求解
- 应用:静态范例查抄、范例安全
- 符号表与代码生成:
- 关系:符号表提供代码生成所需信息
- 使用:变量地址分配、函数调用生成
- 优化:符号表与中间表示结合
- 应用:目的代码生成、链接时优化
- 调试信息:
- 内容:行号、变量名、范例信息
- 格式:DWARF、STABS、PDB
- 生成:编译时生成、链接时归并
- 应用:源代码级调试、性能分析
5.4.2 语法分析
- 语法分析器:
- 方法:递归下降、LL分析、LR分析
- 实现:自顶向下、自底向上
- 工具:ANTLR、Bison、Yacc
- 应用:语言剖析、代码分析
- 抽象语法树(AST):
- 结构:树形表示步伐的语法结构
- 节点:表达式、语句、声明
- 操作:遍历、转换、优化
- 应用:代码分析、代码生成
- 语法分析优化:
- 方法:语法分析表压缩、错误规复
- 策略:增量剖析、并行剖析
- 目的:提高剖析服从、减少内存使用
- 工具:语法分析器生成器、性能分析
- 语义分析:
- 内容:范例查抄、作用域分析、语义验证
- 实现:属性文法、语义动作
- 工具:语义分析器、范例查抄器
- 应用:静态分析、代码验证
- 中间表示:
- 范例:三地址代码、SSA、控制流图
- 转换:AST到中间表示、中间表示优化
- 上风:便于优化、目的代码生成
- 应用:编译器优化、代码生成
- 错误处理:
- 方法:错误检测、错误规复、错误报告
- 策略:继续剖析、跳过错误、部门剖析
- 实现:错误处理步伐、错误规复机制
- 应用:语法错误处理、语义错误处理
5.4.3 代码优化
- 局部优化:
- 方法:常量折叠、强度减弱、死代码消除
- 范围:基本块内、函数内
- 实现:数据流分析、控制流分析
- 应用:提高实验服从、减少代码巨细
- 全局优化:
- 方法:内联睁开、循环优化、全局变量优化
- 范围:整个函数、多个函数
- 实现:调用图分析、别名分析
- 应用:提高步伐性能、减少函数调用开销
- 循环优化:
- 方法:循环睁开、循环融合、循环稳固量外提
- 目的:减少循环开销、提高指令级并行性
- 实现:循环嵌套分析、依赖分析
- 应用:科学计算、图像处理
- 数据流分析:
- 方法:到达定义、活跃变量、可用表达式
- 实现:迭代算法、工作列表算法
- 应用:代码优化、步伐分析
- 工具:数据流分析框架、可视化工具
- 寄存器分配:
- 方法:图着色、线性扫描、优先级分配
- 目的:最大化寄存器使用、最小化内存访问
- 实现:活跃区间分析、冲突图构建
- 应用:代码生成、性能优化
- 并行优化:
- 方法:自动并行化、向量化、SIMD优化
- 目的:使用多核、GPU加速
- 实现:依赖分析、并行区域辨认
- 应用:高性能计算、多媒体处理
5.5 人工智能和机器学习
5.5.1 特征工程
- 特征提取:
- 方法:统计特征、时域特征、频域特征
- 技能:主身分分析、独立身分分析、因子分析
- 应用:图像处理、信号处理、文本分析
- 工具:特征提取库、数据处理框架
- 特征选择:
- 方法:过滤法、包装法、嵌入法
- 算法:信息增益、卡方检验、L1正则化
- 目的:减少特征数量、提高模型性能
- 应用:高维数据分析、模型简化
- 特征转换:
- 方法:标准化、归一化、对数变动
- 技能:独热编码、标签编码、分箱
- 目的:处理非线性关系、处理种别特征
- 应用:数据预处理、模型输入准备
- 特征学习:
- 方法:自编码器、受限玻尔兹曼机、生成对抗网络
- 技能:深度学习、表示学习
- 上风:自动发现特征、处理非结构化数据
- 应用:图像辨认、自然语言处理
- 特征存储:
- 结构:特征向量、特征矩阵、特征数据库
- 格式:稀疏矩阵、压缩存储、列式存储
- 优化:特征缓存、特征索引、特征压缩
- 应用:大规模特征存储、特征检索
- 特征版本控制:
- 方法:特征版本管理、特征血缘分析
- 工具:特征存储体系、版本控制体系
- 目的:跟踪特征厘革、包管特征一致性
- 应用:特征工程管理、模型部署
5.5.2 模型存储
- 模型序列化:
- 格式:JSON、XML、二进制、Protocol Buffers
- 方法:pickle、joblib、ONNX
- 内容:模型参数、模型结构、超参数
- 应用:模型保存、模型加载、模型部署
- 模型压缩:
- 方法:权重量化、剪枝、知识蒸馏
- 技能:低秩分解、稀疏化、模型蒸馏
- 目的:减少模型巨细、提高推理速率
- 应用:移动设备部署、边缘计算
- 模型版本控制:
- 体系:MLflow、DVC、ModelDB
- 功能:版本管理、实验跟踪、模型注册
- 上风:可追溯性、可复现性、协作开发
- 应用:模型生命周期管理、团队协作
- 分布式模型存储:
- 架构:参数服务器、AllReduce、Ring AllReduce
- 实现:分布式文件体系、对象存储
- 上风:大规模模型训练、高可用性
- 应用:分布式训练、模型服务
- 模型缓存:
- 策略:内存缓存、磁盘缓存、分布式缓存
- 实现:缓存管理器、缓存更换策略
- 目的:减少加载时间、提高访问速率
- 应用:模型服务、在线推理
- 模型安全:
- 方法:模型加密、访问控制、水印
- 技能:同态加密、安全多方计算
- 目的:保护知识产权、防止模型窃取
- 应用:商业模型部署、隐私保护
5.5.3 推理优化
- 计算图优化:
- 方法:图简化、常量折叠、算子融合
- 技能:静态图优化、动态图优化
- 目的:减少计算量、提高实验服从
- 应用:深度学习框架、模型推理
- 硬件加速:
- 平台:CPU、GPU、TPU、FPGA
- 技能:SIMD、CUDA、OpenCL、TensorRT
- 优化:内存访问模式、计算麋集型操作
- 应用:高性能推理、及时应用
- 批处理优化:
- 方法:动态批处理、静态批处理
- 策略:批巨细选择、批处理调度
- 目的:提高吞吐量、平衡延长
- 应用:在线服务、批量处理
- 量化推理:
- 方法:权重量化、激活量化、动态量化
- 技能:INT8、FP16、混合精度
- 上风:减少内存使用、提高计算速率
- 应用:移动设备、边缘设备
- 模型分割:
- 方法:模型并行、流水线并行、数据并行
- 技能:模型切分、设备分配、通信优化
- 目的:处理大模型、提高并行度
- 应用:分布式推理、大模型部署
- 延长优化:
- 方法:提前计算、缓存效果、异步处理
- 技能:哀求归并、优先级调度
- 目的:减少响应时间、提高用户体验
- 应用:及时应用、交互式服务
5.6 游戏开发
5.6.1 游戏状态管理
- 状态机:
- 实现:有限状态机、层次状态机、举动树
- 结构:状态、转换、变乱、动作
- 应用:角色AI、游戏流程控制、UI状态
- 优化:状态缓存、状态预测、状态压缩
- 实体组件体系(ECS):
- 架构:实体、组件、体系
- 上风:高内聚低耦合、数据导向计划
- 实现:组件存储、体系调度、实体管理
- 应用:游戏对象管理、物理模仿、渲染体系
- 对象池:
- 原理:预先创建对象,重用而非创建销毁
- 实现:对象池管理器、对象分配策略
- 上风:减少内存分配、减少GC压力
- 应用:粒子体系、子弹、殊效
- 变乱体系:
- 实现:观察者模式、发布-订阅模式
- 结构:变乱、监听器、分发器
- 上风:松耦合、可扩展性
- 应用:游戏逻辑、UI交互、网络同步
- 存档体系:
- 方法:序列化、反序列化、增量保存
- 格式:二进制、JSON、XML
- 功能:游戏状态保存、加载、查抄点
- 应用:游戏进度保存、多人游戏状态同步
- 场景管理:
- 方法:场景图、空间分区、LOD
- 实现:场景加载、卸载、切换
- 优化:异步加载、资源预加载、场景流式加载
- 应用:开放天下游戏、大型场景渲染
5.6.2 物理模仿
- 碰撞检测:
- 方法:包围盒、空间分区、连续碰撞检测
- 算法:分离轴定理、GJK算法、SAP
- 优化:空间哈希、四叉树、八叉树
- 应用:物理模仿、游戏逻辑、交互检测
- 刚体动力学:
- 原理:牛顿活动定律、动量守恒、角动量守恒
- 实现:位置积分、速率积分、束缚求解
- 方法:显式积分、隐式积分、半隐式积分
- 应用:物理模仿、游戏物理、车辆模仿
- 粒子体系:
- 结构:粒子、发射器、影响器
- 属性:位置、速率、生命周期、颜色
- 优化:GPU加速、空间分区、LOD
- 应用:殊效、流体模仿、烟雾模仿
- 布料模仿:
- 方法:质点-弹簧模型、位置动力学、有限元
- 实现:束缚求解、碰撞处理、风力影响
- 优化:GPU加速、简化模型、LOD
- 应用:角色服装、旗帜、窗帘
- 流体模仿:
- 方法:欧拉法、拉格朗日法、混合方法
- 实现:网格分别、压力图解、界限处理
- 优化:GPU加速、简化模型、自顺应网格
- 应用:水、烟雾、火焰
- 束缚体系:
- 范例:点束缚、距离束缚、铰链束缚
- 方法:位置修正、速率修正、束缚求解
- 实现:雅可比矩阵、束缚力计算
- 应用:关节体系、绳索、链条
5.6.3 寻路算法
- A*算法:
- 原理:启发式搜索、代价函数、开放列表/关闭列表
- 实现:优先队列、路径重修、启发函数
- 优化:双向搜索、跳点搜索、分层搜索
- 应用:游戏AI、导航体系、路径规划
- 导航网格(NavMesh):
- 结构:多边形网格、节点、边
- 生成:自动生成、手动编辑、动态更新
- 优化:网格简化、LOD、动态避障
- 应用:3D游戏、复杂地形、动态环境
- 势场法:
- 原理:目的吸引、障碍排挤、合力计算
- 实现:势场生成、力计算、路径平滑
- 上风:及时性好、顺应动态环境
- 应用:群体举动、及时避障、动态寻路
- 分层寻路:
- 方法:抽象层、具体层、层间毗连
- 实现:抽象图构建、路径规划、路径细化
- 上风:处理大规模地图、提高寻路服从
- 应用:开放天下游戏、大规模地图
- 动态寻路:
- 方法:及时更新、局部重规划、预测
- 实现:动态障碍处理、路径调整、平滑处理
- 上风:顺应环境厘革、处理移动障碍
- 应用:动态环境、多智能体体系
- 群体寻路:
- 方法:流场、社会力模型、基于规则
- 实现:群体举动、碰撞克制、路径和谐
- 上风:自然群体举动、高效处理大量单位
- 应用:群体模仿、战役游戏、交通模仿
5.7 安全体系
5.7.1 加密算法
- 对称加密:
- 算法:AES、DES、ChaCha20
- 模式:ECB、CBC、CTR、GCM
- 实现:硬件加速、软件实现
- 应用:数据加密、安全通信
- 非对称加密:
- 算法:RSA、ECC、DH
- 操作:密钥生成、加密、解密、签名
- 安全:密钥长度、随机数生成
- 应用:密钥互换、数字签名、身份认证
- 哈希函数:
- 算法:SHA-256、SHA-3、Blake2
- 特性:单向性、抗碰撞性、雪崩效应
- 应用:数据完整性、暗码存储、数字签名
- 安全:长度扩展攻击、彩虹表攻击
- 随机数生成:
- 方法:真随机、伪随机、暗码学安全随机
- 实现:硬件随机数生成器、软件随机数生成器
- 应用:密钥生成、初始化向量、挑战-响应
- 安全:熵源质量、种子管理
- 密钥管理:
- 方法:密钥生成、存储、分发、更新
- 技能:密钥派生、密钥包装、密钥分割
- 安全:密钥保护、密钥生命周期
- 应用:安全通信、数据保护
- 暗码协议:
- 协议:TLS、SSH、IPsec
- 阶段:握手、密钥互换、数据传输
- 安全:前向安全性、完美前向安全性
- 应用:安全通信、身份认证
5.7.2 访问控制
- 访问控制模型:
- 范例:DAC、MAC、RBAC、ABAC
- 实现:访问控制列表、本领列表、策略引擎
- 操作:授权、撤销、继承、委托
- 应用:操作体系、数据库、Web应用
- 身份认证:
- 方法:暗码、生物特征、多因素认证
- 协议:OAuth、OpenID Connect、SAML
- 安全:暗码策略、防暴力破解、会话管理
- 应用:用户登录、API认证、单点登录
- 权限管理:
- 结构:用户、角色、权限、资源
- 操作:权限分配、权限查抄、权限继承
- 实现:权限矩阵、权限树、策略评估
- 应用:体系安全、数据保护
- 审计日记:
- 内容:用户活动、体系变乱、安全变乱
- 存储:日记文件、数据库、SIEM体系
- 操作:日记收集、分析、保留
- 应用:安全监控、合规性、变乱调查
- 安全策略:
- 范例:暗码策略、访问策略、数据策略
- 实现:策略定义、策略实验、策略评估
- 管理:策略制定、策略更新、策略合规
- 应用:构造安全、合规性管理
- 零信任架构:
- 原则:永不信任,始终验证
- 组件:身份验证、设备验证、网络分段
- 实现:微隔离、持续监控、自顺应访问
- 应用:当代安全架构、云安全
5.7.3 安全存储
- 安全密钥存储:
- 方法:硬件安全模块、密钥管理体系、云密钥管理
- 技能:密钥加密、密钥分割、安全 enclave
- 安全:防窜改、防提取、安全销毁
- 应用:密钥保护、证书管理
- 安全数据存储:
- 方法:透明加密、字段级加密、同态加密
- 技能:数据分类、数据掩码、数据脱敏
- 安全:访问控制、加密保护、安全删除
- 应用:敏感数据保护、合规性存储
- 安全通信存储:
- 方法:端到端加密、传输层安全、安全通道
- 技能:证书管理、密钥互换、会话管理
- 安全:中间人攻击防护、重放攻击防护
- 应用:安全通信、数据传输
- 安全配置存储:
- 方法:配置加密、安全配置管理、配置版本控制
- 技能:环境变量、密钥管理、配置服务
- 安全:访问控制、审计跟踪、变动管理
- 应用:应用配置、体系配置
- 安整日记存储:
- 方法:日记加密、安整日记传输、日记完整性
- 技能:日记轮转、日记归档、日记分析
- 安全:防窜改、防删除、不可否认性
- 应用:安全审计、合规性日记
- 安全备份存储:
- 方法:加密备份、安全传输、安全规复
- 技能:增量备份、差异备份、版本控制
- 安全:访问控制、完整性验证、安全销毁
- 应用:数据备份、劫难规复
6. 数据结构与算法计划
6.1 计划原则
- 精确性:
- 定义:算法可以或许精确办理问题,产生预期效果
- 验证:数学证明、形式化验证、测试用例
- 方法:循环稳固式、递归精确性、界限条件处理
- 应用:关键体系、安全敏感应用、金融计算
- 可维护性:
- 定义:代码易于明确、修改和扩展
- 原则:单一职责、开闭原则、依赖倒置
- 实践:清晰定名、适当注释、模块化计划
- 工具:代码审查、静态分析、重构工具
- 可扩展性:
- 定义:体系可以或许顺应厘革和增长
- 方法:抽象接口、插件架构、配置驱动
- 策略:松耦合、高内聚、依赖注入
- 应用:大型体系、长期维护项目、多团队协作
- 服从:
- 定义:算法在时间和空间上的性能体现
- 分析:时间复杂度、空间复杂度、实际性能
- 优化:算法改进、数据结构选择、实现优化
- 工具:性能分析、基准测试、性能监控
- 资源使用:
- 定义:公道使用计算资源,克制浪费
- 思量:CPU使用率、内存占用、I/O操作、网络带宽
- 策略:资源池化、懒加载、批量处理
- 应用:资源受限环境、高并发体系、云服务
- 可测试性:
- 定义:代码易于举行单元测试和集成测试
- 原则:依赖注入、接口隔离、单一职责
- 方法:测试驱动开发、模仿对象、测试覆盖
- 工具:单元测试框架、测试覆盖率工具、持续集成
- 安全性:
- 定义:算法和数据结构可以或许防止安全毛病
- 思量:输入验证、界限查抄、溢出防护
- 实践:安全编码、代码审计、毛病扫描
- 应用:安全关键体系、处理敏感数据
- 可读性:
- 定义:代码易于阅读和明确
- 原则:清晰定名、适当注释、一致的编码风格
- 实践:代码格式化、文档生成、代码审查
- 工具:代码格式化工具、文档生成器、代码分析工具
6.2 计划模式
- 迭代器模式:
- 定义:提供一种方法顺序访问聚合对象中的各个元素
- 结构:迭代器接口、具体迭代器、聚合接口、具体聚合
- 上风:封装遍历算法、支持多种遍历方式、简化接口
- 应用:集合类、树结构、图结构、流处理
- 组合模式:
- 定义:将对象组合成树形结构以表示"部门/整体"的层次结构
- 结构:组件接口、叶子节点、复合节点
- 上风:统一处理单个对象和组合对象、简化客户端代码
- 应用:文件体系、UI组件、构造结构、表达式树
- 策略模式:
- 定义:定义一系列算法,将每个算法封装起来,并使它们可以互换
- 结构:策略接口、具体策略、上下文
- 上风:算法可以独立于使用它的客户端而厘革、易于扩展
- 应用:排序算法、压缩算法、加密算法、付出方式
- 适配器模式:
- 定义:将一个类的接口转换成客户渴望的另外一个接口
- 结构:目的接口、适配器、被适配者
- 上风:使不兼容的接口可以一起工作、提高代码复用
- 应用:第三方库集成、遗留体系适配、接口转换
- 工厂模式:
- 定义:定义一个创建对象的接口,让子类决定实例化哪一个类
- 变体:简单工厂、工厂方法、抽象工厂
- 上风:封装对象的创建过程、降低耦合度
- 应用:对象创建、插件体系、配置驱动
- 观察者模式:
- 定义:定义对象间的一种一对多的依赖关系
- 结构:主题、观察者、具体主题、具体观察者
- 上风:实现松耦合、支持广播通信
- 应用:变乱处理、用户界面、数据同步
- 下令模式:
- 定义:将一个哀求封装为一个对象,使你可以用差别的哀求对客户举行参数化
- 结构:下令接口、具体下令、调用者、接收者
- 上风:将哀求发送者和接收者解耦、支持撤销操作
- 应用:菜单项、宏下令、事务处理、日记记录
- 状态模式:
- 定义:允许对象在内部状态改变时改变它的举动
- 结构:状态接口、具体状态、上下文
- 上风:将与状态相干的举动局部化、消除条件语句
- 应用:工作流、游戏状态、UI状态、网络毗连状态
- 署理模式:
- 定义:为其他对象提供一种署理以控制对这个对象的访问
- 范例:假造署理、保护署理、远程署理、智能引用
- 上风:控制对对象的访问、延长加载、权限控制
- 应用:延长加载、访问控制、日记记录、缓存
- 模板方法模式:
- 定义:定义一个操作中的算法骨架,将一些步骤延长到子类中实现
- 结构:抽象类、具体类
- 上风:代码复用、扩展点控制、钩子方法
- 应用:算法框架、工作流程、构建过程
6.3 优化本领
- 空间换时间:
- 原理:使用额外的空间来减少时间复杂度
- 方法:预处理、缓存、哈希表、查找表
- 应用:动态规划、字符串匹配、图像处理
- 权衡:内存限制、缓存友好性、数据局部性
- 预处理:
- 原理:提前计算和存储效果,克制重复计算
- 方法:前缀和、差分数组、稀疏表、倍增法
- 应用:范围查询、区间操作、静态数据
- 权衡:预处理时间、存储空间、更新成本
- 缓存:
- 原理:存储最近使用的数据,克制重复计算或访问
- 策略:LRU、LFU、FIFO、时间逾期
- 实现:内存缓存、磁盘缓存、分布式缓存
- 应用:数据库查询、API调用、计算效果
- 并行化:
- 原理:使用多核或多机并行实验任务
- 方法:数据并行、任务并行、流水线并行
- 实现:多线程、进程池、GPU加速、分布式计算
- 应用:大规模数据处理、科学计算、图像处理
- 数据结构选择:
- 原理:根据操作特点选择符合的数据结构
- 思量:访问模式、操作频率、数据规模、内存限制
- 选择:数组、链表、树、哈希表、堆、图
- 应用:特定问题、特定场景、特定束缚
- 算法改进:
- 原理:优化算法本身,减少不须要的计算
- 方法:剪枝、启发式、近似算法、随机化
- 应用:搜索算法、排序算法、图算法
- 权衡:精确性、时间复杂度、实现复杂度
- 位运算优化:
- 原理:使用位运算代替算术运算,提高服从
- 操作:与、或、异或、位移、位计数
- 应用:状态压缩、位图、哈希函数、快速幂
- 上风:速率快、节省空间、硬件友好
- 内存管理优化:
- 原理:优化内存分配和访问模式
- 方法:内存池、对象池、内存对齐、缓存行对齐
- 应用:高并发体系、及时体系、嵌入式体系
- 上风:减少内存碎片、提高缓存命中率、减少GC压力
- I/O优化:
- 原理:减少I/O操作,优化I/O模式
- 方法:批量处理、异步I/O、缓冲、预读
- 应用:文件处理、网络通信、数据库操作
- 上风:减少I/O等候、提高吞吐量、降低延长
- 代码级优化:
- 原理:优化代码实现,提高实验服从
- 方法:循环睁开、内联函数、常量折叠、死代码消除
- 应用:性能关键代码、热点函数、底层库
- 工具:编译器优化、性能分析、代码生成
6.4 算法策略
- 分治策略:
- 原理:将问题分解为子问题,递归办理,归并效果
- 步骤:分解、办理、归并
- 应用:归并排序、快速排序、二分查找、最近点对
- 分析:递归方程、主定理、递归树
- 动态规划:
- 原理:将问题分解为重叠子问题,自底向上求解
- 要素:最优子结构、重叠子问题、状态转移方程
- 应用:背包问题、最长公共子序列、编辑距离、矩阵链乘法
- 实现:自顶向下(记忆化)、自底向上(迭代)
- 贪心策略:
- 原理:每一步选择当前最优解,期望得到全局最优
- 特点:局部最优选择、不可回溯、简单高效
- 应用:活动选择、哈夫曼编码、最小生成树、单源最短路径
- 证明:贪心选择性质、最优子结构
- 回溯法:
- 原理:尝试所有可能的解,碰到不可行解时回溯
- 要素:状态空间、束缚条件、目的函数
- 应用:八皇后、子集和、图的着色、旅行商问题
- 优化:剪枝、启发式、状态压缩
- 分支限界法:
- 原理:体系搜索解空间,使用界限函数剪枝
- 方法:广度优先搜索、优先队列、界限函数
- 应用:0-1背包、作业调度、资源分配
- 上风:包管找到最优解、比回溯法更高效
- 随机化算法:
- 原理:引入随机性,以概率包管精确性或期望性能
- 范例:拉斯维加斯算法、蒙特卡洛算法
- 应用:快速排序、随机化最小生成树、近似算法
- 上风:简单实现、良好平均性能、克制最坏环境
- 近似算法:
- 原理:在多项式时间内找到靠近最优解的办理方案
- 方法:贪心近似、局部搜索、随机化近似
- 应用:旅行商问题、集合覆盖、顶点覆盖
- 分析:近似比、相对毛病、绝对毛病
- 在线算法:
- 原理:处理输入序列,每个哀求必须立即处理
- 特点:不可预知将来输入、竞争比分析
- 应用:缓存更换、页面置换、负载平衡
- 分析:竞争分析、随机化竞争比
- 并行算法:
- 原理:使用多个处理器并行办理问题
- 模型:PRAM、BSP、MapReduce、流处理
- 应用:排序、矩阵乘法、图算法、机器学习
- 分析:加速比、服从、可扩展性
- 量子算法:
- 原理:使用量子力学原理举行计算
- 算法:Shor算法、Grover算法、量子傅里叶变动
- 应用:因子分解、搜索、模仿量子体系
- 上风:指数加速、办理特定问题
6.5 代码实现
- 代码风格:
- 原则:一致性、可读性、简洁性
- 规范:定名约定、缩进规则、注释规范
- 工具:代码格式化、静态分析、代码查抄
- 应用:团队协作、代码维护、代码审查
- 错误处理:
- 方法:非常处理、错误码、断言、日记
- 策略:防御性编程、优雅降级、故障规复
- 实践:输入验证、界限查抄、资源管理
- 应用:结实体系、安全关键应用
- 代码复用:
- 方法:函数、类、模块、库
- 原则:DRY(Don’t Repeat Yourself)、组合优于继承
- 技能:泛型、模板、宏、代码生成
- 应用:减少重复代码、提高可维护性
- 性能优化:
- 方法:算法优化、数据结构选择、代码级优化
- 工具:性能分析、基准测试、性能监控
- 技能:缓存、并行化、内存管理、I/O优化
- 应用:性能关键代码、资源受限环境
- 测试驱动开发:
- 流程:编写测试、实当代码、重构
- 方法:单元测试、集成测试、体系测试
- 工具:测试框架、模仿对象、测试覆盖
- 上风:提高代码质量、简化重构、文档化举动
- 代码文档:
- 内容:接口说明、算法形貌、使用示例
- 格式:注释、文档注释、README、API文档
- 工具:文档生成器、注释剖析器、示例生成器
- 应用:代码明确、API使用、团队协作
- 版本控制:
- 体系:Git、SVN、Mercurial
- 实践:分支管理、归并策略、代码审查
- 工作流:功能分支、GitFlow、Trunk-Based
- 应用:团队协作、代码汗青、发布管理
- 持续集成:
- 流程:自动构建、自动测试、自动部署
- 工具:Jenkins、GitHub Actions、CircleCI
- 实践:频繁集成、自动化测试、环境一致
- 上风:早期发现问题、减少集成风险
- 代码审查:
- 目的:提高代码质量、知识共享、团队协作
- 方法:结对编程、正式审查、工具辅助
- 内容:功能精确性、代码质量、性能、安全性
- 工具:代码审查平台、静态分析、代码度量
- 重构:
- 目的:改善代码结构,不改变外部举动
- 方法:提取方法、移动方法、更换条件、简化表达式
- 工具:重构工具、静态分析、代码导航
- 应用:技能债务管理、代码演进、维护性提高
6.6 测试与验证
- 单元测试:
- 定义:测试代码的最小可测试单元
- 方法:测试用例计划、断言、测试覆盖
- 工具:JUnit、TestNG、Mockito、Jest
- 实践:测试驱动开发、持续集成、自动化测试
- 集成测试:
- 定义:测试多个组件之间的交互
- 方法:接口测试、数据流测试、控制流测试
- 工具:测试框架、模仿对象、测试容器
- 实践:组件集成、体系集成、持续集成
- 性能测试:
- 范例:负载测试、压力测试、稳固性测试、可扩展性测试
- 指标:响应时间、吞吐量、并发用户数、资源使用率
- 工具:JMeter、Gatling、LoadRunner、Prometheus
- 应用:体系容量规划、性能瓶颈辨认、性能优化
- 安全测试:
- 范例:毛病扫描、渗出测试、代码审计、依赖查抄
- 方法:静态分析、动态分析、暗昧测试
- 工具:OWASP ZAP、SonarQube、Snyk、Checkmarx
- 应用:安全毛病发现、合规性验证、安全加固
- 形式化验证:
- 方法:模型查抄、定理证明、抽象解释
- 工具:SPIN、Alloy、Coq、Z3
- 应用:安全关键体系、并发体系、协议验证
- 上风:数学严谨性、全面覆盖、自动化验证
- 代码审查:
- 目的:发现缺陷、提高代码质量、知识共享
- 方法:人工审查、工具辅助、结对编程
- 内容:功能精确性、代码质量、性能、安全性
- 工具:代码审查平台、静态分析、代码度量
- 回归测试:
- 定义:验证修改后的代码不会破坏现有功能
- 方法:自动化测试、测试套件、持续集成
- 工具:测试框架、CI/CD工具、测试数据管理
- 应用:代码修改、重构、版本升级
- 验收测试:
- 定义:验证体系是否满意用户需求和业务需求
- 方法:用户故事、场景测试、举动驱动开发
- 工具:Cucumber、SpecFlow、JBehave
- 应用:需求验证、用户验收、产物发布
- 混沌工程:
- 定义:通过实验发现体系弱点,提高体系弹性
- 方法:故障注入、混沌实验、弹性测试
- 工具:Chaos Monkey、Gremlin、Chaos Toolkit
- 应用:体系弹性评估、故障规复本领、高可用性
- A/B测试:
- 定义:比较两个或多个版本以确定哪个更好
- 方法:随机分配、统计分析、假设检验
- 工具:Google Optimize、Optimizely、VWO
- 应用:用户界面优化、算法比较、功能评估
6.7 实际应用案例
- 搜索引擎:
- 数据结构:倒排索引、前缀树、布隆过滤器
- 算法:PageRank、TF-IDF、BM25、向量检索
- 优化:分布式索引、缓存策略、查询优化
- 挑战:大规模数据、及时更新、相干性排序
- 数据库体系:
- 数据结构:B+树、哈希表、跳表、LSM树
- 算法:查询优化、事务处理、并发控制
- 优化:索引选择、毗连优化、缓存管理
- 挑战:ACID包管、高并发、分布式一致性
- 操作体系:
- 数据结构:页表、进程控制块、文件体系、调度队列
- 算法:页面置换、进程调度、文件分配、死锁检测
- 优化:内存管理、I/O调度、进程通信
- 挑战:资源管理、并发控制、及时性要求
- 网络体系:
- 数据结构:路由表、毗连池、缓冲区、消息队列
- 算法:路由算法、拥塞控制、负载平衡、流量控制
- 优化:零拷贝、内存池、线程池、异步I/O
- 挑战:高吞吐量、低延长、可靠性、安全性
- 图形体系:
- 数据结构:场景图、空间分区、材质体系、动画体系
- 算法:渲染算法、碰撞检测、物理模仿、动画体系
- 优化:视锥剔除、LOD、遮挡剔除、批处理
- 挑战:及时渲染、物理模仿、动画体系、用户交互
- 人工智能:
- 数据结构:特征向量、决策树、神经网络、知识图谱
- 算法:机器学习算法、深度学习、强化学习、自然语言处理
- 优化:模型压缩、量化、分布式训练、推理加速
- 挑战:大规模数据、模型复杂度、计算资源、及时性
- 游戏开发:
- 数据结构:游戏状态、实体组件体系、对象池、变乱体系
- 算法:物理模仿、寻路算法、AI决策、碰撞检测
- 优化:帧率优化、内存管理、资源加载、网络同步
- 挑战:及时性、物理模仿、AI举动、网络延长
- 金融体系:
- 数据结构:交易记录、账户信息、市场数据、风险模型
- 算法:定价算法、风险评估、投资组合优化、高频交易
- 优化:低延长处理、高吞吐量、数据一致性、风险控制
- 挑战:及时性、准确性、安全性、合规性
- 物联网体系:
- 数据结构:传感器数据、设备状态、变乱流、时序数据
- 算法:数据聚合、非常检测、预测分析、资源调度
- 优化:能源服从、网络带宽、存储服从、及时处理
- 挑战:资源受限、网络不稳固、数据量大、及时性
- 区块链体系:
- 数据结构:默克尔树、区块链、状态树、交易池
- 算法:共识算法、暗码学算法、智能合约、P2P网络
- 优化:交易处理、存储服从、网络传播、共识服从
- 挑战:去中心化、安全性、可扩展性、能源斲丧
7. 数据结构实战案例
7.1 电商体系
7.1.1 商品管理
- 商品分类树:使用树结构管理商品分类,支持多级分类和快速导航
- 商品索引:使用B+树或哈希表实现商品快速检索,支持按名称、价格、销量等属性查询
- 购物车:使用哈希表存储用户购物车,键为用户ID,值为购物车商品列表
- 订单队列:使用优先队列管理订单处理,按优先级或时间顺序处理订单
- 商品推荐:使用协同过滤算法和图结构实现个性化商品推荐
- 商品搜索:使用倒排索引和前缀树实现商品搜索功能,支持暗昧匹配和自动补全
7.1.2 库存管理
- 库存计数:使用哈希表记录商品库存数量,支持O(1)的库存查询和更新
- 库存预警:使用最小堆监控库存水平,当库存低于阈值时触发预警
- 库存日记:使用链表或队列记录库存变动汗青,支持库存追溯和审计
- 库存锁定:使用并发哈希表管理库存锁定状态,防止超卖
- 库存分析:使用时间序列数据结构分析库存趋势,预测将来需求
- 分布式库存:使用一致性哈希实现分布式库存管理,提高体系可用性
7.1.3 付出体系
- 付出队列:使用优先级队列处理付出哀求,确保高优先级交易优先处理
- 交易记录:使用B+树存储交易记录,支持高效查询和范围扫描
- 退款处理:使用状态机管理退款流程,跟踪退款状态和进度
- 付出路由:使用加权图实现付出路由,选择最优付出渠道
- 风控体系:使用布隆过滤器快速辨认可疑交易,减少欺诈风险
- 对账体系:使用哈希表比对交易记录,确保账务一致性
7.2 交际网络
7.2.1 关系管理
- 挚友关系图:使用邻接表或邻接矩阵表示交际关系图,支持关系查询和推荐
- 关注列表:使用哈希表和链表组合存储关注关系,支持快速查询和更新
- 消息队列:使用优先级队列处理消息通知,确保重要消息优先送达
- 动态流:使用跳表或红黑树实现动态内容流,支持按时间顺序展示内容
- 交际推荐:使用图算法实现挚友推荐,基于共同挚友和兴趣相似度
- 关系分析:使用图算法分析交际网络结构,辨认关键节点和社区
7.2.2 内容管理
- 内容索引:使用倒排索引实现内容搜索,支持全文检索和标签过滤
- 评论树:使用树结构构造评论,支持多级回复和评论排序
- 点赞计数:使用计数器数据结构记录点赞数,支持原子操作和并发控制
- 分享记录:使用链表或队列记录分享汗青,支持内容传播追踪
- 内容考核:使用布隆过滤器快速过滤违规内容,提高考核服从
- 热门内容:使用最大堆或跳表维护热门内容排行榜,支持及时更新
7.2.3 及时通信
- 消息存储:使用时间序列数据库存储聊天记录,支持高效查询和范围扫描
- 在线状态:使用哈希表记录用户在线状态,支持及时状态更新和查询
- 群组管理:使用集合数据结构管理群组成员,支持快速成员查询和更新
- 消息推送:使用优先级队列处理消息推送,确保重要消息优先送达
- 消息同步:使用版本向量或时间戳实现消息同步,办理冲突和重复问题
- 消息加密:使用加密数据结构保护消息内容,确保通信安全
7.3 搜索引擎
7.3.1 索引构建
- 倒排索引:使用哈希表和链表组合构建倒排索引,支持高效关键词检索
- 前缀树:使用字典树实现自动补全和前缀匹配,提高搜索体验
- 布隆过滤器:使用布隆过滤器快速判定URL是否已爬取,克制重复爬取
- 缓存体系:使用LRU缓存存储热门查询效果,减少重复计算
- 分布式索引:使用一致性哈希实现分布式索引,提高体系可扩展性
- 增量索引:使用LSM树实现增量索引更新,平衡写入和查询性能
7.3.2 查询处理
- 查询剖析:使用语法树剖析搜索查询,支持复杂查询语法和语义明确
- 效果排序:使用堆排序或快速排序对搜索效果举行排序,支持多维度排序
- 相干性计算:使用向量空间模型计算文档相干性,支持语义相似度匹配
- 效果缓存:使用多级缓存存储查询效果,减少重复计算和数据库访问
- 查询优化:使用查询重写和查询筹划优化提高查询服从
- 个性化搜索:使用用户画像和协同过滤实现个性化搜索效果排序
7.3.3 爬虫体系
- URL队列:使用优先级队列管理待爬取URL,支持深度优先和广度优先爬取
- 域名限制:使用哈希表记录域名访问频率,实现爬取速率控制
- 内容剖析:使用DOM树剖析网页内容,提取结构化数据
- 链接提取:使用图结构存储网页链接关系,支持网站地图生成
- 内容去重:使用SimHash或MinHash实现内容相似度检测,克制重复内容
- 分布式爬取:使用任务队列和效果队列实现分布式爬虫,提高爬取服从
7.4 数据库体系
7.4.1 索引结构
- B+树索引:用于范围查询和排序,支持高效的点查询和范围查询
- 哈希索引:用于等值查询,支持O(1)的查询性能
- 位图索引:用于低基数列的查询,如性别、状态等
- 全文索引:用于文本搜索,支持暗昧匹配和相干性排序
- LSM树:用于写入麋集型场景,平衡读写性能
- R树:用于空间数据索引,支持地理位置查询
7.4.2 查询优化
- 索引选择:根据查询条件和数据分布选择符合的索引
- 毗连优化:使用哈希毗连、嵌套循环毗连或排序归并毗连
- 排序优化:使用索引克制排序操作,或使用外部排序
- 缓存策略:使用缓冲池、查询缓存、效果集缓存
- 并行查询:将查询分解为多个子查询并行实验
- 物化视图:预计算常用查询效果,加速查询响应
7.4.3 事务处理
- ACID属性:原子性、一致性、隔离性、持久性
- 并发控制:使用锁机制、时间戳、多版本并发控制
- 规复机制:使用日记、查抄点、回滚段
- 分布式事务:使用两阶段提交、三阶段提交、Paxos算法
- 死锁检测:使用等候图检测死锁,支持死锁预防和克制
- 事务调度:使用串行化调度确保事务一致性
7.5 操作体系
7.5.1 内存管理
- 页表:使用多级页表、反向页表、哈希页表
- 段表:使用段形貌符、段选择子、段权限
- 空闲内存管理:使用位图、链表、同伴体系
- 假造内存:使用页面置换算法、工作集模型、预取
- 内存映射:使用内存映射文件、共享内存、匿名映射
- 内存保护:使用访问权限、地址空隔断离、ASLR
7.5.2 进程管理
- 进程调度:使用先来先服务、短作业优先、时间片轮转、多级反馈队列
- 进程同步:使用信号量、互斥锁、条件变量、管程
- 进程通信:使用管道、消息队列、共享内存、套接字
- 线程管理:使用线程池、线程当地存储、线程调度
- 进程状态:使用状态机、状态转换图、状态表
- 及时调度:使用最早停止时间优先、速率单调调度、最小松懈度优先
7.5.3 文件体系
- 文件构造:使用连续分配、链接分配、索引分配
- 目次结构:使用单级目次、两级目次、树形目次、无环图目次
- 文件保护:使用访问控制列表、本领表、权限位
- 日记文件体系:使用写前日记、写后日记、影子分页
- 分布式文件体系:使用一致性哈希、副本管理、分区容错
- 文件体系性能:使用缓存、预读、写缓冲、延长写入
7.6 网络体系
7.6.1 路由算法
- 最短路径算法:使用Dijkstra算法、Bellman-Ford算法、Floyd-Warshall算法
- 距离向量路由:使用RIP、BGP、IGRP
- 链路状态路由:使用OSPF、IS-IS
- 路径向量路由:使用BGP、EGP
- QoS路由:使用带宽感知路由、延长感知路由、多束缚路由
- 多播路由:使用DVMRP、PIM、MOSPF
7.6.2 拥塞控制
- TCP拥塞控制:使用慢启动、拥塞克制、快重传、快规复
- 自动队列管理:使用RED、WRED、BLUE、CHOKe
- 显式拥塞通知:使用ECN、ECN标记、ECN回显
- 流量整形与羁系:使用漏桶算法、令牌桶算法、双漏桶算法
- 分布式拥塞控制:使用XCP、RCP、VCP
- 跨层拥塞控制:使用TCP友好、TCP友好速率控制、TCP友好拥塞控制
7.6.3 负载平衡
- 服务器负载平衡:使用轮询、加权轮询、最少毗连、加权最少毗连
- 全局负载平衡:使用DNS负载平衡、地理负载平衡、内容感知负载平衡
- 应用层负载平衡:使用HTTP重定向、URL重写、内容互换
- 动态负载平衡:使用自顺应负载平衡、预测性负载平衡、响应时间感知负载平衡
- 一致性哈希:用于分布式缓存、分布式存储、分布式负载平衡
- 负载平衡策略:使用健康查抄、会话保持、故障转移、过载保护
7.7 编译器体系
7.7.1 符号表
- 结构:使用哈希表、二叉搜索树、红黑树、跳表
- 作用域管理:使用作用域栈、作用域树、作用域链
- 符号剖析:使用名称剖析、范例查抄、语义分析
- 符号表优化:使用符号归并、符号消除、符号内联
7.7.2 语法分析
- 剖析器:使用递归下降、LL剖析、LR剖析、语法导向翻译
- 抽象语法树:使用表达式树、语句树、声明树
- 语义分析:使用范例查抄、范例推导、语义验证
7.7.3 代码优化
- 局部优化:使用常量折叠、强度减弱、死代码消除、公共子表达式消除
- 全局优化:使用数据流分析、活跃变量分析、到达定义分析、可用表达式分析
- 循环优化:使用循环睁开、循环融合、循环稳固量外提、循环向量化
7.8 人工智能与机器学习
7.8.1 特征工程
- 特征提取:使用主身分分析、独立身分分析、因子分析、t-SNE
- 特征选择:使用过滤法、包装法、嵌入法、L1正则化
- 特征转换:使用标准化、归一化、对数变动、多项式特征
7.8.2 模型存储
- 序列化:使用JSON、Protocol Buffers、MessagePack、HDF5
- 压缩:使用量化、剪枝、知识蒸馏、模型压缩
- 版本控制:使用模型版本ing、模型注册、模型部署
7.8.3 推理优化
- 计算图优化:使用图优化、算子融合、内存优化、并行计算
- 硬件加速:使用GPU加速、TPU加速、FPGA加速、ASIC加速
- 批处理优化:使用动态批处理、批处理巨细调整、批处理调度
7.9 游戏开发
7.9.1 游戏状态管理
- 状态机:使用有限状态机、层次状态机、举动树
- 实体组件体系:使用实体管理器、组件管理器、体系管理器
- 变乱体系:使用观察者模式、变乱队列、变乱分发器
7.9.2 物理模仿
- 碰撞检测:使用空间分区、包围盒、碰撞树、碰撞网格
- 刚体动力学:使用牛顿活动定律、束缚求解、碰撞响应
- 粒子体系:使用粒子发射器、粒子更新、粒子渲染
7.9.3 寻路算法
- A*算法:使用启发式函数、开放列表、关闭列表、路径重修
- 导航网格:使用网格生成、网格简化、网格寻路
- 举动树:使用选择节点、序列节点、并行节点、装饰节点
7.10 安全体系
7.10.1 加密算法
- 对称加密:使用AES、DES、ChaCha20
- 非对称加密:使用RSA、ECC、DH
- 哈希函数:使用SHA-256、SHA-3、Blake2
7.10.2 访问控制
- 访问控制模型:使用DAC、MAC、RBAC、ABAC
- 认证:使用暗码认证、多因素认证、生物认证
- 权限管理:使用权限矩阵、权限树、权限继承
7.10.3 安全存储
- 密钥存储:使用密钥管理体系、硬件安全模块、安全 enclave
- 数据存储:使用加密存储、安全删除、数据脱敏
- 通信安全:使用TLS、IPsec、端到端加密
7.11 金融体系
7.11.1 交易处理
- 订单匹配:使用订单簿、价格时间优先、冰山订单
- 风险控制:使用风险限额、风险计算、风险监控
- 清算结算:使用净额结算、全额结算、及时结算
7.11.2 市场数据
- 行情数据:使用行情订阅、行情分发、行情存储
- 汗青数据:使用时间序列数据库、数据压缩、数据归档
- 及时分析:使用流处理、复杂变乱处理、及时计算
7.11.3 投资组合
- 资产配置:使用当代投资组公道论、风险平价、Black-Litterman模型
- 绩效分析:使用收益率计算、风险调整收益、归因分析
- 交易实验:使用算法交易、智能订单路由、交易成本分析
7.12 物联网体系
7.12.1 传感器数据
- 数据收罗:使用采样策略、数据过滤、数据压缩
- 数据存储:使用时序数据库、数据分区、数据保留策略
- 数据查询:使用时间范围查询、聚合查询、非常检测
7.12.2 设备管理
- 设备注册:使用设备标识、设备认证、设备分组
- 设备监控:使专心跳检测、状态监控、告警管理
- 设备控制:使用下令下发、配置管理、固件更新
7.12.3 边缘计算
- 数据处理:使用数据预处理、特征提取、模型推理
- 资源调度:使用任务调度、资源分配、负载平衡
- 网络优化:使用数据压缩、协议优化、带宽管理
7.13 区块链体系
7.13.1 数据结构
- 区块链:使用区块、区块头、区块体、默克尔树
- 状态树:使用账户状态、存储树、交易树
- 交易池:使用交易队列、交易优先级、交易验证
7.13.2 共识算法
- PoW:使用工作量证明、难度调整、挖矿奖励
- PoS:使用权益证明、验证者选择、惩罚机制
- DPoS:使用委托权益证明、代表选举、轮换机制
7.13.3 智能合约
- 合约实验:使用假造机、沙箱环境、gas机制
- 合约存储:使用状态存储、变乱日记、代码存储
- 合约安全:使用形式化验证、毛病检测、权限控制
7.14 大数据处理
7.14.1 数据存储
- 分布式文件体系:使用HDFS、GFS、Ceph
- 列式存储:使用Parquet、ORC、Arrow
- 数据湖:使用数据分区、数据版本ing、数据管理
7.14.2 数据处理
- 批处理:使用MapReduce、Spark、Flink
- 流处理:使用Storm、Kafka Streams、Flink
- 图处理:使用Pregel、GraphX、Giraph
7.14.3 数据分析
- 统计分析:使用形貌统计、推断统计、时间序列分析
- 机器学习:使用分类、回归、聚类、推荐
- 可视化:使用图表、仪表盘、交互式可视化
7.15 云计算体系
7.15.1 资源管理
- 假造机管理:使用假造机调度、资源分配、负载平衡
- 容器管理:使用容器编排、服务发现、自动扩缩容
- 存储管理:使用块存储、对象存储、文件存储
7.15.2 服务编排
- 微服务:使用服务注册、服务发现、服务网关
- 服务网格:使用流量管理、安全策略、可观测性
- 无服务器:使用函数即服务、变乱驱动、按需扩展
7.15.3 云原生应用
- 应用开发:使用容器化、微服务、DevOps
- 应用部署:使用持续集成、持续部署、蓝绿部署
- 应用监控:使用日记管理、指标收集、追踪体系
7.16 移动应用开发
7.16.1 UI组件
- 视图层次:使用视图树、布局体系、渲染管线
- 变乱处理:使用变乱分发、手势辨认、动画体系
- 状态管理:使用状态机、响应式编程、单向数据流
7.16.2 数据存储
- 当地存储:使用SQLite、Realm、Room
- 缓存管理:使用内存缓存、磁盘缓存、网络缓存
- 数据同步:使用增量同步、冲突办理、离线支持
7.16.3 网络通信
- API调用:使用REST、GraphQL、gRPC
- 及时通信:使用WebSocket、长轮询、服务器发送变乱
- 安全通信:使用证书固定、加密传输、安全存储
7.17 嵌入式体系
7.17.1 及时体系
- 任务调度:使用优先级调度、停止时间调度、比例份额调度
- 中断处理:使用中断向量表、中断优先级、中断嵌套
- 资源管理:使用资源锁定、优先级继承、死锁克制
7.17.2 内存管理
- 静态分配:使用静态数组、静态变量、常量数据
- 动态分配:使用内存池、堆管理、碎片整理
- 内存保护:使用内存保护单元、访问控制、地址转换
7.17.3 外设控制
- 设备驱动:使用设备寄存器、中断处理、DMA传输
- 通信协议:使用UART、SPI、I2C、CAN
- 传感器接口:使用ADC、PWM、GPIO、定时器
8. 数据结构与性能优化
8.1 内存优化
8.1.1 内存布局
- 数据对齐:使用适当的数据对齐减少内存访问次数,提高缓存命中率
- 内存池:使用内存池减少内存分配和释放的开销,克制内存碎片
- 对象复用:使用对象池复用对象,减少垃圾接纳压力
- 内存映射:使用内存映射文件减少I/O操作,提高大数据集访问服从
- 压缩指针:使用压缩指针减少对象引用占用的内存空间
- 内存预分配:预先分配足够的内存空间,克制频繁的内存重新分配
8.1.2 缓存优化
- 缓存友好性:计划数据结构时思量缓存行巨细,减少缓存未命中
- 数据局部性:使用时间局部性和空间局部性,提高缓存命中率
- 预取技能:使用预取指令提前加载可能必要的数据到缓存
- 缓存行对齐:确保关键数据结构与缓存行对齐,克制伪共享
- 缓存一致性:在多核体系中注意缓存一致性问题,减少缓存同步开销
- 缓存更换策略:选择符合的缓存更换策略,如LRU、LFU、FIFO等
8.1.3 垃圾接纳优化
- 对象生命周期:控制对象生命周期,减少垃圾接纳压力
- 内存走漏检测:使用工具检测和修复内存走漏问题
- 分代垃圾接纳:使用分代垃圾接纳特性,针对差别代接纳差别的接纳策略
- 垃圾接纳调优:调整垃圾接纳参数,平衡吞吐量和延长
- 低延长垃圾接纳:使用低延长垃圾接纳器,减少停顿时间
- 手动内存管理:在关键路径上使用手动内存管理,克制垃圾接纳开销
8.2 算法优化
8.2.1 时间复杂度优化
- 算法选择:根据问题规模和特点选择符合的算法,平衡时间和空间复杂度
- 剪枝技能:使用剪枝技能减少搜索空间,提高算法服从
- 动态规划:使用动态规划克制重复计算,将指数复杂度降低到多项式复杂度
- 贪默算法:在适用场景使用贪默算法,获得近似最优解
- 分治策略:使用分治策略将大问题分解为小问题,降低问题复杂度
- 近似算法:在可担当毛病范围内使用近似算法,获得更高效的办理方案
8.2.2 空间复杂度优化
- 原地算法:使用原地算法减少额外空间使用,如原地排序、原地反转等
- 压缩技能:使用数据压缩技能减少存储空间,如游程编码、哈夫曼编码等
- 稀疏表示:对稀疏数据使用稀疏表示,如稀疏矩阵、稀疏向量等
- 位操作:使用位操作代替数组或布尔值,节省内存空间
- 数据流处理:使用流式处理代替一次性加载全部数据,减少内存占用
- 延长计算:使用延长计算技能,只在必要时计算效果,节省存储空间
8.2.3 算法实现优化
- 循环优化:使用循环睁开、循环融合、循环稳固量外提等技能优化循环
- 条件优化:使用短路评估、条件归并、分支预测等技能优化条件判定
- 数学优化:使用数学变动简化计算,如使用位运算代替乘除法
- 数据结构选择:根据操作特点选择符合的数据结构,如使用哈希表代替线性搜索
- 缓存友好算法:计划思量缓存特性的算法,如分块矩阵乘法、缓存友好的排序算法
- 并行算法:使用并行算法使用多核处理器,提高计算服从
8.3 数据结构选择
8.3.1 基本操作分析
- 访问模式:分析数据的访问模式,如随机访问、顺序访问、范围访问等
- 操作频率:分析各种操作的频率,如查询、插入、删除、更新等
- 数据规模:思量数据规模对性能的影响,如小规模数据和大规模数据的差别选择
- 数据分布:分析数据的分布特征,如均匀分布、偏斜分布、周期性分布等
- 数据稳固性:思量数据的稳固性,如静态数据、动态数据、频繁厘革的数据等
- 内存限制:思量内存限制对数据结构选择的影响,如内存受限环境下的选择
8.3.2 场景特定选择
- 查找麋集型:对于查找麋集型场景,选择哈希表、二叉搜索树、跳表等
- 插入麋集型:对于插入麋集型场景,选择链表、红黑树、AVL树等
- 范围查询:对于范围查询场景,选择B+树、区间树、线段树等
- 前缀匹配:对于前缀匹配场景,选择字典树、后缀树、后缀数组等
- 空间数据:对于空间数据场景,选择四叉树、R树、kd树等
- 图数据:对于图数据场景,选择邻接矩阵、邻接表、压缩稀疏行等
8.3.3 复合数据结构
- 哈希表+链表:结合哈希表的快速查找和链表的顺序访问特性
- 跳表+哈希表:结合跳表的范围查询和哈希表的精确查找特性
- 树+哈希表:结合树的层次结构和哈希表的快速查找特性
- 布隆过滤器+哈希表:使用布隆过滤器减少哈希表查询次数
- 缓存+持久存储:结合内存缓存和持久存储,平衡速率和容量
- 多级索引:使用多级索引结构,平衡差别操作的性能
8.4 并发优化
8.4.1 线程安全
- 不可变对象:使用不可变对象克制同步开销,提高并发性能
- 线程当地存储:使用线程当地存储克制线程间竞争,减少同步开销
- 原子操作:使用原子操作代替锁,减少同步开销,如原子整数、原子引用等
- 无锁算法:使用无锁算法克制锁竞争,如无锁队列、无锁栈等
- 细粒度锁:使用细粒度锁减少锁竞争,如分段锁、读写锁等
- 锁消除:使用锁消除技能,在编译器或运行时消除不须要的锁
8.4.2 并发数据结构
- 并发集合:使用并发集合代替同步集合,如ConcurrentHashMap、CopyOnWriteArrayList等
- 壅闭队列:使用壅闭队列实现生产者-消费者模式,如ArrayBlockingQueue、LinkedBlockingQueue等
- 并发计数器:使用并发计数器举行计数,如AtomicInteger、LongAdder等
- 并发图:使用并发图数据结构处理并发图操作,如并发邻接表、并发邻接矩阵等
- 并发树:使用并发树数据结构处理并发树操作,如并发红黑树、并发B树等
- 并发哈希表:使用并发哈希表处理并发哈希表操作,如ConcurrentHashMap、ConcurrentSkipListMap等
8.4.3 并行计算
- 数据并行:将数据分割成多个部门并行处理,如并行排序、并行搜索等
- 任务并行:将任务分割成多个子任务并行实验,如并行归约、并行扫描等
- 流水线并行:使用流水线并行处理数据流,如流水线排序、流水线过滤等
- 分治并行:使用分治策略并行处理问题,如并行快速排序、并行归并排序等
- 并行图算法:并行处理图算法,如并行BFS、并行DFS、并行最短路径等
- 并行流处理:使用并行流处理数据,如Java Stream API的并行流、响应式流等
8.5 I/O优化
8.5.1 文件I/O优化
- 缓冲I/O:使用缓冲I/O减少体系调用次数,如BufferedReader、BufferedWriter等
- 内存映射:使用内存映射文件减少I/O操作,如MappedByteBuffer等
- 异步I/O:使用异步I/O克制壅闭,如AsynchronousFileChannel、CompletableFuture等
- 批量I/O:使用批量I/O减少I/O操作次数,如批量读取、批量写入等
- 压缩I/O:使用压缩I/O减少传输数据量,如GZIPInputStream、GZIPOutputStream等
- 随机访问优化:优化随机访问模式,如使用索引、缓存、预读等
8.5.2 网络I/O优化
- 非壅闭I/O:使用非壅闭I/O克制线程壅闭,如NIO、Netty等
- 变乱驱动:使用变乱驱动模型处理I/O变乱,如Reactor模式、Proactor模式等
- 毗连池:使用毗连池复用毗连,减少毗连建立和断开的开销
- 消息压缩:使用消息压缩减少网络传输量,如Protocol Buffers、MessagePack等
- 批量传输:使用批量传输减少网络往返次数,如批量哀求、批量响应等
- 长毗连:使用长毗连减少毗连建立和断开的开销,如WebSocket、HTTP/2等
8.5.3 数据库I/O优化
- 索引优化:使用符合的索引减少数据库扫描,如B+树索引、哈希索引等
- 查询优化:优化SQL查询减少数据库I/O,如克制全表扫描、使用覆盖索引等
- 批量操作:使用批量操作减少数据库往返次数,如批量插入、批量更新等
- 毗连池:使用数据库毗连池复用毗连,减少毗连建立和断开的开销
- 缓存策略:使用缓存策略减少数据库访问,如查询缓存、效果集缓存等
- 分区策略:使用分区策略减少数据库扫描范围,如范围分区、哈希分区等
8.6 体系级优化
8.6.1 操作体系优化
- 进程调度:优化进程调度策略,如优先级调度、时间片轮转等
- 内存管理:优化内存管理策略,如页面置换算法、内存分配策略等
- 文件体系:优化文件体系性能,如文件体系范例、挂载选项等
- 网络栈:优化网络栈性能,如TCP参数调优、网络缓冲区巨细等
- 体系调用:减少体系调用次数,如使用批处理、缓存等
- 中断处理:优化中断处理,如中断亲和性、中断归并等
8.6.2 假造机优化
- JVM参数调优:调整JVM参数优化性能,如堆巨细、垃圾接纳器、线程栈巨细等
- 即时编译:使用即时编译优化热点代码,如方法内联、逃逸分析等
- 类加载优化:优化类加载过程,如类预加载、类共享等
- 内存模型:明确并使用内存模型优化并发步伐,如可见性、有序性等
- 线程模型:优化线程模型,如线程池、工作窃取等
- 字节码优化:优化字节码,如常量折叠、死代码消除等
8.6.3 分布式体系优化
- 数据分区:优化数据分区策略,如一致性哈希、范围分区等
- 复制策略:优化复制策略,如主从复制、多主复制、无主复制等
- 一致性模型:选择符合的 consistency 模型,如强一致性、最终一致性等
- 故障检测:优化故障检测机制,如心跳检测、超时设置等
- 负载平衡:优化负载平衡策略,如轮询、加权轮询、最少毗连等
- 网络拓扑:优化网络拓扑,如星形拓扑、环形拓扑、网状拓扑等
8.7 性能测量与分析
8.7.1 性能指标
- 响应时间:测量体系响应时间,如平均响应时间、百分位响应时间等
- 吞吐量:测量体系吞吐量,如每秒哀求数、每秒事务数等
- 并发度:测量体系并发度,如并发用户数、并发毗连数等
- 资源使用率:测量体系资源使用率,如CPU使用率、内存使用率、磁盘使用率等
- 延长:测量体系延长,如网络延长、处理延长、列队延长等
- 公平性:测量体系公平性,如资源分配公平性、服务公平性等
8.7.2 性能分析工具
- 性能分析器:使用性能分析器分析步伐性能,如JProfiler、VisualVM、perf等
- 内存分析器:使用内存分析器分析内存使用,如MAT、jmap、Valgrind等
- 线程分析器:使用线程分析器分析线程举动,如jstack、Thread Dump Analyzer等
- 体系监控工具:使用体系监控工具监控体系性能,如top、htop、iostat等
- 网络分析工具:使用网络分析工具分析网络性能,如tcpdump、Wireshark、netstat等
- 日记分析工具:使用日记分析工具分析体系日记,如ELK Stack、Splunk、Graylog等
8.7.3 性能测试方法
- 基准测试:使用基准测试测量体系性能,如JMH、BenchmarkDotNet等
- 负载测试:使用负载测试测试体系在高负载下的性能,如JMeter、Gatling等
- 压力测试:使用压力测试测试体系在极限负载下的性能,如Stress Testing等
- 稳固性测试:使用稳固性测试测试体系在长时间运行下的稳固性,如Long-running Test等
- 可扩展性测试:使用可扩展性测试测试体系在规模增长下的性能,如Scalability Test等
- 对比测试:使用对比测试比较差别实现或配置的性能,如A/B Testing等
8.8 实际案例分析
8.8.1 数据库查询优化
- 索引优化:优化数据库索引提高查询性能,如选择符合的索引范例、优化索引列顺序等
- 查询重写:重写SQL查询提高查询性能,如克制子查询、使用毗连代替子查询等
- 实验计分别析:分析SQL实验筹划找出性能瓶颈,如全表扫描、索引失效等
- 分区策略:使用分区策略提高查询性能,如范围分区、哈希分区等
- 物化视图:使用物化视图预计算常用查询效果,如汇总数据、复杂毗连等
- 查询缓存:使用查询缓存减少重复查询,如效果集缓存、查询筹划缓存等
8.8.2 Web应用优化
- 前端优化:优化前端性能,如资源压缩、懒加载、代码分割等
- 后端优化:优化后端性能,如缓存策略、数据库优化、并发处理等
- 网络优化:优化网络性能,如CDN、HTTP/2、压缩等
- 会话管理:优化会话管理,如会话共享、会话复制、会话持久化等
- 静态资源:优化静态资源,如资源归并、资源压缩、资源缓存等
- API计划:优化API计划,如RESTful API、GraphQL、批量API等
8.8.3 大数据处理优化
- 数据分区:优化数据分区策略,如范围分区、哈希分区、复合分区等
- 并行处理:优化并行处理策略,如数据并行、任务并行、流水线并行等
- 内存管理:优化内存管理策略,如内存池、内存映射、压缩等
- 数据压缩:优化数据压缩策略,如列式存储、编码优化、压缩算法选择等
- 查询优化:优化查询策略,如查询重写、实验筹划优化、物化视图等
- 资源调度:优化资源调度策略,如动态分配、优先级调度、公平调度等
9. 数据结构与并发编程
9.1 并发数据结构
9.1.1 线程安全集合
- ConcurrentHashMap
- 基于分段锁或CAS操作的线程安全哈希表
- 支持高并发读写操作,适合读多写少的场景
- 内部使用Node数组和链表/红黑树结构
- 提供原子操作和批量操作
- 支持弱一致性的迭代器
- 适用场景:缓存、计数器、共享资源管理
- CopyOnWriteArrayList
- 写时复制策略的线程安全列表
- 读操作完全无锁,写操作复制整个数组
- 适合读多写少的场景,写操作性能较差
- 内存占用较大,不适合大数据量
- 迭代器支持弱一致性,不会抛出ConcurrentModificationException
- 适用场景:监听器列表、配置信息、只读数据
- BlockingQueue
- 支持壅闭操作的线程安全队列
- 提供put/take等壅闭操作和offer/poll等非壅闭操作
- 实现类包括ArrayBlockingQueue、LinkedBlockingQueue等
- 支持容量限制和超时机制
- 可用于生产者-消费者模式
- 适用场景:任务队列、消息队列、数据缓冲
- ConcurrentSkipListMap
- 基于跳表的线程安全有序映射
- 支持高并发读写操作,保持键的有序性
- 查找、插入、删除的平均时间复杂度为O(log n)
- 空间复杂度较高,适合必要有序性的场景
- 支持范围查询和导航操作
- 适用场景:有序数据、范围查询、优先级队列
9.1.2 无锁数据结构
- CAS操作
- Compare-And-Swap,原子比较并互换操作
- 由CPU直接支持,无需锁机制
- 适用于简单的原子操作,如计数器、标记位
- 可能出现ABA问题,必要使用版本号或时间戳办理
- 在高竞争环境下性能可能下降
- 适用场景:原子计数器、标记位、简单数据结构
- 原子类
- 提供原子操作的包装类,如AtomicInteger、AtomicLong
- 基于CAS操作实现,无需显式同步
- 支持原子更新、原子累加、原子比较等操作
- 提供高性能的原子操作,如addAndGet、compareAndSet
- 适用于简单的原子操作,复杂操作需自行实现
- 适用场景:计数器、标记位、简单状态管理
- 无锁队列
- 基于CAS操作实现的线程安全队列
- 如ConcurrentLinkedQueue,支持高并发操作
- 无需锁机制,性能优于基于锁的队列
- 实现复杂,调试困难
- 适用于高并发场景,如消息队列、任务队列
- 适用场景:高性能消息队列、任务调度、变乱处理
- 无锁栈
- 基于CAS操作实现的线程安全栈
- 如ConcurrentLinkedDeque,支持高并发操作
- 无需锁机制,性能优于基于锁的栈
- 实现复杂,调试困难
- 适用于高并发场景,如撤销栈、操作汗青
- 适用场景:撤销/重做操作、操作汗青、任务调度
9.2 并发控制
9.2.1 同步机制
- 互斥锁
- 包管同一时间只有一个线程访问共享资源
- 如synchronized关键字、ReentrantLock类
- 支持可重入,克制自锁死锁
- 可能导致线程壅闭和上下文切换
- 支持公平锁和非公平锁
- 适用场景:共享资源访问、临界区保护
- 读写锁
- 允许多个读操作并发实验,写操作独占实验
- 如ReadWriteLock接口、ReentrantReadWriteLock类
- 提高读多写少场景的并发性
- 支持锁降级,但不支持锁升级
- 实现复杂,调试困难
- 适用场景:缓存、配置信息、共享资源
- 条件变量
- 用于线程间的和谐和通信
- 如Condition接口、Object.wait/notify方法
- 支持线程等候和唤醒机制
- 必须与锁配合使用
- 可以克制忙等候,提高CPU使用率
- 适用场景:生产者-消费者模式、线程和谐
- 信号量
- 控制同时访问资源的线程数量
- 如Semaphore类,支持许可的获取和释放
- 可以用于资源池、限流等场景
- 支持公平模式和非公平模式
- 可以用于实现复杂的同步需求
- 适用场景:资源池、限流、并发控制
9.2.2 并发模式
- 生产者消费者
- 生产者生产数据,消费者消费数据,通过队列解耦
- 可以使用BlockingQueue、信号量、条件变量等实现
- 支持多生产者-多消费者模式
- 可以用于任务处理、数据流处理、变乱处理
- 必要处理队列满和空的环境
- 适用场景:任务处理、数据流处理、变乱处理
- 读者写者
- 允许多个读者同时读取,写者独占写入
- 可以使用读写锁、信号量等实现
- 支持读者优先、写者优先、公平模式
- 适用于读多写少的场景
- 必要处理读者和写者的优先级
- 适用场景:缓存、配置信息、共享资源
- 哲学家进餐
- 经典的死锁和资源竞争问题
- 可以使用多种策略克制死锁,如资源排序、超时机制
- 可以用于测试并发控制机制
- 必要处理死锁、饥饿等问题
- 可以用于讲授和演示并发问题
- 适用场景:并发控制测试、讲授演示
- 剃头师问题
- 经典的资源分配和队列管理问题
- 可以使用信号量、条件变量等实现
- 必要处理队列满和空的环境
- 可以用于测试并发控制机制
- 可以用于讲授和演示并发问题
- 适用场景:资源分配、队列管理、讲授演示
9.3 线程安全计划
9.3.1 不可变对象
- 定义:创建后状态不可改变的对象,天然线程安全
- 实现方式:所有字段声明为final,不提供修改状态的方法
- 上风:无需同步机制,简化并发编程,减少错误
- 应用场景:配置信息、常量数据、值对象、不可变集合
- 范围性:每次修改必要创建新对象,可能增加内存压力
- 示例:String、Integer、BigDecimal、不可变集合
9.3.2 线程当地存储
- 定义:为每个线程提供独立的变量副本,克制线程间共享
- 实现方式:ThreadLocal类,为每个线程维护独立的变量副本
- 上风:克制同步开销,提高并发性能
- 应用场景:用户上下文、事务上下文、哀求上下文
- 注意事项:必要及时清理,克制内存走漏
- 示例:用户认证信息、数据库毗连、格式化工具
9.3.3 线程封闭
- 定义:将数据限制在单个线程内,克制共享
- 实现方式:局部变量、ThreadLocal、线程内部对象
- 上风:无需同步机制,简化并发编程,提高性能
- 应用场景:线程内部计算、临时数据、中间效果
- 范围性:数据不能跨线程共享
- 示例:线程内部计算、临时数据、中间效果
9.4 并发编程最佳实践
9.4.1 计划原则
- 最小化共享:减少线程间共享的数据,降低同步需求
- 不可变性:优先使用不可变对象,克制同步问题
- 显式同步:使用显式的同步机制,克制隐式同步
- 线程封闭:将数据限制在单个线程内,克制共享
- 同步粒度:选择符合的同步粒度,平衡并发性和复杂性
- 克制活跃性伤害:克制死锁、饥饿、活锁等活跃性伤害
9.4.2 性能优化
- 减少锁竞争:减少锁的持偶然间,降低锁的粒度
- 使用无锁算法:在适用场景使用无锁算法,克制锁开销
- 使用线程池:使用线程池管理和复用线程,克制频繁创建和销毁
- 使用并发集合:使用并发集合代替同步集合,提高并发性能
- 使用原子操作:使用原子操作代替锁,减少同步开销
- 使用线程当地存储:使用线程当地存储克制共享,减少同步需求
9.4.3 调试与测试
- 死锁检测:使用工具检测死锁,如jstack、Thread Dump Analyzer
- 竞态条件检测:使用工具检测竞态条件,如FindBugs、ThreadSanitizer
- 并发测试:使用并发测试工具测试并发步伐,如JCStress、ConcurrentUnit
- 压力测试:使用压力测试工具测试并发步伐,如JMeter、Gatling
- 日记记录:记录关键操作的日记,资助调试并发问题
- 单元测试:编写单元测试验证并发步伐的精确性
10. 数据结构与内存管理
10.1 内存分配
10.1.1 静态分配
- 全局变量
- 定义:在步伐整个生命周期内存在的变量
- 特点:在步伐启动时分配,步伐结束时释放
- 存储位置:数据段(全局区)
- 访问方式:全局可见,所有函数均可访问
- 内存管理:由编译器自动管理,无需手动释放
- 应用场景:全局配置、常量数据、共享资源
- 静态变量
- 定义:使用static关键字声明的变量
- 特点:在步伐启动时分配,步伐结束时释放
- 存储位置:数据段(全局区)
- 作用域:仅在声明它的文件或函数内可见
- 内存管理:由编译器自动管理,无需手动释放
- 应用场景:函数内状态保持、模块级共享数据
- 常量
- 定义:使用const或final关键字声明的不可变数据
- 特点:值在编译时确定,运行时不可修改
- 存储位置:只读数据段(常量区)
- 内存管理:由编译器自动管理,无需手动释放
- 优化:编译器可能将常量内联到代码中
- 应用场景:配置参数、数学常数、字符串常量
- 代码段
- 定义:存储步伐指令的内存区域
- 特点:只读,不可修改
- 存储内容:步伐的可实验代码、函数体
- 内存管理:由操作体系管理,步伐结束时释放
- 优化:可能被多个进程共享,节省物理内存
- 应用场景:步伐代码、函数定义、内联函数
10.1.2 动态分配
- 堆内存
- 定义:用于动态分配的内存区域
- 特点:巨细不固定,生命周期由步伐控制
- 分配方式:malloc/free(C)、new/delete(C++)、垃圾接纳(Java)
- 内存管理:必要手动管理或由垃圾接纳器管理
- 碎片问题:可能导致内存碎片,必要碎片整理
- 应用场景:动态数据结构、大对象、长期存活的对象
- 栈内存
- 定义:用于存储函数调用和局部变量的内存区域
- 特点:后进先出(LIFO),自动分配和释放
- 分配方式:函数调用时自动分配,函数返回时自动释放
- 内存管理:由编译器自动管理,无需手动释放
- 巨细限制:通常较小,可能导致栈溢出
- 应用场景:函数调用、局部变量、参数传递
- 内存池
- 定义:预分配一块内存,然后从中分配小块内存
- 特点:减少内存分配和释放的开销,克制内存碎片
- 实现方式:固定巨细的块、可变巨细的块、分层池
- 内存管理:由步伐手动管理,必要显式释放
- 优化:适合频繁分配和释放相同巨细的对象
- 应用场景:对象池、毗连池、缓冲区管理
- 对象池
- 定义:预先创建对象,重复使用而不是频繁创建和销毁
- 特点:减少对象创建和垃圾接纳的开销
- 实现方式:空闲对象列表、对象状态管理
- 内存管理:由步伐手动管理,必要显式释放
- 优化:适合创建成本高、生命周期短的对象
- 应用场景:线程池、毗连池、字符串池、缓冲区池
10.2 内存接纳
10.2.1 手动接纳
- 显式释放
- 定义:步伐员手动调用释放函数接纳内存
- 实现方式:free(C)、delete(C++)、Dispose(C#)
- 优点:精确控制内存释放时机,无垃圾接纳开销
- 缺点:轻易导致内存走漏、悬空指针、重复释放
- 最佳实践:配对使用分配和释放函数,使用RAII模式
- 应用场景:C/C++步伐、资源管理、体系编程
- 资源池
- 定义:管理一组资源的分配和释放
- 实现方式:对象池、毗连池、内存池
- 优点:减少资源创建和销毁的开销,克制资源走漏
- 缺点:必要额外的管理开销,可能占用更多内存
- 最佳实践:根据实际需求调整池巨细,监控资源使用
- 应用场景:数据库毗连、网络毗连、线程管理
- 引用计数
- 定义:通过计数引用次数来管理对象生命周期
- 实现方式:增加引用时计数加1,减少引用时计数减1
- 优点:简单直观,可以及时接纳不再使用的对象
- 缺点:无法处理循环引用,计数操作开销大
- 最佳实践:结合其他垃圾接纳算法,处理循环引用
- 应用场景:COM组件、Python对象、智能指针
- 智能指针
- 定义:自动管理指针生命周期的包装类
- 实现方式:RAII模式,构造函数分配,析构函数释放
- 范例:unique_ptr(独占所有权)、shared_ptr(共享所有权)、weak_ptr(弱引用)
- 优点:自动管理内存,克制内存走漏
- 缺点:有一定的性能开销,可能影响代码可读性
- 应用场景:C++资源管理、非常安全、所有权管理
10.2.2 自动接纳
- 标记-清除算法
- 定义:标记所有可达对象,清除未标记对象
- 实现方式:从根对象开始遍历,标记所有可达对象
- 优点:简单直观,可以处理循环引用
- 缺点:必要停止步伐实验,可能产生内存碎片
- 优化:增量接纳、并发接纳、三色标记
- 应用场景:Java、Python、JavaScript等语言的垃圾接纳
- 复制算法
- 定义:将存活对象复制到新空间,释放旧空间
- 实现方式:将内存分为两个区域,瓜代使用
- 优点:无内存碎片,分配速率快
- 缺点:必要额外空间,存活对象多时开销大
- 优化:分代接纳、增量复制、并发复制
- 应用场景:新生代垃圾接纳、小对象接纳
- 分代接纳
- 定义:根据对象存活时间接纳差别的接纳策略
- 实现方式:将对象分为新生代和老年代,接纳差别算法
- 优点:针对差别生命周期对象接纳最优策略
- 缺点:实现复杂,必要额外开销
- 优化:增量接纳、并发接纳、混合接纳
- 应用场景:Java、.NET等当代语言的垃圾接纳
- 增量接纳
- 定义:将垃圾接纳过程分散到步伐实验过程中
- 实现方式:每次只接纳一部门内存,减少停顿时间
- 优点:减少步伐停顿时间,提高响应性
- 缺点:总体接纳时间可能增加,实现复杂
- 优化:并发接纳、混合接纳、自顺应接纳
- 应用场景:及时体系、交互式应用、服务器应用
10.3 内存优化
10.3.1 内存布局
- 数据对齐
- 定义:将数据存储在内存地址的特定界限上
- 目的:提高内存访问服从,满意硬件要求
- 实现方式:编译器自动对齐,手动指定对齐方式
- 优化:减少内存访问次数,提高缓存命中率
- 缺点:可能增加内存占用,产生填充字节
- 应用场景:结构体定义、数组访问、硬件交互
- 内存紧凑
- 定义:将分散的内存块整理成连续的内存块
- 目的:减少内存碎片,提高内存使用率
- 实现方式:移动对象,更新引用,压缩内存
- 优化:定期举行内存紧凑,减少碎片
- 缺点:必要额外开销,可能影响性能
- 应用场景:垃圾接纳、内存池管理、长期运行的步伐
- 内存映射
- 定义:将文件或设备映射到内存地址空间
- 目的:提高I/O服从,简化内存管理
- 实现方式:mmap体系调用,内存映射文件
- 优化:减少数据拷贝,提高访问速率
- 缺点:可能增加内存占用,必要管理映射生命周期
- 应用场景:大文件处理、共享内存、设备驱动
10.3.2 缓存优化
- 缓存友好数据结构
- 定义:计划适合缓存访问模式的数据结构
- 目的:提高缓存命中率,减少内存访问
- 实现方式:局部性原理,数据紧凑存储,预取数据
- 优化:减少缓存未命中,提高访问速率
- 缺点:可能增加实现复杂度,影响代码可读性
- 应用场景:高性能计算、图形处理、数据库体系
- 预取技能
- 定义:提前加载可能必要的数据到缓存
- 目的:减少缓存未命中,提高访问速率
- 实现方式:硬件预取,软件预取,数据流分析
- 优化:根据访问模式调整预取策略
- 缺点:可能加载不必要的数据,浪费带宽
- 应用场景:循环处理、顺序访问、数据流处理
- 数据局部性
- 定义:步伐倾向于访问最近访问过的数据附近的数据
- 范例:时间局部性(最近访问的数据很可能再次访问)、空间局部性(访问的数据附近的数据很可能被访问)
- 优化:使用局部性原理计划数据结构和算法
- 应用:循环优化、数据结构计划、算法优化
- 缺点:某些算法难以使用局部性
- 应用场景:矩阵运算、图像处理、数据库查询
10.3.3 内存池优化
- 固定巨细内存池
- 定义:预分配固定巨细的内存块,重复使用
- 目的:减少内存分配和释放的开销,克制碎片
- 实现方式:空闲列表,位图管理,分层池
- 优化:根据实际需求调整池巨细和块巨细
- 缺点:可能浪费内存,不适合变长数据
- 应用场景:对象池,毗连池,缓冲区管理
- 可变巨细内存池
- 定义:支持差别巨细的内存块的内存池
- 目的:灵活管理差别巨细的内存需求
- 实现方式:同伴体系,分层池,最佳适配算法
- 优化:根据实际需求调整池巨细和分配策略
- 缺点:管理复杂,可能有内部碎片
- 应用场景:通用内存管理,对象池,资源池
- 分层内存池
- 定义:将内存池分为多个层次,每层管理差别巨细的内存块
- 目的:高效管理差别巨细的内存需求
- 实现方式:每层使用差别的分配策略,层间协作
- 优化:根据实际需求调整各层巨细和策略
- 缺点:实现复杂,必要额外开销
- 应用场景:高性能内存管理,通用对象池,资源管理
10.4 内存管理策略
10.4.1 内存分配策略
- 首次适配
- 定义:分配第一个足够大的空闲块
- 优点:简单快速,适合小内存哀求
- 缺点:可能产生大量小碎片
- 实现:线性搜索空闲块列表
- 优化:结合其他策略,如最佳适配
- 应用场景:简单内存管理,小内存哀求
- 最佳适配
- 定义:分配最小的足够大的空闲块
- 优点:减少内存浪费,适合变长哀求
- 缺点:必要搜索整个空闲块列表,可能产生小碎片
- 实现:搜索所有空闲块,选择最小的足够大的块
- 优化:使用有序列表加速搜索
- 应用场景:通用内存管理,变长内存哀求
- 最差适配
- 定义:分配最大的空闲块
- 优点:减少小碎片,适合大内存哀求
- 缺点:可能浪费内存,大块可能很快用完
- 实现:搜索所有空闲块,选择最大的块
- 优化:使用有序列表加速搜索
- 应用场景:大内存哀求,减少碎片
- 同伴体系
- 定义:将内存分为巨细为2的幂的块,相邻的相同巨细的块称为同伴
- 优点:快速分配和释放,减少碎片
- 缺点:可能浪费内存,不适合变长哀求
- 实现:使用位图或链表管理空闲块
- 优化:结合其他策略,如分层管理
- 应用场景:操作体系内存管理,图形处理
10.4.2 内存接纳策略
- 引用计数
- 定义:通过计数引用次数来管理对象生命周期
- 优点:简单直观,可以及时接纳不再使用的对象
- 缺点:无法处理循环引用,计数操作开销大
- 实现:增加引用时计数加1,减少引用时计数减1
- 优化:结合其他垃圾接纳算法,处理循环引用
- 应用场景:COM组件,Python对象,智能指针
- 标记-清除
- 定义:标记所有可达对象,清除未标记对象
- 优点:可以处理循环引用,实现简单
- 缺点:必要停止步伐实验,可能产生内存碎片
- 实现:从根对象开始遍历,标记所有可达对象
- 优化:增量接纳,并发接纳,三色标记
- 应用场景:Java,Python,JavaScript等语言的垃圾接纳
- 复制接纳
- 定义:将存活对象复制到新空间,释放旧空间
- 优点:无内存碎片,分配速率快
- 缺点:必要额外空间,存活对象多时开销大
- 实现:将内存分为两个区域,瓜代使用
- 优化:分代接纳,增量复制,并发复制
- 应用场景:新生代垃圾接纳,小对象接纳
- 分代接纳
- 定义:根据对象存活时间接纳差别的接纳策略
- 优点:针对差别生命周期对象接纳最优策略
- 缺点:实现复杂,必要额外开销
- 实现:将对象分为新生代和老年代,接纳差别算法
- 优化:增量接纳,并发接纳,混合接纳
- 应用场景:Java,.NET等当代语言的垃圾接纳
10.4.3 内存管理最佳实践
- 内存走漏检测
- 定义:辨认和修复内存走漏问题
- 方法:静态分析,动态检测,内存分析工具
- 工具:Valgrind,AddressSanitizer,Memory Profiler
- 最佳实践:定期查抄,使用智能指针,配对使用分配和释放
- 常见问题:未释放资源,循环引用,非常处理不当
- 应用场景:C/C++步伐,资源管理,长期运行的步伐
- 内存碎片管理
- 定义:减少和管理内存碎片
- 方法:内存紧凑,内存池,同伴体系
- 工具:内存分析工具,碎片检测工具
- 最佳实践:使用符合的内存分配策略,定期整理内存
- 常见问题:外部碎片,内部碎片,碎片化严厉
- 应用场景:长期运行的步伐,内存受限体系,高性能应用
- 内存使用优化
- 定义:减少内存使用,提高内存服从
- 方法:数据结构优化,内存池,缓存优化
- 工具:内存分析工具,性能分析工具
- 最佳实践:选择符合的数据结构,克制冗余数据,及时释放不必要的内存
- 常见问题:内存使用过多,内存访问服从低,内存分配频繁
- 应用场景:资源受限体系,高性能应用,大规模数据处理
10.5 高级内存管理技能
10.5.1 假造内存
- 定义:将物理内存和磁盘空间结合,提供更大的地址空间
- 实现:页表,页错误,页面更换算法
- 优点:提供更大的地址空间,进程隔离,内存共享
- 缺点:可能影响性能,必要额外的硬件支持
- 页面更换算法:LRU,FIFO,Clock,工作集
- 应用场景:操作体系,大型应用,多进程体系
10.5.2 内存映射文件
- 定义:将文件映射到内存地址空间,直接访问文件内容
- 实现:mmap体系调用,内存映射文件
- 优点:减少数据拷贝,提高访问速率,简化文件操作
- 缺点:可能增加内存占用,必要管理映射生命周期
- 应用场景:大文件处理,数据库体系,图形处理
10.5.3 共享内存
- 定义:多个进程共享同一块内存区域
- 实现:共享内存段,内存映射文件,内存映射设备
- 优点:进程间高效通信,减少数据拷贝
- 缺点:必要同步机制,可能产生竞态条件
- 同步机制:信号量,互斥锁,条件变量
- 应用场景:进程间通信,数据共享,高性能计算
10.5.4 非统一内存访问(NUMA)
- 定义:多处理器体系中,内存访问时间取决于内存位置
- 实现:NUMA架构,当地内存,远程内存
- 优点:提高多处理器体系性能,减少内存访问瓶颈
- 缺点:必要特殊的内存分配策略,管理复杂
- 优化:当地内存分配,数据局部性,负载平衡
- 应用场景:高性能服务器,多处理器体系,大规模计算
11. 数据结构与数据库
11.1 索引结构
11.1.1 B+树索引
- 结构特点
- 多路平衡搜索树,所有数据存储在叶子节点
- 非叶子节点只存储键值,不存储数据
- 所有叶子节点通过链表相连,支持范围查询
- 树的高度较低,通常为3-4层
- 节点巨细通常为页巨细(如4KB或16KB)
- 支持前缀压缩,节省空间
- 操作服从
- 查找:O(log n),n为记录数
- 插入:O(log n),必要分裂节点
- 删除:O(log n),必要归并节点
- 范围查询:O(log n + k),k为效果集巨细
- 顺序访问:O(1),通过叶子节点链表
- 随机访问:O(log n),必要从根节点遍历
- 范围查询
- 支持高效的范围查询,如WHERE id BETWEEN 10 AND 20
- 通过叶子节点链表快速遍历范围内的所有记录
- 支持前缀范围查询,如WHERE name LIKE ‘John%’
- 支持多列范围查询,如复合索引(a, b, c)上的WHERE a=1 AND b BETWEEN 2 AND 5
- 支持排序操作,如ORDER BY id
- 支持分组操作,如GROUP BY id
- 前缀索引
- 只索引列的前缀部门,节省空间
- 适用于长字符串列,如VARCHAR(255)
- 前缀长度选择:区分度与空间服从的平衡
- 计算区分度:SELECT COUNT(DISTINCT LEFT(column, n)) / COUNT(*) FROM table
- 前缀索引限制:无法用于ORDER BY和GROUP BY
- 前缀索引优化:根据实际查询模式选择符合的前缀长度
11.1.2 哈希索引
- 精确匹配
- 支持O(1)的精确匹配查询,如WHERE id = 10
- 适用于等值查询,如=, IN, IS NULL
- 不支持范围查询,如>, <, BETWEEN, LIKE
- 不支持排序操作,如ORDER BY
- 不支持前缀查询,如LIKE ‘John%’
- 适用于主键索引和唯一索引
- 冲突处理
- 开放寻址法:线性探测、二次探测、双重哈希
- 链地址法:使用链表存储冲突的元素
- 再哈希法:使用多个哈希函数
- 动态扩容:当负载因子超过阈值时扩容
- 冲突影响:降低查询性能,增加空间开销
- 优化策略:选择符合的哈希函数,控制负载因子
- 动态扩容
- 触发条件:负载因子超过阈值(通常为0.75)
- 扩容策略:容量翻倍,重新哈希所有元素
- 扩容开销:必要重新计算所有元素的哈希值
- 渐进式扩容:分批迁徙数据,减少停顿时间
- 收缩策略:当负载因子低于阈值时收缩
- 优化:预分配足够空间,克制频繁扩容
- 性能优化
- 哈希函数选择:均匀分布,计算快速
- 负载因子控制:平衡空间使用率和冲突率
- 冲突处理策略:根据实际场景选择符合的策略
- 局部性优化:使用CPU缓存,提高访问服从
- 并发控制:支持高并发访问,减少锁竞争
- 内存管理:高效的内存分配和接纳策略
11.1.3 位图索引
- 结构特点
- 为每个可能的值创建一个位图
- 每个位表示一行是否包含该值
- 支持高效的位操作,如AND, OR, NOT
- 适用于低基数列,如性别、状态、标记位
- 空间服从高,特别是对于稀疏数据
- 支持快速统计和聚合操作
- 操作服从
- 等值查询:O(1),直接访问对应位图
- 范围查询:O(k),k为范围内的值数量
- 多条件查询:通过位操作高效组合多个条件
- 统计操作:O(1),通过位计数快速统计
- 更新操作:必要更新多个位图,开销较大
- 空间开销:与列的基数成正比,与行数成正比
- 应用场景
- 数据堆栈:OLAP查询,统计分析
- 低基数列:性别、状态、标记位、种别
- 多条件查询:必要组合多个条件的查询
- 统计查询:COUNT, SUM, AVG等聚合操作
- 稀疏数据:大多数值为NULL或默认值的数据
- 及时分析:必要快速响应的分析查询
- 优化策略
- 压缩技能:游程编码,位图压缩
- 分段存储:将大位图分段存储,减少内存压力
- 缓存优化:使用CPU缓存,提高访问服从
- 并行处理:支持并行位操作,提高性能
- 增量更新:支持增量更新,减少更新开销
- 混合索引:结合B+树索引,平衡查询和更新性能
11.1.4 全文索引
- 结构特点
- 基于倒排索引,存储词项到文档的映射
- 支持文本搜索,如LIKE ‘%keyword%’
- 支持暗昧匹配,如拼写错误、同义词
- 支持相干性排序,如TF-IDF, BM25
- 支持分词和停用词处理
- 支持多语言和特殊字符处理
- 操作服从
- 关键词查询:O(log n),n为词项数量
- 短语查询:O(k * log n),k为短语中的词项数量
- 暗昧查询:O(m * log n),m为候选词项数量
- 相干性排序:O(r * log r),r为效果集巨细
- 更新操作:必要重修索引或增量更新
- 空间开销:通常为原文本巨细的1-3倍
- 应用场景
- 搜索引擎:全文搜索,相干性排序
- 内容管理:文档搜索,内容检索
- 日记分析:日记搜索,问题诊断
- 知识库:问答体系,知识检索
- 电子商务:商品搜索,形貌匹配
- 交际媒体:内容搜索,话题发现
- 优化策略
- 分词优化:选择符合的分词算法,处理特殊字符
- 索引压缩:压缩倒排索引,减少空间开销
- 缓存优化:缓存常用查询效果,提高响应速率
- 并行处理:支持并行搜索,提高吞吐量
- 增量更新:支持增量索引更新,减少重修开销
- 混合索引:结合B+树索引,平衡精确匹配和暗昧匹配
11.1.5 LSM树
- 结构特点
- 分层存储结构,内存层和磁盘层
- 内存层:跳表或B树,支持快速写入
- 磁盘层:多个有序文件,定期归并
- 写入操作:先写入内存,到达阈值后刷盘
- 读取操作:必要查询内存和多个磁盘文件
- 支持高效的写入和范围查询
- 操作服从
- 写入操作:O(log n),n为内存层巨细
- 读取操作:O(log n + k),k为磁盘层文件数量
- 范围查询:O(log n + k + r),r为效果集巨细
- 空间放大:由于重复数据,空间开销较大
- 写入放大:由于归并操作,实际写入量大于逻辑写入量
- 读取放大:由于必要查询多个文件,实际读取量大于逻辑读取量
- 应用场景
- 日记体系:高吞吐量写入,如WAL
- 时序数据库:时间序列数据,如InfluxDB
- 键值存储:高性能键值存储,如LevelDB, RocksDB
- 搜索引擎:倒排索引存储,如Elasticsearch
- 消息队列:消息存储,如Kafka
- 区块链:区块和交易存储
- 优化策略
- 归并策略:选择符合的归并策略,平衡写入和读取性能
- 压缩技能:压缩磁盘文件,减少空间开销
- 布隆过滤器:减少不须要的磁盘读取
- 缓存优化:缓存热点数据,提高读取性能
- 并行处理:支持并行归并,提高吞吐量
- 分层计划:根据数据访问模式计划差别层级的存储策略
11.1.6 R树
- 结构特点
- 多维空间索引,用于地理数据和空间数据
- 将空间对象分组为最小外接矩形(MBR)
- 非叶子节点存储MBR和子节点指针
- 叶子节点存储MBR和实际对象
- 支持高效的空间查询,如范围查询、最近邻查询
- 适用于二维和三维空间数据
- 操作服从
- 点查询:O(log n),n为对象数量
- 范围查询:O(log n + k),k为效果集巨细
- 最近邻查询:O(log n)
- 插入操作:O(log n),可能必要分裂节点
- 删除操作:O(log n),可能必要归并节点
- 空间开销:与数据分布和MBR重叠水平相干
- 应用场景
- 地理信息体系:地图数据,位置服务
- 空间数据库:空间数据存储和查询
- 计算机图形学:碰撞检测,视锥体裁剪
- 游戏开发:空间分区,对象查询
- 物联网:传感器数据,位置追踪
- 数据可视化:空间数据可视化
- 优化策略
- 节点分裂策略:选择符合的分裂策略,减少MBR重叠
- 节点归并策略:选择符合的归并策略,减少节点数量
- 批量加载:支持批量构建索引,提高构建服从
- 并行处理:支持并行查询和构建,提高性能
- 压缩技能:压缩MBR,减少空间开销
- 缓存优化:缓存热点数据,提高访问服从
11.2 查询优化
11.2.1 实验筹划
- 索引选择
- 基于统计信息选择最优索引
- 思量索引的选择性、覆盖度和排序需求
- 支持多索引扫描和索引归并
- 支持索引下推,减少回表操作
- 支持索引跳跃扫描,减少索引扫描范围
- 支持自顺应索引选择,根据运行时统计调整
- 毗连顺序
- 选择最优的毗连顺序,减少中间效果集巨细
- 思量表的巨细、选择性、毗连条件和可用索引
- 支持动态规划算法选择最优毗连顺序
- 支持贪默算法快速选择次优毗连顺序
- 支持毗连重排序,优化多表毗连
- 支持子查询优化,将子查询转换为毗连
- 过滤条件
- 选择最优的过滤条件顺序,尽早过滤无关数据
- 支持条件重排序,将高选择性条件提前
- 支持条件归并,减少重复计算
- 支持条件推导,推导出隐含条件
- 支持条件消除,消除冗余条件
- 支持条件简化,简化复杂条件
- 排序方式
- 选择最优的排序方式,使用索引或内存排序
- 支持索引排序,克制额外的排序操作
- 支持内存排序,适用于小效果集
- 支持外部排序,适用于大效果集
- 支持并行排序,提高排序性能
- 支持部门排序,只排序须要的数据
11.2.2 性能调优
- 索引优化
- 创建符合的索引,覆盖常用查询模式
- 克制冗余索引,减少维护开销
- 定期维护索引,如重修、碎片整理
- 监控索引使用环境,删除未使用的索引
- 优化索引结构,如复合索引、前缀索引
- 使用覆盖索引,减少回表操作
- 查询重写
- 重写复杂查询,简化实验筹划
- 将子查询转换为毗连或派生表
- 消除冗余操作,如重复计算、重复过滤
- 优化聚合操作,如提前过滤、预聚合
- 优化分页查询,如键集分页、游标分页
- 优化暗昧查询,如前缀匹配、全文搜索
- 统计信息
- 收集和维护准确的统计信息
- 统计表巨细、行数、列分布、索引使用环境
- 支持直方图,更精确地表示数据分布
- 支持增量统计,减少统计开销
- 支持自动统计更新,保持统计信息最新
- 支持统计信息采样,减少统计开销
- 缓存策略
- 使用查询缓存,缓存常用查询效果
- 使用效果集缓存,缓存中间效果
- 使用数据缓存,缓存热点数据
- 使用索引缓存,缓存索引页
- 使用缓冲池,缓存数据页
- 使用内存表,将小表加载到内存
11.2.3 并行查询
- 并行扫描
- 并行扫描表数据,提高扫描性能
- 支持分区并行扫描,每个分区一个线程
- 支持分块并行扫描,每个块一个线程
- 支持动态并行度,根据体系负载调整
- 支持并行过滤,并行处理过滤条件
- 支持并行投影,并行处理投影操作
- 并行毗连
- 并行实验毗连操作,提高毗连性能
- 支持分区并行毗连,每个分区一个线程
- 支持分块并行毗连,每个块一个线程
- 支持哈希并行毗连,并行处理哈希毗连
- 支持嵌套循环并行毗连,并行处理嵌套循环毗连
- 支持排序归并并行毗连,并行处理排序归并毗连
- 并行聚合
- 并行实验聚合操作,提高聚合性能
- 支持分组并行聚合,每个分组一个线程
- 支持分块并行聚合,每个块一个线程
- 支持两阶段聚合,先局部聚合再全局聚合
- 支持近似聚合,如HyperLogLog、Count-Min Sketch
- 支持增量聚合,支持流式处理
- 负载平衡
- 平衡分配工作负载,克制热点
- 支持动态负载平衡,根据节点负载调整
- 支持自顺应并行度,根据数据分布调整
- 支持工作窃取,空闲线程从忙线程窃取工作
- 支持流水线并行,减少线程同步开销
- 支持混归并行,结合差别并行策略
11.2.4 查询优化器
- 代价模型
- 基于统计信息和代价模型选择最优实验筹划
- 思量CPU代价、I/O代价、内存代价、网络代价
- 支持自定义代价函数,顺应特定场景
- 支持动态代价调整,根据运行时统计调整
- 支持多目的优化,平衡性能和资源斲丧
- 支持启发式规则,快速选择次优筹划
- 筹划枚举
- 枚举可能的实验筹划,选择最优筹划
- 支持动态规划算法,包管最优筹划
- 支持贪默算法,快速选择次优筹划
- 支持随机筹划,探索更多可能性
- 支持筹划缓存,重用常用筹划
- 支持筹划自顺应,根据运行时统计调整
- 筹划转换
- 转换实验筹划,优化实验服从
- 支持筹划重排序,优化操作顺序
- 支持筹划归并,归并相似操作
- 支持计分别解,分解复杂操作
- 支持筹划重写,简化复杂筹划
- 支持筹划验证,确保筹划精确性
- 自顺应优化
- 根据运行时统计自顺应调整实验筹划
- 支持筹划监控,收集运行时统计
- 支持筹划调整,根据统计调整筹划
- 支持筹划切换,在多个筹划间切换
- 支持筹划学习,从汗青实验中学习
- 支持筹划预测,预测将来实验环境
11.3 事务处理
11.3.1 ACID特性
- 原子性(Atomicity)
- 定义:事务是不可分割的工作单位,要么全部实验,要么全部不实验
- 实现:通过日记和回滚机制包管
- 日记范例:重做日记(Redo Log)、撤销日记(Undo Log)
- 回滚机制:事务回滚、体系回滚、查抄点回滚
- 故障规复:体系故障、事务故障、介质故障
- 应用场景:资金转账、库存管理、订单处理
- 一致性(Consistency)
- 定义:事务实验前后,数据库从一个一致性状态变到另一个一致性状态
- 实现:通过束缚、触发器、应用步伐逻辑包管
- 束缚范例:实体完整性、参照完整性、用户定义完整性
- 触发器:行级触发器、语句级触发器、替换触发器
- 应用步伐逻辑:业务规则、数据验证、状态转换
- 应用场景:数据验证、业务规则、状态管理
- 隔离性(Isolation)
- 定义:多个事务并发实验时,一个事务的实验不应影响其他事务
- 实现:通过锁机制、多版本并发控制(MVCC)包管
- 隔离级别:读未提交、读已提交、可重复读、串行化
- 锁范例:共享锁、排他锁、意向锁、间隙锁
- 锁粒度:行级锁、表级锁、页级锁、数据库级锁
- 应用场景:并发访问、数据一致性、克制脏读
- 持久性(Durability)
- 定义:事务一旦提交,其效果应永世保存在数据库中
- 实现:通过日记和查抄点机制包管
- 日记范例:重做日记、撤销日记、二进制日记
- 日记策略:先写日记、后写数据、WAL(Write-Ahead Logging)
- 查抄点机制:定期将脏页刷新到磁盘,减少规复时间
- 应用场景:数据持久化、故障规复、数据备份
11.3.2 并发控制
- 锁机制
- 定义:通过锁控制并发访问,包管数据一致性
- 锁范例:共享锁(读锁)、排他锁(写锁)、意向锁、间隙锁
- 锁粒度:行级锁、表级锁、页级锁、数据库级锁
- 锁模式:乐观锁、灰心锁、自顺应锁
- 锁升级:锁升级策略,减少锁冲突
- 死锁处理:死锁检测、死锁预防、死锁克制
- 多版本并发控制(MVCC)
- 定义:通过维护多个版本的数据实现并发控制
- 实现:版本链、快照读、当前读
- 版本管理:版本创建、版本清理、版本可见性
- 快照隔离:基于时间戳的快照隔离、基于版本的快照隔离
- 优点:读不壅闭写,写不壅闭读,提高并发性
- 缺点:空间开销大,必要定期清理旧版本
- 时间戳排序
- 定义:通逾期间戳决定事务的实验顺序
- 实现:为每个事务分配唯一的时间戳
- 规则:如果事务A的时间戳小于事务B的时间戳,则A先实验
- 冲突处理:通过回滚和重试处理冲突
- 优点:无需锁机制,减少死锁
- 缺点:可能导致大量回滚,影响性能
- 乐观并发控制
- 定义:假设冲突很少发生,在提交时查抄冲突
- 实现:版本号、时间戳、校验和
- 冲突检测:比较版本号或时间戳,检测冲突
- 冲突办理:回滚和重试、归并更改、手动办理
- 优点:无锁机制,高并发性,适合读多写少场景
- 缺点:冲突多时性能下降,必要额外的冲突办理机制
11.3.3 规复机制
- 日记规复
- 定义:通过日记规复数据库到一致状态
- 日记范例:重做日记、撤销日记、二进制日记
- 规复策略:前滚规复、回滚规复、查抄点规复
- 日记记录:物理日记、逻辑日记、生理日记
- 日记缓冲区:日记缓冲区管理、日记刷新策略
- 日记归档:日记归档策略、日记清理策略
- 查抄点机制
- 定义:定期将脏页刷新到磁盘,减少规复时间
- 查抄点范例:完全查抄点、增量查抄点、暗昧查抄点
- 查抄点触发:时间触发、日记巨细触发、手动触发
- 查抄点过程:暂停担当新事务、等候活动事务完成、刷新脏页、记录查抄点
- 查抄点优化:并行查抄点、增量查抄点、异步查抄点
- 规复优化:从最近查抄点开始规复,减少规复时间
- 故障规复
- 定义:在体系故障后规复数据库到一致状态
- 故障范例:体系故障、事务故障、介质故障
- 规复策略:前滚规复、回滚规复、介质规复
- 规复过程:分析阶段、重做阶段、回滚阶段
- 规复优化:并行规复、增量规复、选择性规复
- 规复工具:规复管理器、规复向导、规复脚本
- 备份规复
- 定义:通过备份规复数据库到指定状态
- 备份范例:完全备份、增量备份、差异备份
- 备份策略:定期备份、及时备份、连续备份
- 规复策略:完全规复、时间点规复、选择性规复
- 备份优化:并行备份、压缩备份、增量备份
- 规复优化:并行规复、选择性规复、快速规复
11.3.4 分布式事务
- 两阶段提交(2PC)
- 定义:和谐者和参与者两阶段提交协议
- 阶段:准备阶段、提交阶段
- 参与者:实验事务,但不提交
- 和谐者:收集参与者效果,决定提交或回滚
- 优点:包管原子性,适用于强一致性场景
- 缺点:同步壅闭、单点问题、数据不一致
- 三阶段提交(3PC)
- 定义:在2PC底子上增加预提交阶段
- 阶段:准备阶段、预提交阶段、提交阶段
- 参与者:实验事务,预提交事务
- 和谐者:收集参与者效果,决定预提交或回滚
- 优点:减少壅闭,提高可用性
- 缺点:仍然存在单点问题,网络分区时可能不一致
- 最终一致性
- 定义:允许暂时不一致,最终到达一致状态
- 实现:变乱溯源、CQRS、Saga模式
- 策略:赔偿事务、重试机制、冲突办理
- 优点:高可用性,高性能,适合分布式体系
- 缺点:暂时不一致,必要额外的和谐机制
- 应用场景:电子商务、交际媒体、物联网
- 分布式事务框架
- 定义:提供分布式事务支持的框架
- 实现:Seata、TCC-Transaction、ByteTCC
- 模式:AT模式、TCC模式、Saga模式、XA模式
- 功能:事务管理、和谐器、参与者、资源管理器
- 优点:简化分布式事务开发,提供多种模式
- 缺点:增加体系复杂度,必要额外的组件
11.4 数据库计划
11.4.1 数据模型
- 关系模型
- 定义:基于表的数据模型,表由行和列组成
- 特点:结构化数据,支持SQL查询,强一致性
- 概念:表、行、列、主键、外键、束缚
- 范式:第一范式、第二范式、第三范式、BCNF
- 优点:成熟稳固,支持复杂查询,强一致性
- 缺点:扩展性有限,不适合非结构化数据
- 文档模型
- 定义:基于文档的数据模型,文档是自包含的数据单元
- 特点:半结构化数据,支持嵌套和数组,灵活模式
- 概念:文档、集合、字段、嵌入文档、数组
- 存储:JSON、BSON、XML
- 优点:灵活模式,适合快速迭代,支持复杂对象
- 缺点:查询本领有限,不支持复杂毗连
- 图模型
- 定义:基于图的数据模型,数据由节点和边组成
- 特点:关系麋集型数据,支持复杂关系查询
- 概念:节点、边、属性、标签、方向
- 查询:图遍历、路径查询、模式匹配
- 优点:高效的关系查询,直观的数据表示
- 缺点:不适合大规模数据,查询语言不成熟
- 列族模型
- 定义:基于列族的数据模型,按列存储数据
- 特点:分析型数据,支持高效聚合和扫描
- 概念:行键、列族、列限定符、时间戳、单元格
- 存储:按列族存储,支持版本控制
- 优点:高效的分析查询,高压缩率
- 缺点:不适合事务处理,更新性能差
11.4.2 数据库范式
- 第一范式(1NF)
- 定义:表中的每个字段都是原子的,不可再分
- 特点:消除重复组,每个字段只有一个值
- 示例:将地址拆分为省、市、区、街道
- 优点:简化数据结构,减少数据冗余
- 缺点:可能增加表数量,增加毗连操作
- 应用场景:底子数据规范化,消除重复组
- 第二范式(2NF)
- 定义:在1NF底子上,非主键字段完全依赖于主键
- 特点:消除部门依赖,非主键字段依赖于整个主键
- 示例:订单明细表中的商品名称依赖于商品ID
- 优点:减少数据冗余,提高数据一致性
- 缺点:增加表数量,增加毗连操作
- 应用场景:消除部门依赖,提高数据一致性
- 第三范式(3NF)
- 定义:在2NF底子上,非主键字段不依赖于其他非主键字段
- 特点:消除传递依赖,非主键字段只依赖于主键
- 示例:学生表中的班级名称依赖于班级ID
- 优点:减少数据冗余,提高数据一致性
- 缺点:增加表数量,增加毗连操作
- 应用场景:消除传递依赖,提高数据一致性
- 巴斯-科德范式(BCNF)
- 定义:在3NF底子上,所有决定因素都是候选键
- 特点:消除所有依赖,包管数据完整性
- 示例:课程表中的教师只能教授一门课程
- 优点:最高级别的规范化,包管数据完整性
- 缺点:过分规范化,增加体系复杂度
- 应用场景:严格要求数据完整性的场景
11.4.3 反范式化
- 定义
- 定义:故意违背数据库范式,增加数据冗余
- 目的:提高查询性能,减少毗连操作
- 策略:增加冗余字段,归并表,预计算
- 权衡:性能与数据一致性、存储空间与查询服从
- 场景:读多写少、复杂查询、性能敏感
- 风险:数据不一致、更新非常、维护困难
- 冗余字段
- 定义:在表中增加冗余字段,减少毗连操作
- 示例:订单表中增加商品名称字段
- 优点:减少毗连操作,提高查询性能
- 缺点:数据冗余,更新非常
- 策略:只冗余频繁查询的字段,保持适度冗余
- 应用场景:读多写少、查询性能敏感
- 预计算
- 定义:预先计算和存储计算效果,减少运行时计算
- 示例:订单表中增加订单总金额字段
- 优点:减少运行时计算,提高查询性能
- 缺点:数据冗余,更新开销大
- 策略:只预计算频繁查询的效果,保持适度预计算
- 应用场景:复杂计算、聚合查询、报表生成
- 归并表
- 定义:将多个表归并为一个表,减少毗连操作
- 示例:将用户表和用户详情表归并
- 优点:减少毗连操作,提高查询性能
- 缺点:表结构复杂,更新非常
- 策略:只归并频繁一起查询的表,保持适度归并
- 应用场景:频繁毗连、查询性能敏感
11.4.4 分区策略
- 水平分区
- 定义:按行将表分割到多个分区中
- 策略:范围分区、哈希分区、列表分区、复合分区
- 优点:提高查询性能,简化管理,支持并行处理
- 缺点:跨分区查询性能差,分区键选择困难
- 场景:大表、时间序列数据、地理数据
- 管理:分区维护、分区迁徙、分区归并
- 垂直分区
- 定义:按列将表分割到多个分区中
- 策略:按访问频率分区、按数据范例分区
- 优点:减少I/O,提高缓存服从,支持并行处理
- 缺点:必要毗连操作,管理复杂
- 场景:宽表、差别列访问模式差异大
- 管理:分区维护、分区迁徙、分区归并
- 分片策略
- 定义:将数据分散到多个数据库实例中
- 策略:范围分片、哈希分片、列表分片、复合分片
- 优点:支持水平扩展,提高并发处理本领
- 缺点:跨分片查询复杂,事务处理困难
- 场景:大规模数据、高并发、地理分布
- 管理:分片维护、分片迁徙、分片归并
- 复制策略
- 定义:将数据复制到多个数据库实例中
- 策略:主从复制、多主复制、环形复制
- 优点:提高可用性,支持读写分离,支持地理分布
- 缺点:数据一致性挑战,复制延长
- 场景:高可用性要求、读写分离、地理分布
- 管理:复制维护、故障转移、数据同步
12. 数据结构与网络编程
12.1 网络协议
12.1.1 协议实现
- 数据包
- 定义:网络传输的基本单位,包含头部和数据部门
- 结构:包头(协议信息)+ 负载(实际数据)
- 处理流程:封装、传输、解封装、处理
- 数据结构:链表、环形缓冲区、内存池
- 优化:内存对齐、数据压缩、分片重组
- 应用:TCP/IP协议栈、自定义协议、及时通信
- 缓冲区
- 定义:用于存储和管理网络数据的连续内存区域
- 范例:固定巨细缓冲区、动态缓冲区、环形缓冲区
- 操作:写入、读取、清空、扩容、收缩
- 管理:内存池、垃圾接纳、引用计数
- 优化:零拷贝、内存对齐、预分配
- 应用:网络I/O、数据流处理、消息队列
- 队列
- 定义:用于管理网络消息的有序集合
- 范例:FIFO队列、优先级队列、延长队列
- 实现:链表、数组、堆、跳表
- 操作:入队、出队、查看、清空、巨细
- 优化:无锁队列、批量处理、内存池
- 应用:消息队列、哀求队列、响应队列
- 定时器
- 定义:用于管理网络变乱的时间调度机制
- 范例:一次性定时器、周期性定时器、延长定时器
- 实现:堆、链表、时间轮、红黑树
- 操作:启动、停止、重置、回调
- 优化:批量处理、分层时间轮、低精度定时器
- 应用:超时处理、心跳检测、重传机制
12.1.2 性能优化
- 零拷贝
- 定义:减少数据在内核空间和用户空间之间的拷贝次数
- 技能:mmap、sendfile、splice、DMA
- 实现:直接内存访问、内存映射、共享内存
- 上风:减少CPU开销、减少内存带宽、提高吞吐量
- 限制:硬件支持、操作体系支持、应用场景
- 应用:文件传输、网络署理、流媒体
- 内存池
- 定义:预分配一块内存,然后从中分配小块内存
- 范例:固定巨细内存池、可变巨细内存池、分层内存池
- 实现:空闲列表、位图管理、同伴体系
- 上风:减少内存分配和释放的开销,克制内存碎片
- 优化:内存对齐、预分配、接纳策略
- 应用:网络缓冲区、对象池、毗连池
- 线程池
- 定义:管理和复用线程的机制,克制频繁创建和销毁线程
- 范例:固定巨细线程池、缓存线程池、调度线程池
- 实现:任务队列、工作线程、线程工厂
- 上风:减少线程创建和销毁的开销,控制并发度
- 优化:任务优先级、任务分组、负载平衡
- 应用:网络服务器、并发处理、异步操作
- 异步IO
- 定义:非壅闭的I/O操作,允许步伐在等候I/O完成时实验其他任务
- 模型:变乱驱动模型、回调模型、Future模型
- 实现:select、poll、epoll、kqueue、IOCP
- 上风:提高并发处理本领,减少线程开销
- 优化:变乱批处理、变乱归并、变乱优先级
- 应用:高并发服务器、及时通信、流处理
12.2 网络应用
12.2.1 服务器实现
- 毗连池
- 定义:管理和复用网络毗连的机制
- 范例:固定巨细毗连池、动态毗连池、分层毗连池
- 实现:空闲毗连列表、毗连状态管理、毗连工厂
- 操作:获取毗连、释放毗连、创建毗连、销毁毗连
- 优化:毗连预热、毗连保活、毗连超时
- 应用:数据库毗连、HTTP毗连、RPC毗连
- 会话管理
- 定义:管理客户端和服务器之间的会话状态
- 范例:无状态会话、有状态会话、分布式会话
- 实现:会话表、会话超时、会话规复
- 存储:内存、数据库、分布式缓存
- 优化:会话压缩、会话共享、会话迁徙
- 应用:Web应用、游戏服务器、即时通讯
- 消息队列
- 定义:用于服务器内部组件之间的消息传递
- 范例:点对点队列、发布订阅队列、优先级队列
- 实现:内存队列、持久化队列、分布式队列
- 操作:发送消息、接收消息、过滤消息、路由消息
- 优化:消息批处理、消息压缩、消息优先级
- 应用:组件通信、变乱处理、任务调度
- 变乱循环
- 定义:处理网络变乱的主循环,如毗连、数据、超时
- 模型:Reactor模型、Proactor模型、多Reactor模型
- 实现:变乱分发器、变乱处理器、定时器
- 优化:变乱批处理、变乱归并、变乱优先级
- 扩展:多线程变乱循环、多进程变乱循环
- 应用:网络服务器、游戏服务器、及时通信
12.2.2 客户端实现
- 哀求队列
- 定义:管理客户端发送的哀求的有序集合
- 范例:FIFO队列、优先级队列、延长队列
- 实现:链表、数组、堆、跳表
- 操作:添加哀求、发送哀求、取消哀求、清空队列
- 优化:哀求归并、哀求压缩、哀求优先级
- 应用:HTTP客户端、RPC客户端、消息客户端
- 响应缓存
- 定义:缓存服务器响应,减少重复哀求
- 范例:内存缓存、磁盘缓存、分布式缓存
- 策略:LRU、LFU、FIFO、TTL
- 实现:哈希表、LRU缓存、分层缓存
- 优化:缓存预热、缓存更新、缓存失效
- 应用:Web浏览器、API客户端、数据客户端
- 重试机制
- 定义:在哀求失败时自动重试的机制
- 策略:固定重试、指数退避、自定义重试
- 参数:重试次数、重试隔断、重试条件
- 实现:重试器、重试策略、重试上下文
- 优化:智能重试、部门重试、熔断机制
- 应用:网络客户端、RPC客户端、消息客户端
- 负载平衡
- 定义:将哀求分发到多个服务器,提高体系可用性和性能
- 策略:轮询、加权轮询、最少毗连、哈希、随机
- 范例:客户端负载平衡、服务器负载平衡、全局负载平衡
- 实现:负载平衡器、健康查抄、故障转移
- 优化:动态权重、会话保持、地理位置感知
- 应用:Web服务、微服务、分布式体系
12.3 网络数据结构
12.3.1 协议数据结构
- 协议头
- 定义:包含协议控制信息的头部结构
- 字段:版本、范例、长度、校验和、序列号
- 格式:固定长度、可变长度、TLV格式
- 处理:剖析、验证、生成、修改
- 优化:内存对齐、字段压缩、位操作
- 应用:TCP/IP协议、HTTP协议、自定义协议
- 消息格式
- 定义:网络消息的数据格式和结构
- 范例:二进制格式、文本格式、混合格式
- 编码:JSON、XML、Protocol Buffers、MessagePack
- 处理:序列化、反序列化、验证、转换
- 优化:压缩、批处理、增量更新
- 应用:RPC、消息队列、Web API
- 数据包分片
- 定义:将大数据包分割成多个小数据包传输
- 策略:固定巨细分片、动态巨细分片、路径MTU分片
- 字段:分片ID、分片偏移、分片标记、分片巨细
- 处理:分片、重组、超时处理、丢失处理
- 优化:选择性确认、快速重传、拥塞控制
- 应用:大文件传输、流媒体、及时通信
12.3.2 网络缓冲区
- 发送缓冲区
- 定义:用于存储待发送数据的缓冲区
- 范例:固定巨细缓冲区、动态缓冲区、环形缓冲区
- 操作:写入、发送、清空、扩容、收缩
- 管理:内存池、垃圾接纳、引用计数
- 优化:零拷贝、内存对齐、预分配
- 应用:TCP发送、UDP发送、自定义协议发送
- 接收缓冲区
- 定义:用于存储接收到的数据的缓冲区
- 范例:固定巨细缓冲区、动态缓冲区、环形缓冲区
- 操作:接收、读取、清空、扩容、收缩
- 管理:内存池、垃圾接纳、引用计数
- 优化:零拷贝、内存对齐、预分配
- 应用:TCP接收、UDP接收、自定义协议接收
- 应用缓冲区
- 定义:用于应用步伐处理数据的缓冲区
- 范例:固定巨细缓冲区、动态缓冲区、环形缓冲区
- 操作:写入、读取、清空、扩容、收缩
- 管理:内存池、垃圾接纳、引用计数
- 优化:零拷贝、内存对齐、预分配
- 应用:数据处理、消息处理、协议处理
12.4 网络算法
12.4.1 路由算法
- 最短路径算法
- 定义:计算网络中两点之间的最短路径
- 算法:Dijkstra算法、Bellman-Ford算法、Floyd-Warshall算法
- 实现:邻接矩阵、邻接表、优先队列
- 优化:双向搜索、启发式搜索、并行计算
- 应用:路由表生成、网络规划、路径选择
- 变体:多束缚最短路径、k最短路径、动态最短路径
- 距离向量路由
- 定义:基于距离向量的路由算法,如RIP
- 原理:每个节点维护到其他节点的距离向量
- 更新:定期互换距离向量,更新路由表
- 收敛:慢收敛、路由环路、无穷计数
- 优化:水平分割、毒性逆转、触发更新
- 应用:小型网络、简单拓扑、静态路由
- 链路状态路由
- 定义:基于链路状态的路由算法,如OSPF
- 原理:每个节点维护整个网络的拓扑信息
- 更新:泛洪链路状态信息,计算最短路径
- 收敛:快速收敛、无路由环路、精确路由
- 优化:区域分别、层次结构、增量更新
- 应用:大型网络、复杂拓扑、动态路由
12.4.2 拥塞控制
- TCP拥塞控制
- 定义:控制TCP发送速率,克制网络拥塞
- 算法:慢启动、拥塞克制、快重传、快规复
- 参数:拥塞窗口、慢启动阈值、往返时间
- 变体:TCP Tahoe、TCP Reno、TCP NewReno、TCP CUBIC
- 优化:BBR、TCP Vegas、TCP Westwood
- 应用:可靠传输、流量控制、带宽使用
- 自动队列管理
- 定义:路由器自动管理队列,克制缓冲区溢出
- 算法:RED、WRED、CoDel、PIE
- 参数:队列长度、扬弃概率、标记概率
- 优化:自顺应参数、多队列管理、优先级队列
- 应用:路由器、互换机、网络设备
- 效果:减少列队延长、提高吞吐量、公平性
12.4.3 负载平衡算法
- 静态负载平衡
- 定义:基于固定规则的负载平衡算法
- 算法:轮询、加权轮询、哈希、随机
- 实现:负载平衡器、服务器列表、选择策略
- 优点:简单、高效、可预测
- 缺点:不思量服务器负载、不顺应厘革
- 应用:简单场景、静态配置、低厘革环境
- 动态负载平衡
- 定义:基于及时信息的负载平衡算法
- 算法:最少毗连、加权最少毗连、响应时间、CPU负载
- 实现:负载平衡器、健康查抄、负载监控
- 优点:顺应厘革、提高资源使用率、自动故障转移
- 缺点:复杂、开销大、必要监控
- 应用:复杂场景、动态环境、高可用性要求
- 一致性哈希
- 定义:在服务器厘革时最小化重新分配的哈希算法
- 原理:将哈希空间映射到环形空间,服务器分布在环上
- 实现:假造节点、权重、分区
- 优点:服务器厘革时影响最小,支持动态扩缩容
- 缺点:负载可能不均匀,必要假造节点
- 应用:分布式缓存、分布式存储、服务发现
12.5 网络安全
12.5.1 加密算法
- 对称加密
- 定义:使用相同密钥举行加密和解密的算法
- 算法:AES、DES、3DES、ChaCha20
- 模式:ECB、CBC、CFB、OFB、CTR、GCM
- 实现:软件实现、硬件加速、专用指令集
- 优化:并行计算、流水线、查表法
- 应用:数据加密、安全通信、存储加密
- 非对称加密
- 定义:使用差别密钥举行加密和解密的算法
- 算法:RSA、ECC、DH、DSA
- 实现:软件实现、硬件加速、专用指令集
- 优化:密钥生成、模幂运算、椭圆曲线运算
- 应用:密钥互换、数字签名、身份认证
- 变体:RSA-OAEP、ECDH、Ed25519
- 哈希函数
- 定义:将任意长度数据映射为固定长度数据的函数
- 算法:SHA-1、SHA-2、SHA-3、MD5
- 特性:单向性、抗碰撞性、雪崩效应
- 应用:数据完整性、暗码存储、数字签名
- 变体:HMAC、PBKDF2、Argon2
- 优化:并行计算、硬件加速、专用指令集
12.5.2 安全协议
- TLS/SSL
- 定义:提供通信安全性的传输层协议
- 版本:SSL 3.0、TLS 1.0、TLS 1.1、TLS 1.2、TLS 1.3
- 功能:加密、认证、完整性、前向安全性
- 实现:OpenSSL、BoringSSL、LibreSSL
- 优化:会话复用、OCSP Stapling、False Start
- 应用:HTTPS、安全邮件、VPN
- IPsec
- 定义:网络层安全协议,提供IP通信的安全性
- 模式:传输模式、隧道模式
- 功能:加密、认证、完整性、防重放
- 实现:内核模块、用户空间实现、硬件加速
- 优化:硬件加速、并行处理、会话管理
- 应用:VPN、站点间通信、移动IP
- SSH
- 定义:安全外壳协议,提供安全的远程登录和文件传输
- 版本:SSH-1、SSH-2
- 功能:加密、认证、完整性、端口转发
- 实现:OpenSSH、Dropbear、PuTTY
- 优化:密钥管理、会话复用、压缩
- 应用:远程登录、文件传输、隧道
12.5.3 安全数据结构
- 密钥管理
- 定义:管理加密密钥的生命周期
- 操作:生成、存储、分发、更新、销毁
- 存储:硬件安全模块、密钥管理体系、安全存储
- 策略:密钥轮换、密钥备份、密钥规复
- 优化:密钥缓存、批量操作、并行处理
- 应用:加密体系、安全通信、身份认证
- 证书管理
- 定义:管理数字证书的生命周期
- 操作:生成、签发、验证、更新、撤销
- 存储:证书存储、证书链、证书撤销列表
- 策略:证书轮换、证书备份、证书规复
- 优化:证书缓存、批量操作、并行处理
- 应用:HTTPS、安全邮件、代码签名
- 安全会话
- 定义:管理安全通信会话的状态
- 操作:建立、维护、更新、终止
- 存储:会话状态、会话密钥、会话参数
- 策略:会话超时、会话规复、会话迁徙
- 优化:会话复用、会话压缩、会话批处理
- 应用:安全通信、身份认证、授权
13. 数据结构与分布式体系
13.1 分布式存储
13.1.1 数据分片
- 一致性哈希
- 定义:将哈希空间映射到环形空间,节点分布在环上,数据根据哈希值分配到最近的节点
- 优点:节点增减时只需重新分配受影响的数据,影响范围小
- 实现:假造节点、权重、分区、跳跃一致性哈希
- 数据结构:环形哈希表、跳跃表、红黑树
- 优化:假造节点数量、哈希函数选择、分区策略
- 应用:分布式缓存、分布式数据库、内容分发网络
- 分片策略
- 定义:将数据分别为多个分片并分配到差别节点的策略
- 范例:范围分片、哈希分片、列表分片、复合分片
- 实现:分片键选择、分片函数、分片路由表
- 数据结构:分片映射表、路由表、元数据表
- 优化:热点数据分散、分片巨细平衡、分片迁徙
- 应用:分布式数据库、分布式文件体系、分布式缓存
- 复制机制
- 定义:将数据复制到多个节点以提高可用性和性能
- 范例:主从复制、多主复制、无主复制
- 策略:同步复制、异步复制、半同步复制
- 数据结构:复制日记、操作日记、状态向量
- 优化:批量复制、增量复制、压缩复制
- 应用:高可用数据库、读写分离、地理分布
- 故障转移
- 定义:在节点故障时自动将服务转移到其他节点的机制
- 范例:自动故障转移、手动故障转移、混合故障转移
- 策略:心跳检测、超时机制、多数派投票
- 数据结构:故障检测表、节点状态表、选举日记
- 优化:快速检测、平滑切换、数据一致性包管
- 应用:高可用服务、数据库集群、负载平衡
13.1.2 数据同步
- 日记复制
- 定义:通过复制操作日记来同步数据状态
- 范例:操作日记、状态日记、混合日记
- 实现:WAL(Write-Ahead Logging)、CDC(Change Data Capture)
- 数据结构:日记条目、日记序列、日记缓冲区
- 优化:日记压缩、批量传输、并行复制
- 应用:数据库复制、消息队列、变乱溯源
- 状态同步
- 定义:直接同步数据状态而不是操作日记
- 范例:全量同步、增量同步、差异同步
- 实现:快照、差异计算、归并策略
- 数据结构:状态向量、差异集、归并树
- 优化:增量计算、并行同步、压缩传输
- 应用:分布式缓存、配置同步、状态复制
- 冲突办理
- 定义:办理多节点并发修改导致的数据冲突
- 策略:最后写入胜利、归并策略、自定义策略
- 实现:版本向量、时间戳、操作转换
- 数据结构:冲突检测图、归并树、版本汗青
- 优化:冲突预防、冲突减少、冲突办理服从
- 应用:多主数据库、分布式协作、离线同步
- 一致性协议
- 定义:包管分布式体系中数据一致性的协议
- 范例:强一致性、最终一致性、因果一致性
- 协议:Paxos、Raft、ZAB、2PC、3PC
- 数据结构:提案、投票、状态机、日记
- 优化:协议简化、性能优化、容错加强
- 应用:分布式和谐、元数据管理、配置管理
13.2 分布式计算
13.2.1 任务调度
- 任务队列
- 定义:管理和分发分布式计算任务的队列体系
- 范例:优先级队列、延长队列、批处理队列
- 实现:集中式调度、分布式调度、混合调度
- 数据结构:任务图、依赖图、资源需求向量
- 优化:任务归并、任务分割、任务优先级
- 应用:批处理体系、工作流引擎、资源调度
- 负载平衡
- 定义:将计算负载平衡分配到多个节点
- 策略:轮询、加权轮询、最少毗连、响应时间
- 实现:集中式负载平衡、分布式负载平衡
- 数据结构:负载表、节点状态表、调度决策树
- 优化:动态权重、自顺应策略、预测性调度
- 应用:计算集群、服务网格、微服务架构
- 故障规复
- 定义:在节点故障时规复和重新分配任务
- 策略:任务重试、任务迁徙、任务重新调度
- 实现:查抄点、状态规复、任务重放
- 数据结构:故障检测表、规复日记、状态快照
- 优化:快速检测、最小化规复时间、资源使用
- 应用:高可用计算、容错体系、弹性计算
- 资源分配
- 定义:分配和管理计算资源(CPU、内存、存储等)
- 策略:静态分配、动态分配、按需分配
- 实现:资源池、资源配额、资源预留
- 数据结构:资源向量、分配矩阵、资源树
- 优化:资源使用率、资源碎片、资源争用
- 应用:云计算、容器编排、资源调度
13.2.2 数据流处理
- 流处理
- 定义:及时处理连续数据流的体系
- 模型:数据流图、操作符图、处理管道
- 实现:变乱处理、窗口计算、状态管理
- 数据结构:流缓冲区、窗口状态、处理图
- 优化:背压处理、并行处理、批处理优化
- 应用:及时分析、变乱处理、流式ETL
- 批处理
- 定义:处理批量数据的体系
- 模型:MapReduce、DAG、工作流
- 实现:任务分割、数据分区、效果归并
- 数据结构:分区表、中间效果、聚合树
- 优化:数据当地性、任务并行度、资源使用
- 应用:数据分析、ETL处理、机器学习训练
- 窗口计算
- 定义:在时间或计数窗口上举行聚合计算
- 范例:时间窗口、计数窗口、滑动窗口、会话窗口
- 实现:窗口状态、触发器、清除策略
- 数据结构:窗口缓冲区、时间索引、状态表
- 优化:增量计算、延长处理、窗口归并
- 应用:及时统计、趋势分析、非常检测
- 状态管理
- 定义:管理流处理中的状态数据
- 范例:键值状态、列表状态、聚合状态
- 实现:状态后端、状态规复、状态分区
- 数据结构:状态表、状态快照、查抄点
- 优化:状态压缩、状态分区、状态规复
- 应用:状态ful计算、复杂变乱处理、流式毗连
13.3 分布式和谐
13.3.1 一致性算法
- Paxos
- 定义:办理分布式体系一致性问题的底子算法
- 角色:发起者、担当者、学习者
- 阶段:准备阶段、担当阶段、学习阶段
- 数据结构:提案编号、提案值、答应集合
- 变体:Multi-Paxos、Fast Paxos、Cheap Paxos
- 应用:Google Chubby、ZooKeeper、etcd
- Raft
- 定义:易于明确的一致性算法,与Paxos等效
- 角色:领导者、跟随者、候选人
- 阶段:领导者选举、日记复制、安全性
- 数据结构:日记条目、状态机、成员变动
- 优化:日记压缩、成员变动、快照
- 应用:etcd、Consul、CockroachDB
- ZAB
- 定义:ZooKeeper原子广播协议
- 阶段:领导者选举、原子广播、规复
- 数据结构:事务日记、快照、状态树
- 特性:顺序一致性、原子性、单一体系镜像
- 优化:日记压缩、快照、规复
- 应用:ZooKeeper、分布式和谐、配置管理
13.3.2 分布式锁
- 实现方式
- 定义:在分布式环境中实现互斥访问的机制
- 范例:基于数据库、基于缓存、基于ZooKeeper
- 特性:互斥性、可重入性、防死锁、高可用
- 数据结构:锁表、锁节点、锁状态
- 优化:锁粒度、锁超时、锁续期
- 应用:资源控制、并发控制、分布式事务
- 分布式事务
- 定义:跨多个分布式节点的原子操作
- 模型:2PC、3PC、TCC、SAGA
- 实现:和谐者、参与者、状态管理
- 数据结构:事务日记、状态表、赔偿操作
- 优化:性能、可用性、一致性
- 应用:金融交易、订单处理、库存管理
13.4 分布式数据结构
13.4.1 分布式哈希表
- 定义:将哈希表分散到多个节点的数据结构
- 特性:键值存储、分布式查找、负载平衡
- 实现:Chord、Pastry、Kademlia、CAN
- 数据结构:路由表、节点状态、键值对
- 优化:路由服从、节点加入/离开、数据迁徙
- 应用:P2P网络、分布式存储、服务发现
13.4.2 分布式计数器
- 定义:在分布式环境中实现原子计数操作
- 范例:加法计数器、乘法计数器、混合计数器
- 实现:CRDT、状态同步、操作转换
- 数据结构:计数器状态、操作日记、归并策略
- 优化:冲突办理、一致性包管、性能
- 应用:访问统计、资源计数、限流控制
13.4.3 分布式集合
- 定义:在分布式环境中实现的集合数据结构
- 范例:集合、列表、映射、队列
- 实现:CRDT、状态同步、操作转换
- 数据结构:集合状态、操作日记、归并策略
- 优化:冲突办理、一致性包管、性能
- 应用:分布式缓存、配置管理、状态同步
13.5 分布式算法
13.5.1 共识算法
- 定义:使分布式体系中的节点就某个值达成一致
- 范例:同步共识、异步共识、部门同步共识
- 算法:Paxos、Raft、ZAB、PBFT
- 特性:安全性、活性、容错性
- 优化:性能、可扩展性、复杂性
- 应用:元数据管理、配置管理、状态复制
13.5.2 分布式排序
- 定义:在分布式环境中对数据举行排序
- 范例:外部排序、并行排序、分布式排序
- 算法:归并排序、快速排序、基数排序
- 实现:数据分区、局部排序、效果归并
- 优化:数据当地性、通信开销、负载平衡
- 应用:大数据分析、日记处理、数据堆栈
13.5.3 分布式图算法
- 定义:在分布式环境中处理图数据
- 范例:图遍历、最短路径、连通分量
- 算法:BFS、DFS、Dijkstra、PageRank
- 实现:图分区、消息传递、状态同步
- 优化:通信模式、负载平衡、容错性
- 应用:交际网络分析、推荐体系、路径规划
14. 数据结构与大数据处理
14.1 数据存储
14.1.1 列式存储
- 数据压缩
- 定义:对列式存储中的数据举行压缩以减少存储空间和提高I/O服从
- 方法:游程编码、字典编码、位图编码、Delta编码
- 算法:LZ77、LZSS、Snappy、Zstandard
- 数据结构:压缩字典、压缩块、压缩索引
- 优化:压缩率与解压速率平衡、选择性压缩、自顺应压缩
- 应用:数据堆栈、分析数据库、OLAP体系
- 编码方式
- 定义:将数据转换为特定格式以便高效存储和处理
- 范例:定长编码、变长编码、字典编码、位图编码
- 实现:前缀编码、霍夫曼编码、算术编码、游程编码
- 数据结构:编码表、编码树、编码块
- 优化:编码服从、解码速率、内存占用
- 应用:数据压缩、数据传输、数据存储
- 索引结构
- 定义:加速列式存储中数据查询的数据结构
- 范例:位图索引、布隆过滤器、LSM树、B+树
- 实现:多级索引、复合索引、覆盖索引
- 数据结构:索引树、索引表、索引块
- 优化:索引巨细、查询性能、更新开销
- 应用:数据查询、数据过滤、数据聚合
- 查询优化
- 定义:提高列式存储查询性能的技能
- 方法:谓词下推、列裁剪、分区裁剪、物化视图
- 实现:查询筹划生成、代价估算、实验优化
- 数据结构:查询筹划树、统计信息、缓存
- 优化:并行查询、向量化实验、代码生成
- 应用:OLAP查询、报表生成、数据分析
14.1.2 分布式存储
- 分片策略
- 定义:将大数据集分割并分配到多个存储节点
- 范例:范围分片、哈希分片、列表分片、复合分片
- 实现:分片键选择、分片函数、分片路由表
- 数据结构:分片映射表、路由表、元数据表
- 优化:热点数据分散、分片巨细平衡、分片迁徙
- 应用:分布式数据库、分布式文件体系、分布式缓存
- 复制机制
- 定义:将数据复制到多个节点以提高可用性和性能
- 范例:主从复制、多主复制、无主复制
- 策略:同步复制、异步复制、半同步复制
- 数据结构:复制日记、操作日记、状态向量
- 优化:批量复制、增量复制、压缩复制
- 应用:高可用数据库、读写分离、地理分布
- 一致性
- 定义:包管分布式存储体系中数据的一致性
- 模型:强一致性、最终一致性、因果一致性
- 协议:Paxos、Raft、ZAB、2PC、3PC
- 数据结构:提案、投票、状态机、日记
- 优化:协议简化、性能优化、容错加强
- 应用:分布式和谐、元数据管理、配置管理
- 可用性
- 定义:体系在面临故障时保持服务的本领
- 策略:冗余、故障检测、故障转移、自动规复
- 实现:心跳检测、超时机制、多数派投票
- 数据结构:故障检测表、节点状态表、选举日记
- 优化:快速检测、平滑切换、数据一致性包管
- 应用:高可用服务、数据库集群、负载平衡
14.2 数据处理
14.2.1 批处理
- MapReduce
- 定义:处理大规模数据集的并行计算模型
- 阶段:Map阶段、Shuffle阶段、Reduce阶段
- 实现:任务分割、数据分区、效果归并
- 数据结构:键值对、分区表、中间效果
- 优化:数据当地性、任务并行度、资源使用
- 应用:日记处理、数据清洗、数据分析
- 数据分区
- 定义:将数据集分割成多个部门以便并行处理
- 策略:哈希分区、范围分区、列表分区
- 实现:分区函数、分区表、分区路由
- 数据结构:分区映射表、分区状态表
- 优化:分区巨细平衡、数据倾斜处理、动态分区
- 应用:分布式计算、数据并行、任务并行
- 任务调度
- 定义:管理和分发批处理任务的机制
- 范例:集中式调度、分布式调度、混合调度
- 实现:任务队列、依赖管理、资源分配
- 数据结构:任务图、依赖图、资源需求向量
- 优化:任务归并、任务分割、任务优先级
- 应用:批处理体系、工作流引擎、资源调度
- 效果归并
- 定义:将多个处理效果归并成最闭幕果
- 策略:排序归并、哈希归并、流式归并
- 实现:归并树、归并队列、归并缓冲区
- 数据结构:效果集、归并状态、临时文件
- 优化:内存使用、磁盘I/O、并行归并
- 应用:数据聚合、效果汇总、报表生成
14.2.2 流处理
- 及时计算
- 定义:对连续数据流举行及时处理和分析
- 模型:数据流图、操作符图、处理管道
- 实现:变乱处理、窗口计算、状态管理
- 数据结构:流缓冲区、窗口状态、处理图
- 优化:背压处理、并行处理、批处理优化
- 应用:及时分析、变乱处理、流式ETL
- 窗口操作
- 定义:在时间或计数窗口上举行聚合计算
- 范例:时间窗口、计数窗口、滑动窗口、会话窗口
- 实现:窗口状态、触发器、清除策略
- 数据结构:窗口缓冲区、时间索引、状态表
- 优化:增量计算、延长处理、窗口归并
- 应用:及时统计、趋势分析、非常检测
- 状态管理
- 定义:管理流处理中的状态数据
- 范例:键值状态、列表状态、聚合状态
- 实现:状态后端、状态规复、状态分区
- 数据结构:状态表、状态快照、查抄点
- 优化:状态压缩、状态分区、状态规复
- 应用:状态ful计算、复杂变乱处理、流式毗连
- 容错机制
- 定义:包管流处理体系在面临故障时的可靠性
- 策略:查抄点、状态规复、重放机制
- 实现:故障检测、故障转移、数据规复
- 数据结构:查抄点日记、规复状态、故障检测表
- 优化:查抄点频率、规复时间、资源使用
- 应用:高可用流处理、及时分析、变乱处理
14.3 数据索引与查询
14.3.1 索引结构
- 倒排索引
- 定义:将文档中的词映射到包含该词的文档列表
- 结构:词项字典、倒分列表、文档映射
- 实现:压缩存储、跳跃表、归并策略
- 优化:索引巨细、查询性能、更新开销
- 变体:块索引、分层索引、分布式索引
- 应用:全文搜索、搜索引擎、文档检索
- LSM树
- 定义:写优化的数据结构,用于处理大量写入操作
- 结构:内存表、磁盘表、归并策略
- 实现:跳表、B+树、布隆过滤器
- 优化:归并策略、压缩策略、布隆过滤器
- 变体:LevelDB、RocksDB、Cassandra
- 应用:键值存储、日记存储、时序数据库
- 布隆过滤器
- 定义:空间服从高的概率性数据结构,用于成员检测
- 结构:位数组、哈希函数、查询接口
- 实现:标准布隆过滤器、计数布隆过滤器、分层布隆过滤器
- 优化:假阳性率、空间服从、哈希函数选择
- 变体:布谷鸟过滤器、商过滤器、分块布隆过滤器
- 应用:缓存穿透预防、成员检测、近似查询
14.3.2 查询优化
- 查询筹划
- 定义:实验查询的步骤温顺序
- 生成:基于规则、基于代价、混合策略
- 表示:查询筹划树、操作符图、实验图
- 优化:谓词下推、列裁剪、分区裁剪
- 实验:并行实验、向量化实验、代码生成
- 应用:SQL查询、分析查询、复杂查询
- 统计信息
- 定义:形貌数据分布和特征的信息
- 范例:基数估计、直方图、采样统计
- 收集:全表扫描、采样扫描、增量更新
- 使用:代价估算、查询优化、资源分配
- 优化:统计精度、更新频率、存储开销
- 应用:查询优化、资源规划、性能调优
- 缓存策略
- 定义:存储常用数据以提高访问速率
- 范例:查询缓存、效果缓存、中间效果缓存
- 策略:LRU、LFU、FIFO、TTL
- 实现:内存缓存、分布式缓存、多级缓存
- 优化:缓存命中率、缓存一致性、缓存预热
- 应用:查询加速、热点数据访问、效果复用
14.4 数据挖掘与机器学习
14.4.1 特征工程
- 特征提取
- 定义:从原始数据中提取有用特征的过程
- 方法:统计特征、时间特征、空间特征、文本特征
- 实现:特征计算、特征转换、特征选择
- 数据结构:特征向量、特征矩阵、特征图
- 优化:特征质量、特征数量、计算服从
- 应用:机器学习、数据挖掘、模式辨认
- 特征选择
- 定义:选择最相干和最有用的特征子集
- 方法:过滤法、包装法、嵌入法、混正当
- 算法:信息增益、卡方检验、L1正则化、递归特征消除
- 数据结构:特征重要性表、特征相干性矩阵
- 优化:选择服从、特征数量、模型性能
- 应用:降维、模型简化、解释性加强
- 特征转换
- 定义:将特征转换为更适合机器学习的形式
- 方法:标准化、归一化、离散化、编码
- 算法:Min-Max缩放、Z-score标准化、独热编码、标签编码
- 数据结构:转换参数、转换规则、转换表
- 优化:转换服从、信息保留、计算开销
- 应用:数据预处理、模型输入、特征工程
14.4.2 模型存储
- 模型序列化
- 定义:将机器学习模型转换为可存储和传输的格式
- 格式:二进制格式、JSON格式、XML格式、自定义格式
- 方法:Pickle、Joblib、PMML、ONNX
- 数据结构:模型参数、模型结构、模型元数据
- 优化:序列化巨细、序列化速率、兼容性
- 应用:模型部署、模型共享、模型版本控制
- 模型压缩
- 定义:减小模型巨细以提高存储和传输服从
- 方法:权重量化、知识蒸馏、模型剪枝、低秩分解
- 算法:量化感知训练、渐进式剪枝、奇特值分解
- 数据结构:压缩参数、压缩规则、压缩表
- 优化:压缩率、精度损失、推理速率
- 应用:移动设备部署、边缘计算、资源受限环境
- 模型版本控制
- 定义:管理机器学习模型的差别版本
- 体系:MLflow、DVC、ModelDB、自定义体系
- 功能:版本跟踪、元数据管理、实验比较
- 数据结构:版本图、元数据表、实验记录
- 优化:存储服从、查询服从、协作服从
- 应用:模型生命周期管理、实验管理、模型部署
14.5 数据可视化
14.5.1 可视化数据结构
- 树形结构
- 定义:层次化数据的可视化表示
- 范例:树图、旭日图、矩形树图、树形图
- 实现:节点布局、边布局、交互计划
- 数据结构:树节点、树边、树布局
- 优化:布局算法、空间使用、可读性
- 应用:文件体系、构造结构、分类体系
- 图结构
- 定义:关系数据的可视化表示
- 范例:力导向图、环形图、桑基图、网络图
- 实现:节点布局、边布局、力模仿
- 数据结构:图节点、图边、图布局
- 优化:布局算法、边交叉、可读性
- 应用:交际网络、知识图谱、依赖关系
- 多维数据
- 定义:多维数据的可视化表示
- 范例:散点图、平行坐标、雷达图、热力图
- 实现:维度映射、颜色映射、交互计划
- 数据结构:数据点、维度映射、视觉属性
- 优化:维度选择、视觉编码、交互服从
- 应用:数据分析、特征探索、模式发现
14.5.2 交互式可视化
- 数据筛选
- 定义:通过交互方式筛选和过滤数据
- 方法:范围选择、种别选择、条件过滤
- 实现:选择器、过滤器、查询构建器
- 数据结构:选择状态、过滤条件、查询表达式
- 优化:响应速率、选择精度、用户体验
- 应用:数据探索、数据分析、报表生成
- 数据钻取
- 定义:从汇总数据深入到详细数据的交互过程
- 方法:层次钻取、维度钻取、交叉钻取
- 实现:钻取路径、钻取视图、钻取控制
- 数据结构:钻取层次、钻取路径、钻取状态
- 优化:钻取深度、钻取速率、上下文保持
- 应用:商业智能、数据分析、决策支持
- 动态更新
- 定义:及时更新可视化内容以反映数据厘革
- 方法:增量更新、全量更新、动画过渡
- 实现:更新策略、动画控制、状态管理
- 数据结构:更新队列、动画状态、视图状态
- 优化:更新频率、动画流畅度、资源斲丧
- 应用:及时监控、动态数据、交互式分析
15. 数据结构与人工智能
15.1 机器学习
15.1.1 特征工程
- 特征选择
- 定义:从原始特征中选择最相干和最有用的特征子集
- 方法:过滤法、包装法、嵌入法、混正当
- 算法:信息增益、卡方检验、L1正则化、递归特征消除
- 数据结构:特征重要性表、特征相干性矩阵、特征子集
- 优化:选择服从、特征数量、模型性能
- 应用:降维、模型简化、解释性加强、过拟合预防
- 特征转换
- 定义:将特征转换为更适合机器学习的形式
- 方法:标准化、归一化、离散化、编码
- 算法:Min-Max缩放、Z-score标准化、独热编码、标签编码
- 数据结构:转换参数、转换规则、转换表、特征向量
- 优化:转换服从、信息保留、计算开销、内存使用
- 应用:数据预处理、模型输入、特征工程、数据清洗
- 特征存储
- 定义:高效存储和管理特征数据的机制
- 格式:稀疏矩阵、麋集矩阵、特征字典、特征数据库
- 实现:内存存储、磁盘存储、分布式存储
- 数据结构:特征表、特征索引、特征缓存、特征元数据
- 优化:存储服从、访问速率、更新服从、内存使用
- 应用:特征库、特征服务、特征版本控制、特征共享
- 特征索引
- 定义:加速特征检索和访问的数据结构
- 范例:哈希索引、树索引、位图索引、复合索引
- 实现:倒排索引、LSM树、布隆过滤器
- 数据结构:索引表、索引树、索引块、索引缓存
- 优化:索引巨细、查询性能、更新开销、内存使用
- 应用:特征检索、特征匹配、特征过滤、特征聚合
15.1.2 模型训练
- 参数优化
- 定义:探求使模型性能最优的参数值的过程
- 方法:网格搜索、随机搜索、贝叶斯优化、进化算法
- 算法:梯度下降、遗传算法、模仿退火、粒子群优化
- 数据结构:参数空间、参数表、优化汗青、评估效果
- 优化:搜索服从、收敛速率、资源使用、并行计算
- 应用:超参数调优、模型选择、模型集成、自动机器学习
- 梯度计算
- 定义:计算损失函数对模型参数的梯度
- 方法:数值梯度、剖析梯度、自动微分
- 算法:反向传播、随机梯度下降、小批量梯度下降
- 数据结构:计算图、梯度表、参数梯度、中间效果
- 优化:计算服从、内存使用、数值稳固性、并行计算
- 应用:参数更新、模型训练、梯度查抄、梯度裁剪
- 损失函数
- 定义:衡量模型预测与真实值之间差异的函数
- 范例:回归损失、分类损失、排序损失、生成损失
- 实现:均方毛病、交叉熵、铰链损失、KL散度
- 数据结构:损失值、梯度、二阶导数、损失汗青
- 优化:数值稳固性、计算服从、梯度性质、收敛性
- 应用:模型训练、模型评估、模型比较、模型调试
- 正则化
- 定义:防止模型过拟合的技能
- 范例:L1正则化、L2正则化、弹性网络、Dropout
- 实现:权重衰减、早停、数据加强、集成学习
- 数据结构:正则化项、正则化参数、正则化汗青
- 优化:正则化强度、正则化范例、正则化时机
- 应用:过拟合预防、模型简化、特征选择、模型解释
15.2 深度学习
15.2.1 神经网络
- 层结构
- 定义:神经网络的基本构建块,处理特定范例的转换
- 范例:全毗连层、卷积层、池化层、循环层、注意力层
- 实现:前向传播、反向传播、参数初始化、参数更新
- 数据结构:权重矩阵、偏置向量、激活值、梯度
- 优化:层数、层巨细、毗连方式、初始化方法
- 应用:图像辨认、自然语言处理、语音辨认、推荐体系
- 激活函数
- 定义:引入非线性变动的函数,使神经网络可以或许学习复杂模式
- 范例:Sigmoid、Tanh、ReLU、Leaky ReLU、Softmax
- 实现:前向计算、梯度计算、数值稳固性
- 数据结构:激活值、梯度、参数、统计信息
- 优化:梯度消失/爆炸、计算服从、数值稳固性
- 应用:非线性变动、分类输出、特征提取、注意力机制
- 权重更新
- 定义:根据梯度信息调整网络参数的过程
- 方法:随机梯度下降、小批量梯度下降、Adam、RMSprop
- 实现:参数更新规则、学习率调整、动量、自顺应学习率
- 数据结构:参数表、梯度表、动量表、统计信息
- 优化:收敛速率、收敛稳固性、资源使用、并行计算
- 应用:模型训练、参数调优、模型微调、迁徙学习
- 反向传播
- 定义:计算损失函数对网络参数的梯度的算法
- 原理:链式法则、梯度流动、毛病传播
- 实现:自动微分、手动微分、符号微分
- 数据结构:计算图、梯度表、中间效果、反向路径
- 优化:计算服从、内存使用、数值稳固性、并行计算
- 应用:参数更新、梯度查抄、模型调试、模型解释
15.2.2 优化算法
- 梯度下降
- 定义:沿着损失函数梯度的反方向更新参数以最小化损失
- 变体:批量梯度下降、随机梯度下降、小批量梯度下降
- 实现:参数更新规则、学习率选择、收敛判定
- 数据结构:参数表、梯度表、损失汗青、学习率表
- 优化:收敛速率、收敛稳固性、资源使用、并行计算
- 应用:模型训练、参数优化、模型微调、迁徙学习
- 动量法
- 定义:使用汗青梯度的指数加权平均来加速和稳固梯度下降
- 变体:标准动量、Nesterov动量、带动量的RMSprop
- 实现:动量更新规则、动量参数选择、收敛判定
- 数据结构:参数表、梯度表、动量表、损失汗青
- 优化:收敛速率、收敛稳固性、震荡减少、局部最优
- 应用:模型训练、参数优化、模型微调、迁徙学习
- Adam优化器
- 定义:结合动量和RMSprop的自顺应学习率优化算法
- 特性:自顺应学习率、动量、毛病修正
- 实现:参数更新规则、超参数选择、收敛判定
- 数据结构:参数表、梯度表、动量表、方差表
- 优化:收敛速率、收敛稳固性、超参数敏感性、资源使用
- 应用:深度学习、强化学习、自然语言处理、计算机视觉
- 学习率调整
- 定义:在训练过程中动态调整学习率的策略
- 方法:学习率衰减、学习率预热、循环学习率、自顺应学习率
- 实现:学习率调度器、学习率表、学习率汗青
- 数据结构:学习率表、训练轮次、损失汗青、梯度汗青
- 优化:收敛速率、收敛稳固性、局部最优、资源使用
- 应用:模型训练、参数优化、模型微调、迁徙学习
15.3 强化学习
15.3.1 状态表示
- 状态空间
- 定义:强化学习环境中所有可能状态的集合
- 范例:离散状态空间、连续状态空间、混合状态空间
- 表示:状态向量、状态图、状态树、状态表
- 数据结构:状态表、状态索引、状态特征、状态转换
- 优化:状态压缩、状态抽象、状态分解、状态编码
- 应用:游戏AI、机器人控制、资源调度、推荐体系
- 状态转换
- 定义:形貌状态之间转换关系的模型
- 范例:确定性转换、随机转换、部门可观察转换
- 表示:转换函数、转换概率、转换图、转换表
- 数据结构:转换表、转换图、转换概率、转换汗青
- 优化:转换服从、转换精度、转换压缩、转换预测
- 应用:环境模仿、策略评估、值函数估计、模型学习
15.3.2 动作选择
- 动作空间
- 定义:强化学习环境中所有可能动作的集合
- 范例:离散动作空间、连续动作空间、混合动作空间
- 表示:动作向量、动作图、动作树、动作表
- 数据结构:动作表、动作索引、动作特征、动作效果
- 优化:动作压缩、动作抽象、动作分解、动作编码
- 应用:游戏AI、机器人控制、资源调度、推荐体系
- 策略表示
- 定义:从状态到动作的映射函数
- 范例:确定性策略、随机策略、参数化策略
- 表示:策略表、策略函数、策略网络、策略树
- 数据结构:策略表、策略参数、策略梯度、策略汗青
- 优化:策略服从、策略泛化、策略探索、策略使用
- 应用:策略学习、策略评估、策略改进、策略部署
15.4 自然语言处理
15.4.1 文本表示
- 词嵌入
- 定义:将词映射到低维连续向量空间的表示方法
- 模型:Word2Vec、GloVe、FastText、BERT
- 实现:Skip-gram、CBOW、负采样、层次Softmax
- 数据结构:词向量表、词索引、上下文窗口、负样本
- 优化:训练服从、词向量质量、词汇覆盖、上下文明确
- 应用:语义搜索、文本分类、情感分析、机器翻译
- 序列表示
- 定义:表示文本序列的数据结构
- 范例:词序列、字符序列、子词序列、句子序列
- 实现:序列编码、序列解码、序列对齐、序列填充
- 数据结构:序列表、序列索引、序列特征、序列标签
- 优化:序列长度、序列压缩、序列对齐、序列处理
- 应用:文本生成、序列标注、序列分类、序列翻译
15.4.2 语言模型
- 统计语言模型
- 定义:基于统计方法预测文本序列概率的模型
- 范例:N-gram模型、平滑模型、回退模型、插值模型
- 实现:概率估计、平滑技能、回退策略、插值方法
- 数据结构:概率表、计数表、平滑参数、回退参数
- 优化:模型巨细、预测精度、计算服从、词汇覆盖
- 应用:文本生成、语音辨认、机器翻译、拼写改正
- 神经网络语言模型
- 定义:使用神经网络预测文本序列概率的模型
- 范例:前馈神经网络、循环神经网络、Transformer
- 实现:词嵌入、上下文表示、概率预测、损失计算
- 数据结构:词向量、隐蔽状态、注意力权重、输出概率
- 优化:模型巨细、训练服从、预测精度、上下文长度
- 应用:文本生成、语音辨认、机器翻译、文本摘要
15.5 计算机视觉
15.5.1 图像表示
- 像素表示
- 定义:基于像素的图像表示方法
- 范例:灰度图像、RGB图像、HSV图像、多光谱图像
- 实现:像素矩阵、通道分离、通道归并、像素变动
- 数据结构:像素数组、图像矩阵、通道表、变动参数
- 优化:存储服从、访问速率、处理服从、内存使用
- 应用:图像处理、图像分析、图像辨认、图像生成
- 特征表示
- 定义:提取图像中重要特征的方法
- 范例:边缘特征、纹理特征、外形特征、深度特征
- 实现:SIFT、SURF、HOG、CNN特征
- 数据结构:特征向量、特征图、特征金字塔、特征索引
- 优化:特征数量、特征质量、计算服从、内存使用
- 应用:图像匹配、物体检测、场景明确、图像检索
15.5.2 卷积神经网络
- 卷积层
- 定义:使用卷积操作提取图像特征的神经网络层
- 参数:卷积核、步长、填充、通道数
- 实现:前向传播、反向传播、参数初始化、参数更新
- 数据结构:卷积核、特征图、梯度图、参数表
- 优化:计算服从、内存使用、并行计算、硬件加速
- 应用:图像分类、物体检测、语义分割、风格迁徙
- 池化层
- 定义:降低特征图空间维度的神经网络层
- 范例:最大池化、平均池化、全局池化、自顺应池化
- 实现:前向传播、反向传播、参数初始化、参数更新
- 数据结构:池化窗口、特征图、梯度图、参数表
- 优化:计算服从、内存使用、并行计算、硬件加速
- 应用:特征提取、降维、稳固性、计算服从
- 全毗连层
- 定义:将特征图转换为分类或回归输出的神经网络层
- 实现:前向传播、反向传播、参数初始化、参数更新
- 数据结构:权重矩阵、偏置向量、激活值、梯度
- 优化:参数数量、计算服从、内存使用、过拟合预防
- 应用:图像分类、物体检测、语义分割、风格迁徙
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |