# 数据结构与算法
# 数据结构
10个数据结构:数组(Array)、链表(Linked List)、栈(Stack)、队列(Queue)、散列表(Hash Table)、二叉树(Binary Tree)、堆(Heap)、跳表(Skip List)、图(Graph)、树(Tree)
# 数组(Array)
数组是固定大小的元素集合,可以通过索引访问。
public class ArrayExample {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
// 访问数组元素
System.out.println(arr[0]); // 输出:1
// 修改数组元素
arr[1] = 20;
// 遍历数组
for (int element : arr) {
System.out.println(element);
}
}
}
# 链表
链表由一系列节点组成,每个节点包含数据和指向下一个节点的引用。
class Node {
int data;
Node next;
Node(int data) {
this.data = data;
this.next = null;
}
}
public class LinkedListExample {
Node head;
// 添加元素到链表
public void add(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
} else {
Node temp = head;
while (temp.next != null) {
temp = temp.next;
}
temp.next = newNode;
}
}
// 打印链表
public void printList() {
Node temp = head;
while (temp != null) {
System.out.print(temp.data + " ");
temp = temp.next;
}
}
public static void main(String[] args) {
LinkedListExample list = new LinkedListExample();
list.add(1);
list.add(2);
list.add(3);
list.printList(); // 输出:1 2 3
}
}
# 栈(Stack)
栈是一种后进先出(LIFO)的数据结构。
import java.util.Stack;
public class StackExample {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
// 入栈
stack.push(1);
stack.push(2);
stack.push(3);
// 出栈
System.out.println(stack.pop()); // 输出:3
System.out.println(stack.pop()); // 输出:2
// 查看栈顶元素
System.out.println(stack.peek()); // 输出:1
}
}
# 队列(Queue)
队列是一种先进先出(FIFO)的数据结构。
import java.util.LinkedList;
import java.util.Queue;
public class QueueExample {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
// 入队
queue.add(1);
queue.add(2);
queue.add(3);
// 出队
System.out.println(queue.poll()); // 输出:1
System.out.println(queue.poll()); // 输出:2
// 查看队首元素
System.out.println(queue.peek()); // 输出:3
}
}
# 散列表(Hash Table)
散列表通过键值对存储数据,具有快速的查找、插入和删除操作。
import java.util.HashMap;
public class HashTableExample {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
// 查找键值
System.out.println(map.get("a")); // 输出:1
// 删除键值对
map.remove("b");
// 遍历散列表
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
}
}
# 二叉树(Binary Tree)
二叉树是每个节点最多有两个子节点的数据结构。
class TreeNode {
int data;
TreeNode left, right;
TreeNode(int data) {
this.data = data;
left = right = null;
}
}
public class BinaryTreeExample {
TreeNode root;
// 添加节点
public void add(int data) {
root = addRecursive(root, data);
}
private TreeNode addRecursive(TreeNode node, int data) {
if (node == null) {
return new TreeNode(data);
}
if (data < node.data) {
node.left = addRecursive(node.left, data);
} else if (data > node.data) {
node.right = addRecursive(node.right, data);
}
return node;
}
// 打印二叉树(中序遍历)
public void printInOrder(TreeNode node) {
if (node != null) {
printInOrder(node.left);
System.out.print(node.data + " ");
printInOrder(node.right);
}
}
public static void main(String[] args) {
BinaryTreeExample tree = new BinaryTreeExample();
tree.add(5);
tree.add(3);
tree.add(7);
tree.printInOrder(tree.root); // 输出:3 5 7
}
}
# 堆(Heap)
堆是一种完全二叉树,满足特定的堆性质(最大堆或最小堆)。
import java.util.PriorityQueue;
public class HeapExample {
public static void main(String[] args) {
PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
// 添加元素
maxHeap.add(3);
maxHeap.add(5);
maxHeap.add(1);
// 取出最大元素
System.out.println(maxHeap.poll()); // 输出:5
// 遍历堆
for (int num : maxHeap) {
System.out.println(num);
}
}
}
# 跳表(Skip List)
跳表是一种数据结构,支持快速查找、插入和删除。
class Node {
int value;
Node[] next;
Node(int value, int level) {
this.value = value;
next = new Node[level + 1];
}
}
public class SkipListExample {
private static final int MAX_LEVEL = 4;
private Node head = new Node(-1, MAX_LEVEL);
// 插入元素
public void insert(int value) {
Node[] update = new Node[MAX_LEVEL + 1];
Node current = head;
for (int i = MAX_LEVEL; i >= 0; i--) {
while (current.next[i] != null && current.next[i].value < value) {
current = current.next[i];
}
update[i] = current;
}
int level = randomLevel();
Node newNode = new Node(value, level);
for (int i = 0; i <= level; i++) {
newNode.next[i] = update[i].next[i];
update[i].next[i] = newNode;
}
}
private int randomLevel() {
int level = 0;
while (Math.random() < 0.5 && level < MAX_LEVEL) {
level++;
}
return level;
}
// 打印跳表
public void printList() {
Node node = head.next[0];
while (node != null) {
System.out.print(node.value + " ");
node = node.next[0];
}
System.out.println();
}
public static void main(String[] args) {
SkipListExample list = new SkipListExample();
list.insert(3);
list.insert(6);
list.insert(7);
list.insert(9);
list.insert(12);
list.printList(); // 输出:3 6 7 9 12
}
}
# 图(Graph)
图由顶点和边组成,可以是有向图或无向图。
import java.util.*;
public class GraphExample {
private Map<Integer, List<Integer>> adjList = new HashMap<>();
// 添加边
public void addEdge(int src, int dest) {
adjList.putIfAbsent(src, new ArrayList<>());
adjList.get(src).add(dest);
}
// 打印图
public void printGraph() {
for (int src : adjList.keySet()) {
System.out.print(src + " -> ");
for (int dest : adjList.get(src)) {
System.out.print(dest + " ");
}
System.out.println();
}
}
public static void main(String[] args) {
GraphExample graph = new GraphExample();
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(1, 2);
graph.addEdge(2, 0);
graph.addEdge(2, 3);
graph.addEdge(3, 3);
graph.printGraph();
}
}
# 树(Tree)
树用于存储字符串集合,支持高效的前缀查询。
class TrieNode {
TrieNode[] children = new TrieNode[26];
boolean isEndOfWord;
}
public class TrieExample {
private TrieNode root = new TrieNode();
// 插入单词
public void insert(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
int index = c - '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 = root;
for (char c : word.toCharArray()) {
int index = c - 'a';
if (node.children[index] == null) {
return false;
}
node = node.children[index];
}
return node.isEndOfWord;
}
// 打印Trie树(中序遍历)
public void printTrie(TrieNode node, String prefix) {
if (node.isEndOfWord) {
System.out.println(prefix);
}
for (char c = 'a'; c <= 'z'; c++) {
int index = c - 'a';
if (node.children[index] != null) {
printTrie(node.children[index], prefix + c);
}
}
}
public static void main(String[] args) {
TrieExample trie = new TrieExample();
trie.insert("hello");
trie.insert("helium");
trie.insert("world");
System.out.println(trie.search("hello")); // 输出:true
System.out.println(trie.search("helix")); // 输出:false
trie.printTrie(trie.root, ""); // 输出:hello helium world
}
}
# 算法
10个算法:递归(Recursion)、排序(Sorting)、二分查找(Binary Search)、搜索(Search)、哈希算法(Hash Algorithm)、贪心算法(Greedy Algorithm)、分治算法(Divide and Conquer)、回溯算法(Backtracking)、动态规划(Dynamic Programming)、字符串匹配算法(String Matching Algorithm)
# 递归(Recursion)
递归是一种解决问题的方法,通过将问题分解为更小的子问题来求解。
public class RecursionExample {
// 计算阶乘
public static int factorial(int n) {
if (n == 0) {
return 1;
}
return n * factorial(n - 1);
}
public static void main(String[] args) {
System.out.println(factorial(5)); // 输出:120
}
}
# 排序(Sorting)
常见的排序算法有冒泡排序、选择排序、插入排序、快速排序、归并排序等。这里以快速排序为例。
public class QuickSort {
public static void quickSort(int[] array, int low, int high) {
if (low < high) {
int pi = partition(array, low, high);
quickSort(array, low, pi - 1);
quickSort(array, pi + 1, high);
}
}
private static int partition(int[] array, int low, int high) {
int pivot = array[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (array[j] < pivot) {
i++;
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
int temp = array[i + 1];
array[i + 1] = array[high];
array[high] = temp;
return i + 1;
}
public static void main(String[] args) {
int[] array = {10, 7, 8, 9, 1, 5};
quickSort(array, 0, array.length - 1);
for (int num : array) {
System.out.print(num + " ");
}
// 输出:1 5 7 8 9 10
}
}
# 二分查找(Binary Search)
二分查找是一种在有序数组中查找某一特定元素的搜索算法。
public class BinarySearchExample {
public static int binarySearch(int[] arr, int x) {
int low = 0, high = arr.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == x) {
return mid;
}
if (arr[mid] < x) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1; // 未找到元素
}
public static void main(String[] args) {
int[] arr = {2, 3, 4, 10, 40};
int result = binarySearch(arr, 10);
System.out.println(result); // 输出:3
}
}
# 搜索(Search)
搜索算法用于查找数据结构中的特定元素。这里以深度优先搜索(DFS)为例。
import java.util.*;
public class DepthFirstSearchExample {
private Map<Integer, List<Integer>> adjList = new HashMap<>();
// 添加边
public void addEdge(int src, int dest) {
adjList.putIfAbsent(src, new ArrayList<>());
adjList.get(src).add(dest);
}
// 深度优先搜索
public void DFS(int start) {
Set<Integer> visited = new HashSet<>();
DFSUtil(start, visited);
}
private void DFSUtil(int vertex, Set<Integer> visited) {
visited.add(vertex);
System.out.print(vertex + " ");
for (int neighbor : adjList.getOrDefault(vertex, new ArrayList<>())) {
if (!visited.contains(neighbor)) {
DFSUtil(neighbor, visited);
}
}
}
public static void main(String[] args) {
DepthFirstSearchExample graph = new DepthFirstSearchExample();
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(1, 2);
graph.addEdge(2, 0);
graph.addEdge(2, 3);
graph.addEdge(3, 3);
graph.DFS(2); // 输出:2 0 1 3
}
}
# 哈希算法(Hashing)
哈希算法将数据映射到固定大小的哈希表中。
import java.util.HashMap;
public class HashingExample {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
// 插入键值对
map.put("key1", 1);
map.put("key2", 2);
// 访问值
System.out.println(map.get("key1")); // 输出:1
// 删除键值对
map.remove("key2");
// 遍历哈希表
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
}
}
# 贪心算法(Greedy Algorithm)
贪心算法在每一步选择中都采取在当前状态下最好或最优的选择,从而希望导致结果是全局最好或最优的。
import java.util.Arrays;
import java.util.Comparator;
public class GreedyAlgorithmExample {
static class Item {
int value, weight;
Item(int value, int weight) {
this.value = value;
this.weight = weight;
}
}
// 分数背包问题
public static double fractionalKnapsack(int W, Item[] items) {
Arrays.sort(items, new Comparator<Item>() {
public int compare(Item a, Item b) {
double r1 = (double) a.value / a.weight;
double r2 = (double) b.value / b.weight;
return Double.compare(r2, r1);
}
});
int currentWeight = 0;
double finalValue = 0.0;
for (Item item : items) {
if (currentWeight + item.weight <= W) {
currentWeight += item.weight;
finalValue += item.value;
} else {
int remain = W - currentWeight;
finalValue += item.value * ((double) remain / item.weight);
break;
}
}
return finalValue;
}
public static void main(String[] args) {
Item[] items = { new Item(60, 10), new Item(100, 20), new Item(120, 30) };
int W = 50;
System.out.println(fractionalKnapsack(W, items)); // 输出:240.0
}
}
# 分治算法(Divide and Conquer)
分治算法将问题分成较小的子问题,递归地解决每个子问题,然后合并结果。
public class MergeSortExample {
// 归并排序
public static void mergeSort(int[] arr, int l, int r) {
if (l < r) {
int m = (l + r) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
private static void merge(int[] arr, int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int[] L = new int[n1];
int[] R = new int[n2];
System.arraycopy(arr, l, L, 0, n1);
System.arraycopy(arr, m + 1, R, 0, n2);
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
public static void main(String[] args) {
int[] arr = {12, 11, 13, 5, 6, 7};
mergeSort(arr, 0, arr.length - 1);
for (int num : arr) {
System.out.print(num + " ");
}
}
}
# 回溯算法(Backtracking)
回溯算法通过构建所有可能的解来解决问题,一旦发现某个解无法达到目标,就回溯到上一步。
public class BacktrackingExample {
private int N;
private int[][] board;
public BacktrackingExample(int N) {
this.N = N;
board = new int[N][N];
}
// 检查是否可以在board[row][col]放置皇后
private boolean isSafe(int row, int col) {
// 检查列
for (int i = 0; i < col; i++) {
if (board[row][i] == 1) {
return false;
}
}
// 检查左上对角线
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] == 1) {
return false;
}
}
// 检查右上对角线
for (int i = row, j = col; i >= 0 && j < N; i--, j++) {
if (board[i][j] == 1) {
return false;
}
}
return true;
}
// 回溯法解决N皇后问题
private boolean solveNQueens(int col) {
if (col >= N) {
return true; // 所有皇后都放置成功
}
for (int i = 0; i < N; i++) {
if (isSafe(i, col)) {
board[i][col] = 1; // 放置皇后
if (solveNQueens(col + 1)) {
return true;
}
board[i][col] = 0; // 回溯
}
}
return false;
}
// 打印棋盘
private void printBoard() {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(board[i][j] == 1 ? "Q " : ". ");
}
System.out.println();
}
}
public static void main(String[] args) {
int N = 8;
BacktrackingExample solver = new BacktrackingExample(N);
if (solver.solveNQueens(0)) {
solver.printBoard();
} else {
System.out.println("No solution exists");
}
}
}
# 动态规划(Dynamic Programming)
动态规划(Dynamic Programming,简称DP)是一种将复杂问题分解成更小的子问题来解决的技术。通过存储子问题的解来避免重复计算,从而提高效率。下面以经典的动态规划问题“最长公共子序列(LCS)”为例。
public class LCSExample {
// 计算两个字符串的最长公共子序列长度
public static int lcs(String s1, String s2) {
int m = s1.length();
int n = s2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (i == 0 || j == 0) {
dp[i][j] = 0;
} else if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}
public static void main(String[] args) {
String s1 = "AGGTAB";
String s2 = "GXTXAYB";
System.out.println("Length of LCS is " + lcs(s1, s2)); // 输出:4
}
}
# 字符串匹配算法(String Matching Algorithm)
字符串匹配算法用于在给定文本中找到子字符串(模式)的所有出现位置。KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,它利用部分匹配表来加速搜索过程。
public class KMPExample {
// 计算部分匹配表(LPS数组)
public static int[] computeLPSArray(String pattern) {
int n = pattern.length();
int[] lps = new int[n];
int length = 0; // 最长相同前缀后缀的长度
int i = 1;
lps[0] = 0; // lps[0]总是0
while (i < n) {
if (pattern.charAt(i) == pattern.charAt(length)) {
length++;
lps[i] = length;
i++;
} else {
if (length != 0) {
length = lps[length - 1];
} else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
// KMP搜索算法
public static void KMPsearch(String text, String pattern) {
int m = text.length();
int n = pattern.length();
int[] lps = computeLPSArray(pattern);
int i = 0; // text的索引
int j = 0; // pattern的索引
while (i < m) {
if (pattern.charAt(j) == text.charAt(i)) {
i++;
j++;
}
if (j == n) {
System.out.println("Pattern found at index " + (i - j));
j = lps[j - 1];
} else if (i < m && pattern.charAt(j) != text.charAt(i)) {
if (j != 0) {
j = lps[j - 1];
} else {
i++;
}
}
}
}
public static void main(String[] args) {
String text = "ababcabcabababd";
String pattern = "ababd";
KMPsearch(text, pattern); // 输出:Pattern found at index 10
}
}
# 基础算法
排序算法:冒泡排序、插入排序、选择排序、归并排序、快速排序、堆排序、希尔排序、基数排序等。 搜索算法:线性搜索、二分搜索、插值搜索、斐波那契搜索、深度优先搜索(DFS)、广度优先搜索(BFS)等。
# 数据结构算法
链表算法:插入、删除、反转链表、检测循环链表等。 栈和队列算法:栈的压栈、弹栈操作,队列的入队、出队操作等。 树算法:二叉树、AVL树、红黑树、B树、B+树等的插入、删除、搜索等。 图算法:图的遍历(DFS、BFS)、最短路径算法(Dijkstra、Floyd-Warshall、Bellman-Ford)、最小生成树算法(Prim、Kruskal)等。
# 动态规划
背包问题 最长公共子序列(LCS) 最短路径问题(如Floyd-Warshall算法也可以看作是一种动态规划) 0-1背包问题 矩阵链乘法
# 贪心算法
活动选择问题 分数背包问题 哈夫曼编码 最小生成树Prim算法也可以看作是一种贪心算法
# 回溯算法
八皇后问题 图的着色问题 旅行商问题(TSP)
# 分治算法
归并排序 快速排序 大整数乘法 二分搜索
# 分支限界法
整数规划 旅行商问题(TSP)的另一种解法
# 字符串算法
KMP(Knuth-Morris-Pratt)字符串匹配算法 Rabin-Karp字符串搜索算法 Boyer-Moore字符串搜索算法 正则表达式匹配
# 计算几何算法
点在多边形内判断 凸包算法(如Graham扫描法) 最近点对问题 碰撞检测
# 加密与解密算法
对称加密算法:DES、AES等 非对称加密算法:RSA、ECC等 哈希算法:MD5、SHA-1、SHA-256等
# 图像处理算法
边缘检测(如Canny边缘检测) 滤波算法(如高斯滤波、中值滤波) 形态学操作(如腐蚀、膨胀)
# 机器学习算法
线性回归 逻辑回归 决策树 随机森林 支持向量机(SVM) 神经网络(包括深度学习)
MySql →