mirror of
https://gitee.com/yudaocode/SpringBoot-Labs.git
synced 2026-09-29 03:59:24 +08:00
手写 skip list,看看自己最近有多脑残
This commit is contained in:
@@ -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<Edge>[] 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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<Integer>[] 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<Integer> 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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user