手写 skip list,看看自己最近有多脑残

This commit is contained in:
YunaiV
2019-06-14 01:23:27 +08:00
parent 91a42184cb
commit c06797884e
6 changed files with 480 additions and 1 deletions

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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));
}
}

View File

@@ -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
*/

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}