diff --git a/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/graph/DijkstraTest.java b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/graph/DijkstraTest.java new file mode 100644 index 00000000..030a5732 --- /dev/null +++ b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/graph/DijkstraTest.java @@ -0,0 +1,71 @@ +package cn.iocoder.springboot.labs.lab09.graph; + +import java.util.LinkedList; +import java.util.List; + +public class DijkstraTest { + + public static class Graph { + + /** + * 顶点的个数 + */ + private int v; + /** + * 邻接表 + */ + private List[] adj; + + public Graph(int v) { + this.v = v; + adj = new LinkedList[v]; + for (int i = 0; i < v; i++) { + adj[i] = new LinkedList<>(); + } + } + + public void addEdge(int s, int t, int w) { + adj[s].add(new Edge(s, t, w)); + } + + } + + public static class Edge { + + /** + * 来源顶点 + */ + private int s; + /** + * 目标顶点 + */ + private int t; + /** + * 权重(距离) + */ + private int w; + + public Edge(int s, int t, int w) { + this.s = s; + this.t = t; + this.w = w; + } + + } + + public static class Vertex { + + /** + * 顶点编号 id + */ + private int id; + + /** + * 从起始顶点,到达此处的最短距离。 + */ + private int dist; + + } + + +} diff --git a/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/graph/Graph.java b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/graph/Graph.java new file mode 100644 index 00000000..57bfbf8c --- /dev/null +++ b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/graph/Graph.java @@ -0,0 +1,146 @@ +package cn.iocoder.springboot.labs.lab09.graph; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.atomic.AtomicBoolean; + +public class Graph { + + /** + * 顶点的个数 + */ + private int v; + /** + * 邻接表 + */ + private List[] adj; + + public Graph(int v) { + this.v = v; + adj = new LinkedList[v]; + for (int i = 0; i < v; i++) { + adj[i] = new LinkedList<>(); + } + } + + public void addEdge(int s, int t) { + adj[s].add(t); + adj[t].add(s); + } + + public void print() { + for (int i = 0; i < v; i++) { + System.out.print(i + " :"); + System.out.println(adj[i]); + } + } + + public void bfs(int s, int t) { + if (s == t) { + throw new IllegalStateException("参数不合理"); + } + // 初始化已访问 + boolean[] visited = new boolean[v]; + visited[s] = true; + + // 当前走到的路径 + Queue queue = new LinkedList<>(); + queue.add(s); + + // 记录哪个节点走到这里。通过它,实现路径的记录 + int[] prev = new int[v]; + Arrays.fill(prev, -1); + + while (queue.size() != 0) { + int w = queue.poll(); + for (int i = 0; i < adj[w].size(); i++) { + int q = adj[w].get(i); + if (!visited[q]) { + // 记录是从 w 走到 q + prev[q] = w; + // 判断是否到达目的地 + if (q == t) { + print(prev, s, t); + return; + } + visited[q] = true; + queue.add(q); + } + } + } + } + + public void dfs(int s, int t) { + if (s == t) { + throw new IllegalStateException("参数不合理"); + } + // 创建,标记是否找到 + AtomicBoolean found = new AtomicBoolean(false); + + // 初始化已访问 + boolean[] visited = new boolean[v]; + + // 记录哪个节点走到这里。通过它,实现路径的记录 + int[] prev = new int[v]; + Arrays.fill(prev, -1); + + // dfs 遍历 + dfs(s, t, found, visited, prev); + + if (found.get()) { + print(prev, s, t); + } else { + System.out.println("未找到路径..."); + } + } + + private void dfs(int w, int t, AtomicBoolean found, boolean[] visited, int[] prev) { + // 判断是否已经找到 + if (found.get()) { + return; + } + + // 标记已完成 + visited[w] = true; + + // 判断是否到达目的地 + if (w == t) { + found.set(true); + return; + } + + // 遍历 + for (int i = 0; i < adj[w].size(); i++) { + int q = adj[w].get(i); + if (!visited[q]) { + // 记录是从 w 走到 q + prev[q] = w; + // 继续递归 + dfs(q, t, found, visited, prev); + } + } + } + + // 递归打印从 s 到 t 的点 + public void print(int[] prev, int s, int t) { + if (prev[t] != -1 && t != s) { + print(prev, s, prev[t]); + } + System.out.print(t + " "); + } + + public static void main(String[] args) { + Graph graph = new Graph(10); + graph.addEdge(1, 3); + graph.addEdge(3, 5); + graph.addEdge(5, 7); +// graph.addEdge(9, 6); +// graph.print(); +// graph.bfs(1, 7); + graph.dfs(1, 7); + + } + +} diff --git a/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/match/RabinKarp.java b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/match/RabinKarp.java new file mode 100644 index 00000000..80b2a53c --- /dev/null +++ b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/match/RabinKarp.java @@ -0,0 +1,57 @@ +package cn.iocoder.springboot.labs.lab09.match; + +/** + * 参考 https://blog.csdn.net/jianke0503/article/details/79735928 文章 + * + * 实现 Rabin Karp 字符串查找 + */ +public class RabinKarp { + + // power 指数 + // base 计算超过范围,则返回 base + public static int find(String src, String target, int power, int base) { + // 计算长度 + int n = src.length(); + int m = target.length(); + + // target 的 hashcode + int targetCode = 0; + int mPower = 1; + for (int i = 0; i < m; i++) { + targetCode = (targetCode * power + target.charAt(i)) % base; + mPower = (mPower * power) % base; + } + + int srcCode = 0; + for (int i = 0; i < n; i++) { + srcCode = (srcCode * power + src.charAt(i)) % base; + if (i < m - 1) { // 不等于的原因是,i 是从 0 开始的。 + continue; + } + + if (i >= m) { // 此时,需要减掉头的 + srcCode = srcCode - ((src.charAt(i - m) * mPower) % base); + + // 避免减成负数 + if (srcCode < 0) { + srcCode = srcCode + base; + } + } + + if (srcCode == targetCode) { + if (src.substring(i - m + 1, i + 1).equals(target)) { + return i - m + 1; // + 1 的原因是,i 是从 0 开始,而 m 是从 1 开始。 + } + } + } + + return -1; + } + + public static void main(String[] args) { + String src = "2359023141526739921"; + String target = "5902"; + System.out.println(find(src, target, 31, 100)); + } + +} diff --git a/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/search/SkipList2.java b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/search/SkipList2.java index 231d9fb4..fdbebf63 100644 --- a/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/search/SkipList2.java +++ b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/search/SkipList2.java @@ -3,7 +3,11 @@ package cn.iocoder.springboot.labs.lab09.search; import java.util.Random; /** - * 参考 {@link SkipList} ,自己实现一遍跳表 + * 参考 {@link SkipList} ,自己实现一遍跳表。 + * + * 通过 {@link Node} 的 forwards 数组实现,确实挺巧妙,代码量也非常精简。 + * + * 目前,网络上找到的 Java 跳表实现,主要是 https://sylvanassun.github.io/2017/12/31/2017-12-31-skip_list/ 这种。实现方式略有差别。 * * @author yunai */ diff --git a/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/sort/HeapSorterTest.java b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/sort/HeapSorterTest.java new file mode 100644 index 00000000..979e2481 --- /dev/null +++ b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/sort/HeapSorterTest.java @@ -0,0 +1,134 @@ +package cn.iocoder.springboot.labs.lab09.sort; + +import java.util.Arrays; + +/** + * 堆排序 + */ +public class HeapSorterTest { + + public static void main(String[] args) { + if (false) { + HeapSorter heapSorter = new HeapSorter(10); + heapSorter.insert(10); + heapSorter.insert(3); + heapSorter.insert(5); + heapSorter.insert(1); + heapSorter.insert(2); + heapSorter.insert(20); + System.out.println(Arrays.toString(heapSorter.heap)); + + heapSorter.remove(2); + System.out.println(Arrays.toString(heapSorter.heap)); + } + + if (true) { + int[] array = {0, 10, 3, 5, 1, 2, 20}; + HeapSorter heapSorter = HeapSorter.create(array, array.length - 1); +// System.out.println(Arrays.toString(heapSorter.heap)); + heapSorter.sort(); + } + } + + public static class HeapSorter { + + /** + * 堆 + */ + private int[] heap; + /** + * 容量 + */ + private int capacity; + /** + * 元素数量 + */ + private int count; + + public HeapSorter(int[] heap, int count) { + this.capacity = heap.length; + this.heap = heap; + this.count = count; + } + + public HeapSorter(int capacity) { + this.capacity = capacity; + this.heap = new int[capacity + 1]; // 因为 0 被占用了 + count = 0; + } + + public void insert(int value) { + if (count >= capacity) { + throw new IllegalStateException("容量已满"); + } + ++count; + heap[count] = value; + + // 自下向上堆化,如果大于父节点 + int index = count; + while (index >> 1 > 0 && heap[index] > heap[index >> 1]) { + swap(index, index >> 1); + index = index >> 1; + } + } + + public int remove(int pos) { + if (count == 0) { + throw new IllegalStateException("不存在最大值"); + } + int tmp = heap[pos]; + heap[pos] = heap[count]; + heap[count] = 0; // 置空,其实非必要。就是为了好看 + count--; + + heapify(heap, count, pos); + return tmp; + } + + /** + * 排序 + */ + public void sort() { + while (count > 1) { + System.out.println(remove(1)); + } + } + + private void swap(int i, int j) { + swap(heap, i, j); + } + + public static HeapSorter create(int[] heap, int count) { + for (int i = count / 2; i >= 1; i--) { + heapify(heap, count, i); + } + return new HeapSorter(heap, count); + } + + private static void heapify(int[] heap, int count, int pos) { + // 自伤向下, + while (true) { + int maxPos = pos; + if (pos * 2 <= count && heap[pos] < heap[pos * 2]) { + maxPos = pos * 2; + } + if (pos * 2 + 1 <= count && heap[maxPos] < heap[pos * 2 + 1]) { + maxPos = pos * 2 + 1; + } + // 判断相等,说明没变化 + if (maxPos == pos) { + return; + } + swap(heap, pos, maxPos); + } + } + + private static void swap(int[] heap, int i, int j) { + int tmp = heap[i]; + heap[i] = heap[j]; + heap[j] = tmp; + } + + } + +} diff --git a/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/tree/MySQLBTreePlusTest.java b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/tree/MySQLBTreePlusTest.java new file mode 100644 index 00000000..5e440f0c --- /dev/null +++ b/lab-09/src/main/java/cn/iocoder/springboot/labs/lab09/tree/MySQLBTreePlusTest.java @@ -0,0 +1,67 @@ +package cn.iocoder.springboot.labs.lab09.tree; + +/** + * MySQL B+Tree + */ +public class MySQLBTreePlusTest { + + /** + * 非叶子节点 + */ + public static class Node { + + /** + * 5 叉树 + */ + public static int m = 5; + + /** + * 键值的数组 + * + * m - 1 的原因是,keywords 代表的是区间。 + * + * children[0] 的范围是 [ -无穷, keywords[0] ] + * children[1] 的泛微是 + */ + private int[] keywords = new int[m - 1]; + + /** + * 保存子节点的指针 + */ + private Node[] children = new Node[m]; + + } + + /** + * 叶子节点 + */ + public static class LeafNode { + + /** + * 假设每个叶子节点存储三个数据行的键值和数据地址信息 + */ + public static int k = 3; + + /** + * 数据行的键值 + * + * 不同于 {@link Node#keywords} ,这里表示的是具体值 + */ + private int[] keywords = new int[k]; + /** + * 数据航的地址值 + */ + private int[] dataAddresses = new int[k]; + + /** + * 前置的叶子节点,用于区间检索 + */ + private LeafNode prev; + /** + * 后置的叶子节点,用于区间检索 + */ + private LeafNode next; + + } + +}