diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5808138 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Intellij +.idea/* +*.iml +*.iws +out/* + +# Mac +.DS_Store + +# Maven +log/* +target/* \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index 97626ba..0000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index b08e5aa..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/libraries/Arquillian_JUnit_Release.xml b/.idea/libraries/Arquillian_JUnit_Release.xml deleted file mode 100644 index c21f710..0000000 --- a/.idea/libraries/Arquillian_JUnit_Release.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 0548357..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 790d7ab..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Algorithm.iml b/Algorithm.iml deleted file mode 100644 index c90834f..0000000 --- a/Algorithm.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/Caching/src/LRU.java b/Caching/src/LRU.java new file mode 100644 index 0000000..e10af02 --- /dev/null +++ b/Caching/src/LRU.java @@ -0,0 +1,109 @@ +import java.util.HashMap; +import java.util.Iterator; + +public class LRU implements Iterable { + + private Node head; + private Node tail; + private HashMap map; + private int maxSize; + + private class Node { + + Node pre; + Node next; + K k; + V v; + + public Node(K k, V v) { + this.k = k; + this.v = v; + } + } + + + public LRU(int maxSize) { + + this.maxSize = maxSize; + this.map = new HashMap<>(maxSize * 4 / 3); + + head = new Node(null, null); + tail = new Node(null, null); + + head.next = tail; + tail.pre = head; + } + + + public V get(K key) { + + if (!map.containsKey(key)) { + return null; + } + + Node node = map.get(key); + unlink(node); + appendHead(node); + + return node.v; + } + + + public void put(K key, V value) { + + if (map.containsKey(key)) { + Node node = map.get(key); + unlink(node); + } + + Node node = new Node(key, value); + map.put(key, node); + appendHead(node); + + if (map.size() > maxSize) { + Node toRemove = removeTail(); + map.remove(toRemove); + } + } + + + private void unlink(Node node) { + Node pre = node.pre; + node.pre = node.next; + node.next = pre; + } + + + private void appendHead(Node node) { + node.next = head.next; + head.next = node; + } + + + private Node removeTail() { + Node node = tail.pre; + node.pre = tail; + return node; + } + + + @Override + public Iterator iterator() { + + return new Iterator() { + private Node cur = head.next; + @Override + public boolean hasNext() { + return cur != tail; + } + + @Override + public K next() { + Node node = cur; + cur = cur.next; + return node.k; + } + }; + } + +} diff --git a/Caching/src/LRUTest.java b/Caching/src/LRUTest.java new file mode 100644 index 0000000..a1bb03b --- /dev/null +++ b/Caching/src/LRUTest.java @@ -0,0 +1,28 @@ +import org.junit.Test; + +import java.util.Iterator; + +import static org.junit.Assert.assertEquals; + +public class LRUTest { + @Test + public void test() { + + LRU lru = new LRU<>(3); + + lru.put("K1", "V1"); + lru.put("K2", "V2"); + lru.put("K3", "V3"); + + lru.get("K1"); + lru.get("K2"); + + lru.put("K4", "V4"); + + Iterator iterator = lru.iterator(); + + assertEquals(iterator.next(), "K4"); + assertEquals(iterator.next(), "K2"); + assertEquals(iterator.next(), "K1"); + } +} \ No newline at end of file diff --git a/Graph/src/Edge.java b/Graph/src/Edge.java new file mode 100644 index 0000000..4c63c34 --- /dev/null +++ b/Graph/src/Edge.java @@ -0,0 +1,33 @@ +public class Edge { + + private int v; // 顶点 + private int w; // 另一个顶点 + private double weight; // 权值 + + + public Edge(int v, int w, double weight) { + this.v = v; + this.w = w; + this.weight = weight; + } + + + public int getV() { + return v; + } + + + public int getW() { + return w; + } + + + public double getWeight() { + return weight; + } + + + public int getOther(int vertex) { + return vertex ^ (v ^ w); + } +} diff --git a/Graph/src/EdgeWeighGraph.java b/Graph/src/EdgeWeighGraph.java new file mode 100644 index 0000000..e9adad1 --- /dev/null +++ b/Graph/src/EdgeWeighGraph.java @@ -0,0 +1,42 @@ +import java.util.HashSet; +import java.util.Set; + +public class EdgeWeighGraph { + + private int V; // 顶点总数 + private Set[] adj; // 邻接表 + + + public EdgeWeighGraph(int v) { + this.V = v; + adj = new Set[V]; + for (int i = 0; i < V; i++) { + adj[i] = new HashSet<>(); + } + } + + + public void addEdge(Edge edge) { + adj[edge.getV()].add(edge); + adj[edge.getW()].add(edge); + } + + + public int getV() { + return V; + } + + + public Set adj(int v) { + return adj[v]; + } + + + public Set edges() { + Set edges = new HashSet<>(); + for (int i = 0; i < V; i++) { + edges.addAll(adj[i]); + } + return edges; + } +} diff --git a/Graph/src/KruskalMST.java b/Graph/src/KruskalMST.java new file mode 100644 index 0000000..4927503 --- /dev/null +++ b/Graph/src/KruskalMST.java @@ -0,0 +1,43 @@ +import java.util.Comparator; +import java.util.HashSet; +import java.util.PriorityQueue; +import java.util.Set; + +public class KruskalMST extends MST { + + private Set mst; + + + public KruskalMST(EdgeWeighGraph graph) { + + super(graph); + + mst = new HashSet<>(); + + PriorityQueue pq = new PriorityQueue<>(Comparator.comparing(Edge::getWeight)); + pq.addAll(graph.edges()); + + UF uf = new QuickUnionUF(graph.getV()); + + while (!pq.isEmpty() && mst.size() < graph.getV() - 1) { + + Edge edge = pq.poll(); + + int v = edge.getV(), w = edge.getW(); + + if (uf.connected(v, w)) { + continue; + } + + uf.connected(v, w); + mst.add(edge); + } + } + + + @Override + public Set getResult() { + return mst; + } + +} diff --git a/Graph/src/MST.java b/Graph/src/MST.java new file mode 100644 index 0000000..42fb517 --- /dev/null +++ b/Graph/src/MST.java @@ -0,0 +1,14 @@ +import java.util.Set; + +public abstract class MST { + + protected EdgeWeighGraph graph; + + + public MST(EdgeWeighGraph graph) { + this.graph = graph; + } + + + public abstract Set getResult(); +} diff --git a/Graph/src/MSTTest.java b/Graph/src/MSTTest.java new file mode 100644 index 0000000..13b85de --- /dev/null +++ b/Graph/src/MSTTest.java @@ -0,0 +1,55 @@ +import org.junit.Assert; + +import java.util.HashSet; +import java.util.Set; + +public class MSTTest { + + private EdgeWeighGraph graph; + private Set expect; + + + @org.junit.Before + public void data() { + + Edge edge1 = new Edge(0, 1, 1.0); + Edge edge2 = new Edge(1, 2, 2.0); + Edge edge3 = new Edge(2, 3, 3.0); + Edge edge4 = new Edge(3, 0, 4.0); + Edge edge5 = new Edge(0, 2, 5.0); + + graph = new EdgeWeighGraph(4); + graph.addEdge(edge1); + graph.addEdge(edge2); + graph.addEdge(edge3); + graph.addEdge(edge4); + graph.addEdge(edge5); + + expect = new HashSet<>(); + expect.add(edge1); + expect.add(edge2); + expect.add(edge3); + } + + @org.junit.Test + public void testPrimMST() { + test(new PrimMST(graph)); + } + + @org.junit.Test + public void testKruskalMST() { + test(new KruskalMST(graph)); + } + + private void test(MST mst) { + + Set result = mst.getResult(); + Assert.assertEquals(result.size(), expect.size()); + + for (Edge edge : result) { + Assert.assertTrue(expect.contains(edge)); + expect.remove(edge); + } + } + +} \ No newline at end of file diff --git a/Graph/src/PrimMST.java b/Graph/src/PrimMST.java new file mode 100644 index 0000000..ca8f9b2 --- /dev/null +++ b/Graph/src/PrimMST.java @@ -0,0 +1,59 @@ +import java.util.Comparator; +import java.util.HashSet; +import java.util.PriorityQueue; +import java.util.Set; + +public class PrimMST extends MST { + + private boolean[] marked; + private PriorityQueue pq; // 横切边 + private Set mst; // 最小生成树的边 + + + public PrimMST(EdgeWeighGraph graph) { + + super(graph); + + marked = new boolean[graph.getV()]; + pq = new PriorityQueue<>(Comparator.comparingDouble((Edge o) -> (o.getWeight()))); + mst = new HashSet<>(); + + visit(0); + + while (!pq.isEmpty()) { + + Edge edge = pq.poll(); + + int v = edge.getV(), w = edge.getW(); + + if (marked[v] && marked[w]) { + continue; + } + mst.add(edge); + if (!marked[v]) { + visit(v); + } + if (!marked[w]) { + visit(w); + } + } + } + + + @Override + public Set getResult() { + return mst; + } + + + private void visit(int v) { + + marked[v] = true; + + for (Edge edge : graph.adj(v)) { + if (!marked[edge.getOther(v)]) { + pq.add(edge); + } + } + } +} diff --git a/MultiThreading/src/AlternatePrint.java b/MultiThreading/src/AlternatePrint.java new file mode 100644 index 0000000..dfb424c --- /dev/null +++ b/MultiThreading/src/AlternatePrint.java @@ -0,0 +1,42 @@ +import java.util.concurrent.Semaphore; + +public class AlternatePrint { + + private static Semaphore[] semaphores; + private static final int ThreadNum = 3; + private static final int PrintNum = 10; + + + public static void main(String[] args) { + + semaphores = new Semaphore[ThreadNum]; + + for (int i = 0; i < ThreadNum; i++) { + semaphores[i] = new Semaphore(0); + } + + semaphores[0].release(); + + for (int i = 0; i < ThreadNum; i++) { + + final int cur = i; + final int next = (i + 1) % ThreadNum; + + new Thread(() -> { + + for (int j = 0; j < PrintNum; j++) { + + try { + semaphores[cur].acquire(); + char c = (char) ('A' + cur); + System.out.println(c); + semaphores[next].release(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + }).start(); + } + } +} diff --git a/Other/src/Hanoi.java b/Other/src/Hanoi.java new file mode 100644 index 0000000..5c38450 --- /dev/null +++ b/Other/src/Hanoi.java @@ -0,0 +1,19 @@ +public class Hanoi { + + public static void move(int n, String from, String buffer, String to) { + + if (n == 1) { + System.out.println("from " + from + " to " + to); + return; + } + + move(n - 1, from, to, buffer); + move(1, from, buffer, to); + move(n - 1, buffer, from, to); + } + + + public static void main(String[] args) { + Hanoi.move(3, "H1", "H2", "H3"); + } +} diff --git a/Other/src/Huffman.java b/Other/src/Huffman.java new file mode 100644 index 0000000..63e3e43 --- /dev/null +++ b/Other/src/Huffman.java @@ -0,0 +1,72 @@ +import java.util.HashMap; +import java.util.Map; +import java.util.PriorityQueue; + +public class Huffman { + + private class Node implements Comparable { + + char ch; + int freq; + boolean isLeaf; + Node left, right; + + + public Node(char ch, int freq) { + this.ch = ch; + this.freq = freq; + isLeaf = true; + } + + + public Node(Node left, Node right, int freq) { + this.left = left; + this.right = right; + this.freq = freq; + isLeaf = false; + } + + + @Override + public int compareTo(Node o) { + return this.freq - o.freq; + } + } + + + public Map encode(Map frequencyForChar) { + + PriorityQueue priorityQueue = new PriorityQueue<>(); + + for (Character c : frequencyForChar.keySet()) { + priorityQueue.add(new Node(c, frequencyForChar.get(c))); + } + + while (priorityQueue.size() != 1) { + Node node1 = priorityQueue.poll(); + Node node2 = priorityQueue.poll(); + priorityQueue.add(new Node(node1, node2, node1.freq + node2.freq)); + } + + return encode(priorityQueue.poll()); + } + + + private Map encode(Node root) { + + Map encodingForChar = new HashMap<>(); + encode(root, "", encodingForChar); + return encodingForChar; + } + + + private void encode(Node node, String encoding, Map encodingForChar) { + + if (node.isLeaf) { + encodingForChar.put(node.ch, encoding); + return; + } + encode(node.left, encoding + '0', encodingForChar); + encode(node.right, encoding + '1', encodingForChar); + } +} \ No newline at end of file diff --git a/Other/src/HuffmanTest.java b/Other/src/HuffmanTest.java new file mode 100644 index 0000000..2a77f71 --- /dev/null +++ b/Other/src/HuffmanTest.java @@ -0,0 +1,31 @@ +import org.junit.Assert; + +import java.util.HashMap; +import java.util.Map; + +public class HuffmanTest { + + @org.junit.Test + public void encode() { + + Huffman huffman = new Huffman(); + Map frequencyForChar = new HashMap<>(); + + frequencyForChar.put('a', 10); + frequencyForChar.put('b', 20); + frequencyForChar.put('c', 40); + frequencyForChar.put('d', 80); + + Map result = huffman.encode(frequencyForChar); + Map encoding = new HashMap<>(); + + encoding.put('a', "000"); + encoding.put('b', "001"); + encoding.put('c', "01"); + encoding.put('d', "1"); + + for (Character character : result.keySet()) { + Assert.assertEquals(result.get(character), encoding.get(character)); + } + } +} \ No newline at end of file diff --git a/Queue/Queue.iml b/Queue/Queue.iml deleted file mode 100644 index 3a8ffcf..0000000 --- a/Queue/Queue.iml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Queue/src/ListQueue.java b/Queue/src/ListQueue.java index 4eb2715..d6d40ee 100644 --- a/Queue/src/ListQueue.java +++ b/Queue/src/ListQueue.java @@ -1,30 +1,37 @@ import java.util.Iterator; public class ListQueue implements MyQueue { + private Node first; private Node last; int N = 0; + private class Node { Item item; Node next; } + @Override public boolean isEmpty() { return N == 0; } + @Override public int size() { return N; } + @Override public MyQueue add(Item item) { + Node newNode = new Node(); newNode.item = item; newNode.next = null; + if (isEmpty()) { last = newNode; first = newNode; @@ -32,32 +39,45 @@ public MyQueue add(Item item) { last.next = newNode; last = newNode; } + N++; return this; } + @Override public Item remove() throws Exception { - if (isEmpty()) + + if (isEmpty()) { throw new Exception("queue is empty"); + } + Node node = first; first = first.next; N--; - if (isEmpty()) + + if (isEmpty()) { last = null; + } + return node.item; } + @Override public Iterator iterator() { + return new Iterator() { + Node cur = first; + @Override public boolean hasNext() { return cur != null; } + @Override public Item next() { Item item = cur.item; diff --git a/Queue/src/MyQueue.java b/Queue/src/MyQueue.java index 1c97d58..8f2340e 100644 --- a/Queue/src/MyQueue.java +++ b/Queue/src/MyQueue.java @@ -1,4 +1,5 @@ public interface MyQueue extends Iterable { + int size(); boolean isEmpty(); diff --git a/Queue/src/Test.java b/Queue/src/Test.java index 756d0f7..1c38089 100644 --- a/Queue/src/Test.java +++ b/Queue/src/Test.java @@ -1,18 +1,25 @@ import org.junit.Assert; public class Test { + @org.junit.Test public void ListStackTest() throws Exception { + MyQueue queue = new ListQueue<>(); queue.add(1).add(2).add(3).add(4); - for (Integer item : queue) + + for (Integer item : queue) { System.out.println(item); + } + Assert.assertEquals(queue.size(), 4); Assert.assertFalse(queue.isEmpty()); - Assert.assertTrue(queue.remove() == 1); - Assert.assertTrue(queue.remove() == 2); - Assert.assertTrue(queue.remove() == 3); - Assert.assertTrue(queue.remove() == 4); + + Assert.assertEquals(1, (int) queue.remove()); + Assert.assertEquals(2, (int) queue.remove()); + Assert.assertEquals(3, (int) queue.remove()); + Assert.assertEquals(4, (int) queue.remove()); + Assert.assertTrue(queue.isEmpty()); } } diff --git a/README.md b/README.md index 9c58604..d3cb504 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,54 @@ 对代码的详细说明请参考:[算法](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E7%AE%97%E6%B3%95.md) -以下是实现计划列表,欢迎补充 - -- [x] ThreeSum -- [x] 栈 -- [x] 队列 -- [x] 并查集 -- [x] 红黑树 -- [x] 散列表 -- [x] 排序 +``` +| Caching +| ---- LRU // LRU 缓存淘汰算法 +| Graph +| ---- KruskalMST // Kruskal 最小生成树 +| ---- PrimMST // Prim 最小生成树 +| MultiThreading +| ---- AlternatePrint // 多线程交替打印 +| Other +| ---- Hanoi // 汉诺塔 +| ---- Huffman // 哈夫曼编码 +| Queue // 队列 +| Scheduling +| ---- FCFS // 先来先服务调度算法 +| ---- SJF // 最短进程优先调度算法 +| Searching +| ---- OrderedST +| -------- BinarySearchOrderedST // 二分查找实现的有序符号表 +| -------- BST // 二叉查找树 +| -------- RedBlackBST // 红黑二叉查找树 +| ---- Other +| -------- SparseVector // 稀疏矩阵 +| -------- Transaction // 交易类,用于演示散列函数的实现 +| ---- UnorderedST +| -------- LinearProbingHashST // 线性探测法实现的哈希表 +| -------- ListUnorderedST // 链表实现的无序符号表 +| Sorting +| ---- Bubble // 冒泡排序 +| ---- DownUpMergeSort // 自底向上归并排序 +| ---- Heap // 堆 +| ---- HeapSort // 堆排序 +| ---- Insertion // 插入排序 +| ---- QuickSort // 快速排序 +| ---- Selection // 选择排序 +| ---- Shell // 希尔排序 +| ---- ThreeWayQuickSort // 三路归并快速排序 +| ---- Up2DownMergeSort // 自顶向上归并排序 +| Stack +| ---- ArrayStack // 数组实现可动态扩容的栈 +| ---- ListStack // 链表实现的栈 +| ThreeSum +| ---- BinarySearch // 二分查找 +| ---- RatioTest // 倍率实验 +| ---- StopWatch // 计时器 +| ---- ThreeSumFast // 改进的 ThreeSum +| ---- ThreeSumSlow // 未改进的 ThreeSum +| Union-Find +| ---- QuickFindUF // 快速查找并查集 +| ---- QuickUnionUF // 快速合并并查集 +| ---- WeightedQuickUnionUF // 加权快速合并并查集 diff --git a/Scheduling/src/BatchScheduler.java b/Scheduling/src/BatchScheduler.java new file mode 100644 index 0000000..11d558a --- /dev/null +++ b/Scheduling/src/BatchScheduler.java @@ -0,0 +1,24 @@ +public class BatchScheduler extends Scheduler { + + public BatchScheduler(ProcessQueue processQueue) { + super(processQueue); + } + + + @Override + public void run() { + + while (true) { + if (!processQueue.isEmpty()) { + Process process = processQueue.get(); + process.run(process.getTotalTime()); + } + + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/Scheduling/src/FCFSClient.java b/Scheduling/src/FCFSClient.java new file mode 100644 index 0000000..dc91639 --- /dev/null +++ b/Scheduling/src/FCFSClient.java @@ -0,0 +1,13 @@ +public class FCFSClient { + + public static void main(String[] args) { + + ProcessQueue processQueue = new FCFSProcessQueue(); + + ProcessComeEmulator processComeEmulator = new ProcessComeEmulator(processQueue); + processComeEmulator.start(); + + Scheduler scheduler = new BatchScheduler(processQueue); + scheduler.start(); + } +} diff --git a/Scheduling/src/FCFSProcessQueue.java b/Scheduling/src/FCFSProcessQueue.java new file mode 100644 index 0000000..ee948ec --- /dev/null +++ b/Scheduling/src/FCFSProcessQueue.java @@ -0,0 +1,25 @@ +import java.util.LinkedList; +import java.util.Queue; + +public class FCFSProcessQueue implements ProcessQueue { + + private Queue queue = new LinkedList<>(); + + + @Override + public void add(Process process) { + queue.add(process); + } + + + @Override + public Process get() { + return queue.poll(); + } + + + @Override + public boolean isEmpty() { + return queue.isEmpty(); + } +} diff --git a/Scheduling/src/Process.java b/Scheduling/src/Process.java new file mode 100644 index 0000000..59add9a --- /dev/null +++ b/Scheduling/src/Process.java @@ -0,0 +1,50 @@ +/** + * 进程数据结构 + */ +public class Process { + + private String name; + private long totalTime; + private long remainTime; + private long comeInTime; + + + public Process(String name, long totalTime, long comeInTime) { + this.name = name; + this.totalTime = totalTime; + this.remainTime = totalTime; + this.comeInTime = comeInTime; + } + + + public void run(long runTime) { + + System.out.println("process " + name + " is running..."); + System.out.println("come in time : " + comeInTime); + System.out.println("total time : " + totalTime); + System.out.println("remain time : " + remainTime); + System.out.println(); + + remainTime -= runTime; + try { + Thread.sleep(runTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + + public long getTotalTime() { + return totalTime; + } + + + public long getRemainTime() { + return remainTime; + } + + + public long getComeInTime() { + return comeInTime; + } +} diff --git a/Scheduling/src/ProcessComeEmulator.java b/Scheduling/src/ProcessComeEmulator.java new file mode 100644 index 0000000..417713b --- /dev/null +++ b/Scheduling/src/ProcessComeEmulator.java @@ -0,0 +1,36 @@ +public class ProcessComeEmulator extends Thread { + + private ProcessQueue processQueue; + + + public ProcessComeEmulator(ProcessQueue processQueue) { + this.processQueue = processQueue; + } + + + @Override + public void run() { + + int processId = 0; + + while (true) { + + System.out.println("process " + processId + " is coming..."); + System.out.println(); + + Process process = new Process((processId++) + "", getRandomTime(), System.currentTimeMillis()); + processQueue.add(process); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + + private long getRandomTime() { + return (long) (Math.random() * 3000); + } +} diff --git a/Scheduling/src/ProcessQueue.java b/Scheduling/src/ProcessQueue.java new file mode 100644 index 0000000..adb16bc --- /dev/null +++ b/Scheduling/src/ProcessQueue.java @@ -0,0 +1,8 @@ +public interface ProcessQueue { + + void add(Process process); + + Process get(); + + boolean isEmpty(); +} diff --git a/Scheduling/src/SJFClient.java b/Scheduling/src/SJFClient.java new file mode 100644 index 0000000..e945782 --- /dev/null +++ b/Scheduling/src/SJFClient.java @@ -0,0 +1,13 @@ +public class SJFClient { + + public static void main(String[] args) { + + ProcessQueue processQueue = new SJFProcessQueue(); + + ProcessComeEmulator processComeEmulator = new ProcessComeEmulator(processQueue); + processComeEmulator.start(); + + Scheduler scheduler = new BatchScheduler(processQueue); + scheduler.start(); + } +} diff --git a/Scheduling/src/SJFProcessQueue.java b/Scheduling/src/SJFProcessQueue.java new file mode 100644 index 0000000..82452bc --- /dev/null +++ b/Scheduling/src/SJFProcessQueue.java @@ -0,0 +1,25 @@ +import java.util.PriorityQueue; + +public class SJFProcessQueue implements ProcessQueue { + + private PriorityQueue processesQueue = new PriorityQueue<>( + (o1, o2) -> (int) (o1.getTotalTime() - o2.getTotalTime())); + + + @Override + public void add(Process process) { + processesQueue.add(process); + } + + + @Override + public Process get() { + return processesQueue.poll(); + } + + + @Override + public boolean isEmpty() { + return processesQueue.isEmpty(); + } +} diff --git a/Scheduling/src/Scheduler.java b/Scheduling/src/Scheduler.java new file mode 100644 index 0000000..e408605 --- /dev/null +++ b/Scheduling/src/Scheduler.java @@ -0,0 +1,9 @@ +public class Scheduler extends Thread { + + protected ProcessQueue processQueue; + + + public Scheduler(ProcessQueue processQueue) { + this.processQueue = processQueue; + } +} diff --git a/Searching/Searching.iml b/Searching/Searching.iml deleted file mode 100644 index 3a8ffcf..0000000 --- a/Searching/Searching.iml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Searching/src/OrderedST/BST.java b/Searching/src/OrderedST/BST.java index cfa1eee..5dbc141 100644 --- a/Searching/src/OrderedST/BST.java +++ b/Searching/src/OrderedST/BST.java @@ -8,15 +8,19 @@ public class BST, Value> implements OrderedST 0) + + } else if (cmp > 0) { x.right = delete(x.right, key); - else { - if (x.right == null) + + } else { + + if (x.right == null) { return x.left; - if (x.left == null) + } + if (x.left == null) { return x.right; + } + Node t = x; + x = min(t.right); x.right = deleteMin(t.right); x.left = t.left; } + recalculateSize(x); + return x; } + @Override public Key max() { return max(root); } + private Key max(Node x) { - if (x == null) + + if (x == null) { return null; - if (x.right == null) + } + + if (x.right == null) { return x.key; + } + return max(x.right); } + @Override public int rank(Key key) { return rank(key, root); } + private int rank(Key key, Node x) { - if (x == null) + + if (x == null) { return 0; + } + int cmp = key.compareTo(x.key); - if (cmp == 0) + + if (cmp == 0) { return size(x.left); - else if (cmp < 0) + + } else if (cmp < 0) { return rank(key, x.left); - else + + } else { return 1 + size(x.left) + rank(key, x.right); + } } + @Override public List keys(Key l, Key h) { return keys(root, l, h); } + private List keys(Node x, Key l, Key h) { + List list = new ArrayList<>(); - if (x == null) + + if (x == null) { return list; + } + int cmpL = l.compareTo(x.key); int cmpH = h.compareTo(x.key); - if (cmpL < 0) + + if (cmpL < 0) { list.addAll(keys(x.left, l, h)); - if (cmpL <= 0 && cmpH >= 0) + } + if (cmpL <= 0 && cmpH >= 0) { list.add(x.key); - if (cmpH > 0) + } + if (cmpH > 0) { list.addAll(keys(x.right, l, h)); + } return list; } + protected void recalculateSize(Node x) { x.N = size(x.left) + size(x.right) + 1; } diff --git a/Searching/src/OrderedST/BinarySearchOrderedST.java b/Searching/src/OrderedST/BinarySearchOrderedST.java index 0e790cb..db04468 100644 --- a/Searching/src/OrderedST/BinarySearchOrderedST.java +++ b/Searching/src/OrderedST/BinarySearchOrderedST.java @@ -9,36 +9,49 @@ public class BinarySearchOrderedST, Value> implement private Value[] values; private int N = 0; + public BinarySearchOrderedST(int capacity) { keys = (Key[]) new Comparable[capacity]; values = (Value[]) new Object[capacity]; } + @Override public int size() { return N; } + @Override public int rank(Key key) { + int l = 0, h = N - 1; + while (l <= h) { + int m = l + (h - l) / 2; + int cmp = key.compareTo(keys[m]); - if (cmp == 0) + + if (cmp == 0) { return m; - else if (cmp < 0) + } else if (cmp < 0) { h = m - 1; - else + } else { l = m + 1; + } } return l; } + @Override public List keys(Key l, Key h) { + int index = rank(l); + List list = new ArrayList<>(); + while (keys[index].compareTo(h) <= 0) { list.add(keys[index]); index++; @@ -46,37 +59,49 @@ public List keys(Key l, Key h) { return list; } + @Override public void put(Key key, Value value) { + int index = rank(key); + // 如果找到已经存在的节点键位 key,就更新这个节点的值为 value if (index < N && keys[index].compareTo(key) == 0) { values[index] = value; return; } + // 否则在数组中插入新的节点,需要先将插入位置之后的元素都向后移动一个位置 for (int j = N; j > index; j--) { keys[j] = keys[j - 1]; values[j] = values[j - 1]; } + keys[index] = key; values[index] = value; N++; } + @Override public Value get(Key key) { + int index = rank(key); - if (index < N && keys[index].compareTo(key) == 0) + + if (index < N && keys[index].compareTo(key) == 0) { return values[index]; + } + return null; } + @Override public Key min() { return keys[0]; } + @Override public Key max() { return keys[N - 1]; diff --git a/Searching/src/OrderedST/OrderedSTTest.java b/Searching/src/OrderedST/OrderedSTTest.java index 1cb6295..d6d093a 100644 --- a/Searching/src/OrderedST/OrderedSTTest.java +++ b/Searching/src/OrderedST/OrderedSTTest.java @@ -9,31 +9,44 @@ public void BinarySearchOrderedSTTest() { test(new BinarySearchOrderedST(10)); } + @org.junit.Test public void BSTTest() { test(new BST()); } + @org.junit.Test - public void RedBlackBSTTest(){ + public void RedBlackBSTTest() { test(new RedBlackBST()); } + private void test(OrderedST st) { + Integer key1 = 2, key2 = 1, key3 = 3; String value1 = "b", value2 = "a", value3 = "c"; + st.put(key1, value1); - Assert.assertTrue(st.get(key1) == value1); + + Assert.assertSame(st.get(key1), value1); Assert.assertNull(st.get(key2)); + st.put(key2, value2); st.put(key3, value3); - Assert.assertTrue(st.get(key2) == value2); - Assert.assertTrue(st.min() == 1); - Assert.assertTrue(st.max() == 3); - Assert.assertTrue(st.size() == 3); - Assert.assertTrue(st.rank(2) == 1); + + Assert.assertSame(st.get(key2), value2); + + Assert.assertEquals(1, (int) st.min()); + Assert.assertEquals(3, (int) st.max()); + + Assert.assertEquals(3, st.size()); + Assert.assertEquals(1, st.rank(2)); + Assert.assertArrayEquals(st.keys(1, 2).toArray(new Integer[2]), new Integer[]{1, 2}); + st.put(key2, value1); - Assert.assertTrue(st.get(key2) == value1); + + Assert.assertSame(st.get(key2), value1); } } diff --git a/Searching/src/OrderedST/RedBlackBST.java b/Searching/src/OrderedST/RedBlackBST.java index 9e6935b..d807b17 100644 --- a/Searching/src/OrderedST/RedBlackBST.java +++ b/Searching/src/OrderedST/RedBlackBST.java @@ -1,36 +1,47 @@ package OrderedST; public class RedBlackBST, Value> extends BST { + private static final boolean RED = true; private static final boolean BLACK = false; + private boolean isRed(Node x) { if (x == null) return false; return x.color == RED; } + public Node rotateLeft(Node h) { + Node x = h.right; h.right = x.left; x.left = h; x.color = h.color; h.color = RED; x.N = h.N; + recalculateSize(h); + return x; } + public Node rotateRight(Node h) { + Node x = h.left; h.left = x.right; x.color = h.color; h.color = RED; x.N = h.N; + recalculateSize(h); + return x; } + void flipColors(Node h) { h.color = RED; h.left.color = BLACK; @@ -44,28 +55,39 @@ public void put(Key key, Value value) { root.color = BLACK; } + private Node put(Node x, Key key, Value value) { + if (x == null) { Node node = new Node(key, value, 1); node.color = RED; return node; } + int cmp = key.compareTo(x.key); - if (cmp == 0) + + if (cmp == 0) { x.val = value; - else if (cmp < 0) + + } else if (cmp < 0) { x.left = put(x.left, key, value); - else + + } else { x.right = put(x.right, key, value); + } - if (isRed(x.right) && !isRed(x.left)) + if (isRed(x.right) && !isRed(x.left)) { x = rotateLeft(x); - if (isRed(x.left) && isRed(x.left.left)) + } + if (isRed(x.left) && isRed(x.left.left)) { x = rotateRight(x); - if (isRed(x.left) && isRed(x.right)) + } + if (isRed(x.left) && isRed(x.right)) { flipColors(x); + } recalculateSize(x); + return x; } } \ No newline at end of file diff --git a/Searching/src/Other/SparseVector.java b/Searching/src/Other/SparseVector.java index 69ee490..cc84906 100644 --- a/Searching/src/Other/SparseVector.java +++ b/Searching/src/Other/SparseVector.java @@ -6,23 +6,32 @@ * 稀疏矩阵 */ public class SparseVector { + private HashMap hashMap; public SparseVector(double[] vector) { + hashMap = new HashMap<>(); - for (int i = 0; i < vector.length; i++) - if (vector[i] != 0) + + for (int i = 0; i < vector.length; i++) { + if (vector[i] != 0) { hashMap.put(i, vector[i]); + } + } } + public double get(int i) { return hashMap.getOrDefault(i, 0.0); } + public double dot(SparseVector other) { + double sum = 0; - for (int i : hashMap.keySet()) - sum += this.get(i) * other.get(i); + for (int i : hashMap.keySet()) { + sum = sum + this.get(i) * other.get(i); + } return sum; } } \ No newline at end of file diff --git a/Searching/src/Other/SparseVectorTest.java b/Searching/src/Other/SparseVectorTest.java index 234610e..b136a54 100644 --- a/Searching/src/Other/SparseVectorTest.java +++ b/Searching/src/Other/SparseVectorTest.java @@ -6,11 +6,14 @@ public class SparseVectorTest { @Test - public void dot() throws Exception { + public void dot() { + double[] vector1 = {1, 0, 0, 0, 1, 0}; double[] vector2 = {0, 0, 1, 1, 1, 0}; + SparseVector sparseVector1 = new SparseVector(vector1); SparseVector sparseVector2 = new SparseVector(vector2); + Assert.assertEquals(sparseVector1.dot(sparseVector2), 1, 0.0000001); } } \ No newline at end of file diff --git a/Searching/src/Other/Transaction.java b/Searching/src/Other/Transaction.java index d774a23..c0a3f28 100644 --- a/Searching/src/Other/Transaction.java +++ b/Searching/src/Other/Transaction.java @@ -6,16 +6,19 @@ * 交易类,用于演示 hashCode() 实现 */ public class Transaction { + private final String who; private final Date when; private final double amount; + public Transaction(String who, Date when, double amount) { this.who = who; this.when = when; this.amount = amount; } + public int hashCode() { int hash = 17; int R = 31; diff --git a/Searching/src/UnorderedST/LinearProbingHashST.java b/Searching/src/UnorderedST/LinearProbingHashST.java index a4c0c30..8bd2001 100644 --- a/Searching/src/UnorderedST/LinearProbingHashST.java +++ b/Searching/src/UnorderedST/LinearProbingHashST.java @@ -1,75 +1,94 @@ package UnorderedST; public class LinearProbingHashST implements UnorderedST { + private int N = 0; private int M = 16; private Key[] keys; private Value[] values; + public LinearProbingHashST() { init(); } + public LinearProbingHashST(int M) { this.M = M; init(); } + private void init() { keys = (Key[]) new Object[M]; values = (Value[]) new Object[M]; } + private int hash(Key key) { return (key.hashCode() & 0x7fffffff) % M; } + @Override public int size() { return N; } + @Override public void put(Key key, Value value) { resize(); putInternal(key, value); } + /** * 因为 put() 会调用 resize(),而 resize() 操作又需要将键值对重新插入 * 如果 resize() 又调用 put(),那么就会循环调用,不仅容易出错,而且会造成一些多于的检查步骤 */ private void putInternal(Key key, Value value) { + int i; - for (i = hash(key); keys[i] != null; i = (i + 1) % M) + + for (i = hash(key); keys[i] != null; i = (i + 1) % M) { if (keys[i].equals(key)) { values[i] = value; return; } + } keys[i] = key; values[i] = value; N++; } + @Override public Value get(Key key) { - for (int i = hash(key); keys[i] != null; i = (i + 1) % M) - if (keys[i].equals(key)) - return values[i]; + for (int i = hash(key); keys[i] != null; i = (i + 1) % M) { + if (keys[i].equals(key)) { + return values[i]; + } + } return null; } + @Override public void delete(Key key) { + int i = hash(key); - while (keys[i] != null && !key.equals(keys[i])) + + while (keys[i] != null && !key.equals(keys[i])) { i = (i + 1) % M; + } // 不存在,直接返回 - if (keys[i] == null) + if (keys[i] == null) { return; + } keys[i] = null; values[i] = null; @@ -77,30 +96,46 @@ public void delete(Key key) { // 将之后相连的键值对重新插入 i = (i + 1) % M; while (keys[i] != null) { + Key keyToRedo = keys[i]; Value valToRedo = values[i]; + keys[i] = null; values[i] = null; + N--; + putInternal(keyToRedo, valToRedo); + i = (i + 1) % M; } + N--; + resize(); } + private void resize() { - if (N >= M / 2) + + if (N >= M / 2) { resize(2 * M); - else if (N <= M / 8) + + } else if (N <= M / 8) { resize(M / 2); + } } + private void resize(int cap) { + LinearProbingHashST t = new LinearProbingHashST(cap); - for (int i = 0; i < M; i++) - if (keys[i] != null) + + for (int i = 0; i < M; i++) { + if (keys[i] != null) { t.putInternal(keys[i], values[i]); + } + } keys = t.keys; values = t.values; diff --git a/Searching/src/UnorderedST/ListUnorderedST.java b/Searching/src/UnorderedST/ListUnorderedST.java index 555dd85..782cc76 100644 --- a/Searching/src/UnorderedST/ListUnorderedST.java +++ b/Searching/src/UnorderedST/ListUnorderedST.java @@ -4,11 +4,14 @@ public class ListUnorderedST implements UnorderedST { private Node first; + private class Node { + Key key; Value value; Node next; + Node(Key key, Value value, Node next) { this.key = key; this.value = value; @@ -16,8 +19,10 @@ private class Node { } } + @Override public int size() { + int cnt = 0; Node cur = first; while (cur != null) { @@ -27,9 +32,12 @@ public int size() { return cnt; } + @Override public void put(Key key, Value value) { + Node cur = first; + // 如果在链表中找到节点的键等于 key 就更新这个节点的值为 value while (cur != null) { if (cur.key.equals(key)) { @@ -38,17 +46,24 @@ public void put(Key key, Value value) { } cur = cur.next; } + // 否则使用头插法插入一个新节点 first = new Node(key, value, first); } + @Override public void delete(Key key) { - if (first == null) + + if (first == null) { return; - if (first.key.equals(key)) + } + if (first.key.equals(key)) { first = first.next; + } + Node pre = first, cur = first.next; + while (cur != null) { if (cur.key.equals(key)) { pre.next = cur.next; @@ -59,14 +74,19 @@ public void delete(Key key) { } } + @Override public Value get(Key key) { + Node cur = first; + while (cur != null) { - if (cur.key.equals(key)) + if (cur.key.equals(key)) { return cur.value; + } cur = cur.next; } + return null; } } diff --git a/Searching/src/UnorderedST/UnorderedSTTest.java b/Searching/src/UnorderedST/UnorderedSTTest.java index 763ecea..29e0fff 100644 --- a/Searching/src/UnorderedST/UnorderedSTTest.java +++ b/Searching/src/UnorderedST/UnorderedSTTest.java @@ -9,23 +9,34 @@ public void ListUnorderedSTTest() { test(new ListUnorderedST()); } + @org.junit.Test public void LinearProbingHashSTTest() { test(new LinearProbingHashST()); } + private void test(UnorderedST st) { + String key1 = "a", key2 = "b"; int value1 = 1, value2 = 2; + st.put(key1, value1); - Assert.assertTrue(st.get(key1) == value1); + + Assert.assertEquals((int) st.get(key1), value1); Assert.assertNull(st.get(key2)); + st.put(key2, value2); - Assert.assertTrue(st.get(key2) == value2); - Assert.assertTrue(st.size() == 2); + + Assert.assertEquals((int) st.get(key2), value2); + Assert.assertEquals(2, st.size()); + st.put(key2, value1); - Assert.assertTrue(st.get(key2) == value1); + + Assert.assertEquals((int) st.get(key2), value1); + st.delete(key2); + Assert.assertNull(st.get(key2)); } } diff --git a/Sorting/Sorting.iml b/Sorting/Sorting.iml deleted file mode 100644 index 3a8ffcf..0000000 --- a/Sorting/Sorting.iml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Sorting/src/Bubble.java b/Sorting/src/Bubble.java index df91c74..22f698f 100644 --- a/Sorting/src/Bubble.java +++ b/Sorting/src/Bubble.java @@ -1,11 +1,12 @@ public class Bubble> extends Sort { + @Override public void sort(T[] nums) { int N = nums.length; boolean hasSorted = false; - for (int i = 0; i < N && !hasSorted; i++) { + for (int i = N - 1; i > 0 && !hasSorted; i--) { hasSorted = true; - for (int j = 0; j < N - i - 1; j++) { + for (int j = 0; j < i; j++) { if (less(nums[j + 1], nums[j])) { hasSorted = false; swap(nums, j, j + 1); diff --git a/Sorting/src/Down2UpMergeSort.java b/Sorting/src/Down2UpMergeSort.java index aaa9b92..7f0b061 100644 --- a/Sorting/src/Down2UpMergeSort.java +++ b/Sorting/src/Down2UpMergeSort.java @@ -1,10 +1,14 @@ public class Down2UpMergeSort> extends MergeSort { + @Override public void sort(T[] nums) { int N = nums.length; aux = (T[]) new Comparable[N]; - for (int sz = 1; sz < N; sz += sz) - for (int lo = 0; lo < N - sz; lo += sz + sz) + + for (int sz = 1; sz < N; sz += sz) { + for (int lo = 0; lo < N - sz; lo += sz + sz) { merge(nums, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, N - 1)); + } + } } } diff --git a/Sorting/src/Heap.java b/Sorting/src/Heap.java index 41e3cf0..8ff44a8 100644 --- a/Sorting/src/Heap.java +++ b/Sorting/src/Heap.java @@ -3,52 +3,64 @@ public class Heap> { private T[] heap; private int N = 0; + public Heap(int maxN) { this.heap = (T[]) new Comparable[maxN + 1]; } + public boolean isEmpty() { return N == 0; } + public int size() { return N; } + private boolean less(int i, int j) { return heap[i].compareTo(heap[j]) < 0; } + private void swap(int i, int j) { T t = heap[i]; heap[i] = heap[j]; heap[j] = t; } + private void swim(int k) { + while (k > 1 && less(k / 2, k)) { swap(k / 2, k); k = k / 2; } } + private void sink(int k) { while (2 * k <= N) { int j = 2 * k; - if (j < N && less(j, j + 1)) + if (j < N && less(j, j + 1)) { j++; - if (!less(k, j)) + } + if (!less(k, j)) { break; + } swap(k, j); k = j; } } + public void insert(T v) { heap[++N] = v; swim(N); } + public T delMax() { T max = heap[1]; swap(1, N--); diff --git a/Sorting/src/HeapSort.java b/Sorting/src/HeapSort.java index 96837a1..e3abdb2 100644 --- a/Sorting/src/HeapSort.java +++ b/Sorting/src/HeapSort.java @@ -1,12 +1,16 @@ public class HeapSort> extends Sort { + /** * 数组第 0 个位置不能有元素 */ @Override public void sort(T[] nums) { + int N = nums.length - 1; - for (int k = N / 2; k >= 1; k--) + + for (int k = N / 2; k >= 1; k--) { sink(nums, k, N); + } while (N > 1) { swap(nums, 1, N--); @@ -14,18 +18,23 @@ public void sort(T[] nums) { } } + private void sink(T[] nums, int k, int N) { + while (2 * k <= N) { int j = 2 * k; - if (j < N && less(nums, j, j + 1)) + if (j < N && less(nums, j, j + 1)) { j++; - if (!less(nums, k, j)) + } + if (!less(nums, k, j)) { break; + } swap(nums, k, j); k = j; } } + private boolean less(T[] nums, int i, int j) { return nums[i].compareTo(nums[j]) < 0; } diff --git a/Sorting/src/HeapSortTest.java b/Sorting/src/HeapSortTest.java index 71c14a1..e28cf57 100644 --- a/Sorting/src/HeapSortTest.java +++ b/Sorting/src/HeapSortTest.java @@ -7,13 +7,16 @@ * 需要单独创建一个测试类 */ public class HeapSortTest { + @Test - public void sort() throws Exception { + public void sort() { + Integer[] numsBefore = {0, 2, 3, 6, 5, 4, -1, -2, 0, Integer.MIN_VALUE, Integer.MAX_VALUE}; Integer[] numsAfter = {0, Integer.MIN_VALUE, -2, -1, 0, 2, 3, 4, 5, 6, Integer.MAX_VALUE}; + HeapSort sort = new HeapSort<>(); sort.sort(numsBefore); + Assert.assertArrayEquals(numsBefore, numsAfter); } - } \ No newline at end of file diff --git a/Sorting/src/HeapTest.java b/Sorting/src/HeapTest.java index 8776257..266df13 100644 --- a/Sorting/src/HeapTest.java +++ b/Sorting/src/HeapTest.java @@ -1,18 +1,24 @@ import org.junit.Assert; public class HeapTest { + @org.junit.Test public void test() { + Heap heap = new Heap<>(10); + heap.insert(5); heap.insert(4); heap.insert(6); heap.insert(1); + Assert.assertEquals(heap.size(), 4); - Assert.assertTrue(heap.delMax() == 6); - Assert.assertTrue(heap.delMax() == 5); - Assert.assertTrue(heap.delMax() == 4); - Assert.assertTrue(heap.delMax() == 1); + + Assert.assertEquals(6, (int) heap.delMax()); + Assert.assertEquals(5, (int) heap.delMax()); + Assert.assertEquals(4, (int) heap.delMax()); + Assert.assertEquals(1, (int) heap.delMax()); + Assert.assertTrue(heap.isEmpty()); } } \ No newline at end of file diff --git a/Sorting/src/Insertion.java b/Sorting/src/Insertion.java index d3fa3c0..5e04f4e 100644 --- a/Sorting/src/Insertion.java +++ b/Sorting/src/Insertion.java @@ -1,9 +1,12 @@ public class Insertion> extends Sort { + @Override public void sort(T[] nums) { int N = nums.length; - for (int i = 1; i < N; i++) - for (int j = i; j > 0 && less(nums[j], nums[j - 1]); j--) + for (int i = 1; i < N; i++) { + for (int j = i; j > 0 && less(nums[j], nums[j - 1]); j--) { swap(nums, j, j - 1); + } + } } } diff --git a/Sorting/src/MergeSort.java b/Sorting/src/MergeSort.java index abfe564..4234e9b 100644 --- a/Sorting/src/MergeSort.java +++ b/Sorting/src/MergeSort.java @@ -2,21 +2,28 @@ public abstract class MergeSort> extends Sort { protected T[] aux; + protected void merge(T[] nums, int l, int m, int h) { + int i = l, j = m + 1; - for (int k = l; k <= h; k++) + for (int k = l; k <= h; k++) { aux[k] = nums[k]; // 将数据复制到辅助数组 + } for (int k = l; k <= h; k++) { - if (i > m) + if (i > m) { nums[k] = aux[j++]; - else if (j > h) + + } else if (j > h) { nums[k] = aux[i++]; - else if (aux[i].compareTo(nums[j]) <= 0) + + } else if (aux[i].compareTo(nums[j]) <= 0) { nums[k] = aux[i++]; // 先进行这一步,保证稳定性 - else + + } else { nums[k] = aux[j++]; + } } } } diff --git a/Sorting/src/QuickSort.java b/Sorting/src/QuickSort.java index 7ab7c03..b3d620a 100644 --- a/Sorting/src/QuickSort.java +++ b/Sorting/src/QuickSort.java @@ -3,25 +3,27 @@ import java.util.List; public class QuickSort> extends Sort { - @Override - public void sort(T[] nums) { - shuffle(nums); - sort(nums, 0, nums.length - 1); - } - protected void sort(T[] nums, int l, int h) { - if (h <= l) - return; - int j = partition(nums, l, h); - sort(nums, l, j - 1); - sort(nums, j + 1, h); - } + @Override + public void sort(T[] nums) { + shuffle(nums); + sort(nums, 0, nums.length - 1); + } - private void shuffle(T[] nums) { - List list = Arrays.asList(nums); - Collections.shuffle(list); - list.toArray(nums); + protected void sort(T[] nums, int l, int h) { + if (h <= l) { + return; } + int j = partition(nums, l, h); + sort(nums, l, j - 1); + sort(nums, j + 1, h); + } + + private void shuffle(T[] nums) { + List list = Arrays.asList(nums); + Collections.shuffle(list); + list.toArray(nums); + } private int partition(T[] nums, int l, int h) { int i = l, j = h + 1; @@ -29,8 +31,9 @@ private int partition(T[] nums, int l, int h) { while (true) { while (less(nums[++i], v) && i != h) ; while (less(v, nums[--j]) && j != l) ; - if (i >= j) + if (i >= j) { break; + } swap(nums, i, j); } swap(nums, l, j); @@ -41,12 +44,16 @@ public T select(T[] nums, int k) { int l = 0, h = nums.length - 1; while (h > l) { int j = partition(nums, l, h); - if (j == k) + + if (j == k) { return nums[k]; - else if (j > k) + + } else if (j > k) { h = j - 1; - else + + } else { l = j + 1; + } } return nums[k]; } diff --git a/Sorting/src/Selection.java b/Sorting/src/Selection.java index fbec81f..6e18101 100644 --- a/Sorting/src/Selection.java +++ b/Sorting/src/Selection.java @@ -1,12 +1,15 @@ public class Selection> extends Sort { + @Override public void sort(T[] nums) { int N = nums.length; for (int i = 0; i < N; i++) { int min = i; - for (int j = i + 1; j < N; j++) - if (less(nums[j], nums[min])) + for (int j = i + 1; j < N; j++) { + if (less(nums[j], nums[min])) { min = j; + } + } swap(nums, i, min); } } diff --git a/Sorting/src/Shell.java b/Sorting/src/Shell.java index 8d7ad7f..c8d6695 100644 --- a/Sorting/src/Shell.java +++ b/Sorting/src/Shell.java @@ -1,15 +1,21 @@ public class Shell> extends Sort { + @Override public void sort(T[] nums) { + int N = nums.length; int h = 1; - while (h < N / 3) + + while (h < N / 3) { h = 3 * h + 1; // 1, 4, 13, 40, ... + } while (h >= 1) { - for (int i = h; i < N; i++) - for (int j = i; j >= h && less(nums[j], nums[j - h]); j -= h) + for (int i = h; i < N; i++) { + for (int j = i; j >= h && less(nums[j], nums[j - h]); j -= h) { swap(nums, j, j - h); + } + } h = h / 3; } } diff --git a/Sorting/src/Test.java b/Sorting/src/Test.java index df8359c..364b0f0 100644 --- a/Sorting/src/Test.java +++ b/Sorting/src/Test.java @@ -18,47 +18,57 @@ public class Test { {Integer.MIN_VALUE, Integer.MAX_VALUE} }; + @org.junit.Test public void SelectionTest() { test(new Selection<>()); } + @org.junit.Test public void BubbleTest() { test(new Bubble<>()); } + @org.junit.Test public void InsertionTest() { test(new Insertion<>()); } + @org.junit.Test public void ShellTest() { test(new Shell<>()); } + @org.junit.Test public void Up2DownMergeSortTest() { test(new Up2DownMergeSort<>()); } + @org.junit.Test public void Down2UpMergeSortTest() { test(new Down2UpMergeSort<>()); } + @org.junit.Test public void QuickSortTest() { test(new QuickSort<>()); } + @org.junit.Test public void ThreeWayQuickSortTest() { test(new ThreeWayQuickSort<>()); } + private void test(Sort sort) { + for (int i = 0; i < numsBefore.length; i++) { sort.sort(numsBefore[i]); Assert.assertArrayEquals(numsBefore[i], numsAfter[i]); diff --git a/Sorting/src/ThreeWayQuickSort.java b/Sorting/src/ThreeWayQuickSort.java index 4dc6c7a..60a5dd6 100644 --- a/Sorting/src/ThreeWayQuickSort.java +++ b/Sorting/src/ThreeWayQuickSort.java @@ -1,18 +1,21 @@ public class ThreeWayQuickSort> extends QuickSort { + @Override protected void sort(T[] nums, int l, int h) { - if (h <= l) + if (h <= l) { return; + } int lt = l, i = l + 1, gt = h; T v = nums[l]; while (i <= gt) { int cmp = nums[i].compareTo(v); - if (cmp < 0) + if (cmp < 0) { swap(nums, lt++, i++); - else if (cmp > 0) + } else if (cmp > 0) { swap(nums, i, gt--); - else + } else { i++; + } } sort(nums, l, lt - 1); sort(nums, gt + 1, h); diff --git a/Sorting/src/Up2DownMergeSort.java b/Sorting/src/Up2DownMergeSort.java index 36ac3b4..ebf599a 100644 --- a/Sorting/src/Up2DownMergeSort.java +++ b/Sorting/src/Up2DownMergeSort.java @@ -1,4 +1,5 @@ public class Up2DownMergeSort> extends MergeSort { + @Override public void sort(T[] nums) { aux = (T[]) new Comparable[nums.length]; @@ -6,8 +7,9 @@ public void sort(T[] nums) { } private void sort(T[] nums, int l, int h) { - if (h <= l) + if (h <= l) { return; + } int mid = l + (h - l) / 2; sort(nums, l, mid); sort(nums, mid + 1, h); diff --git a/Stack/Stack.iml b/Stack/Stack.iml deleted file mode 100644 index 3a8ffcf..0000000 --- a/Stack/Stack.iml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Stack/src/ArrayStack.java b/Stack/src/ArrayStack.java index 2c019ea..1d21358 100644 --- a/Stack/src/ArrayStack.java +++ b/Stack/src/ArrayStack.java @@ -4,11 +4,14 @@ * 使用数组实现的可以动态调整大小的栈 */ public class ArrayStack implements MyStack { + // 栈元素数组,只能通过转型来创建泛型数组 private Item[] a = (Item[]) new Object[1]; + // 元素数量 private int N = 0; + @Override public MyStack push(Item item) { check(); @@ -16,48 +19,69 @@ public MyStack push(Item item) { return this; } + @Override public Item pop() throws Exception { - if (isEmpty()) + + if (isEmpty()) { throw new Exception("stack is empty"); + } Item item = a[--N]; + check(); - a[N] = null; // 避免对象游离 + + // 避免对象游离 + a[N] = null; + return item; } + private void check() { - if (N >= a.length) + + if (N >= a.length) { resize(2 * a.length); - else if (N > 0 && N <= a.length / 4) + + } else if (N > 0 && N <= a.length / 4) { resize(a.length / 2); + } } + /** * 调整数组大小,使得栈具有伸缩性 */ private void resize(int size) { + Item[] tmp = (Item[]) new Object[size]; - for (int i = 0; i < N; i++) + + for (int i = 0; i < N; i++) { tmp[i] = a[i]; + } + a = tmp; } + @Override public boolean isEmpty() { return N == 0; } + @Override public int size() { return N; } + @Override public Iterator iterator() { + // 返回逆序遍历的迭代器 return new Iterator() { + private int i = N; @Override @@ -70,5 +94,6 @@ public Item next() { return a[--i]; } }; + } } \ No newline at end of file diff --git a/Stack/src/ListStack.java b/Stack/src/ListStack.java index d5752cf..8827b70 100644 --- a/Stack/src/ListStack.java +++ b/Stack/src/ListStack.java @@ -4,54 +4,75 @@ * 使用链表实现的栈 */ public class ListStack implements MyStack { + private Node top = null; private int N = 0; + private class Node { Item item; Node next; } + @Override public MyStack push(Item item) { + Node newTop = new Node(); + newTop.item = item; newTop.next = top; + top = newTop; + N++; + return this; } + @Override public Item pop() throws Exception { - if (isEmpty()) + + if (isEmpty()) { throw new Exception("stack is empty"); + } + Item item = top.item; + top = top.next; N--; + return item; } + @Override public boolean isEmpty() { return N == 0; } + @Override public int size() { return N; } + @Override public Iterator iterator() { + return new Iterator() { + private Node cur = top; + @Override public boolean hasNext() { return cur != null; } + @Override public Item next() { Item item = cur.item; @@ -59,5 +80,6 @@ public Item next() { return item; } }; + } } \ No newline at end of file diff --git a/Stack/src/MyStack.java b/Stack/src/MyStack.java index a50196f..643226e 100644 --- a/Stack/src/MyStack.java +++ b/Stack/src/MyStack.java @@ -1,4 +1,5 @@ public interface MyStack extends Iterable { + MyStack push(Item item); Item pop() throws Exception; @@ -6,4 +7,5 @@ public interface MyStack extends Iterable { boolean isEmpty(); int size(); + } diff --git a/Stack/src/Test.java b/Stack/src/Test.java index ba17adb..cd6dcfc 100644 --- a/Stack/src/Test.java +++ b/Stack/src/Test.java @@ -1,5 +1,7 @@ import org.junit.Assert; +import static org.junit.Assert.assertTrue; + public class Test { @org.junit.Test @@ -7,21 +9,30 @@ public void ResizingArrayStackTest() throws Exception { test(new ArrayStack<>()); } + @org.junit.Test public void ListStackTest() throws Exception { test(new ListStack<>()); } + private static void test(MyStack stack) throws Exception { + stack.push(1).push(2).push(3).push(4); + Assert.assertEquals(stack.size(), 4); Assert.assertFalse(stack.isEmpty()); - for (Integer item : stack) + + for (Integer item : stack) { System.out.println(item); - Assert.assertTrue(stack.pop() == 4); - Assert.assertTrue(stack.pop() == 3); - Assert.assertTrue(stack.pop() == 2); - Assert.assertTrue(stack.pop() == 1); - Assert.assertTrue(stack.isEmpty()); + } + + Assert.assertEquals(4, (int) stack.pop()); + Assert.assertEquals(3, (int) stack.pop()); + Assert.assertEquals(2, (int) stack.pop()); + Assert.assertEquals(1, (int) stack.pop()); + + assertTrue(stack.isEmpty()); + } } diff --git a/ThreeSum/ThreeSum.iml b/ThreeSum/ThreeSum.iml deleted file mode 100644 index 9b05c67..0000000 --- a/ThreeSum/ThreeSum.iml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ThreeSum/src/BinarySearch.java b/ThreeSum/src/BinarySearch.java index ff7018b..cfe898f 100644 --- a/ThreeSum/src/BinarySearch.java +++ b/ThreeSum/src/BinarySearch.java @@ -1,15 +1,24 @@ public class BinarySearch { + public static int search(int[] nums, int target) { + int l = 0, h = nums.length - 1; + while (l <= h) { + int m = l + (h - l) / 2; - if (target == nums[m]) + + if (target == nums[m]) { return m; - else if (target > nums[m]) + + } else if (target > nums[m]) { l = m + 1; - else + + } else { h = m - 1; + } } + return -1; } } diff --git a/ThreeSum/src/BinarySearchTest.java b/ThreeSum/src/BinarySearchTest.java index 1ef07da..b18920e 100644 --- a/ThreeSum/src/BinarySearchTest.java +++ b/ThreeSum/src/BinarySearchTest.java @@ -15,7 +15,7 @@ public class BinarySearchTest { }; @org.junit.Test - public void search() throws Exception { + public void search() { for (int i = 0; i < nums.length; i++) { Assert.assertEquals(BinarySearch.search(nums[i], targets[i]), expects[i]); } diff --git a/ThreeSum/src/RatioTest.java b/ThreeSum/src/RatioTest.java index fd8f408..f6e11f8 100644 --- a/ThreeSum/src/RatioTest.java +++ b/ThreeSum/src/RatioTest.java @@ -2,21 +2,31 @@ * 倍率实验 */ public class RatioTest { + public static void main(String[] args) { + int N = 500; int loopTimes = 7; double preTime = -1; + while (loopTimes-- > 0) { + int[] nums = new int[N]; + StopWatch.start(); + ThreeSum threeSum = new ThreeSumSlow(); + int cnt = threeSum.count(nums); System.out.println(cnt); + double elapsedTime = StopWatch.elapsedTime(); double ratio = preTime == -1 ? 0 : elapsedTime / preTime; System.out.println(N + " " + elapsedTime + " " + ratio); + preTime = elapsedTime; N *= 2; + } } } \ No newline at end of file diff --git a/ThreeSum/src/StopWatch.java b/ThreeSum/src/StopWatch.java index 6718cb3..1f0a6b5 100644 --- a/ThreeSum/src/StopWatch.java +++ b/ThreeSum/src/StopWatch.java @@ -2,12 +2,15 @@ * 用于统计算法运行时间 */ public class StopWatch { + private static long start; - - public static void start(){ + + + public static void start() { start = System.currentTimeMillis(); } - + + public static double elapsedTime() { long now = System.currentTimeMillis(); return (now - start) / 1000.0; diff --git a/ThreeSum/src/Test.java b/ThreeSum/src/Test.java index 9a07006..aae0184 100644 --- a/ThreeSum/src/Test.java +++ b/ThreeSum/src/Test.java @@ -5,17 +5,21 @@ public class Test { private final int[] nums = {-2, -1, 0, 1, 2}; private final int expect = 2; + @org.junit.Test public void ThreeSumTest() { test(new ThreeSumSlow()); } + @org.junit.Test public void ThreeSumFastTest() { test(new ThreeSumFast()); } + private void test(ThreeSum threeSum) { Assert.assertEquals(threeSum.count(nums), expect); } + } \ No newline at end of file diff --git a/ThreeSum/src/ThreeSumFast.java b/ThreeSum/src/ThreeSumFast.java index 373de37..c0f85d9 100644 --- a/ThreeSum/src/ThreeSumFast.java +++ b/ThreeSum/src/ThreeSumFast.java @@ -1,19 +1,29 @@ import java.util.Arrays; public class ThreeSumFast implements ThreeSum { + @Override public int count(int[] nums) { + Arrays.sort(nums); + int N = nums.length; int cnt = 0; - for (int i = 0; i < N; i++) + + for (int i = 0; i < N; i++) { + for (int j = i + 1; j < N; j++) { + int target = -nums[i] - nums[j]; int index = BinarySearch.search(nums, target); + // 应该注意这里的下标必须大于 j,否则会重复统计。 - if (index > j) + if (index > j) { cnt++; + } } + } + return cnt; } } \ No newline at end of file diff --git a/ThreeSum/src/ThreeSumSlow.java b/ThreeSum/src/ThreeSumSlow.java index 9a0254b..080a167 100644 --- a/ThreeSum/src/ThreeSumSlow.java +++ b/ThreeSum/src/ThreeSumSlow.java @@ -3,11 +3,15 @@ public class ThreeSumSlow implements ThreeSum { public int count(int[] nums) { int N = nums.length; int cnt = 0; - for (int i = 0; i < N; i++) - for (int j = i + 1; j < N; j++) - for (int k = j + 1; k < N; k++) - if (nums[i] + nums[j] + nums[k] == 0) + for (int i = 0; i < N; i++) { + for (int j = i + 1; j < N; j++) { + for (int k = j + 1; k < N; k++) { + if (nums[i] + nums[j] + nums[k] == 0) { cnt++; + } + } + } + } return cnt; } } \ No newline at end of file diff --git a/Union-Find/Union-Find.iml b/Union-Find/Union-Find.iml deleted file mode 100644 index 3a8ffcf..0000000 --- a/Union-Find/Union-Find.iml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Union-Find/src/QuickFindUF.java b/Union-Find/src/QuickFindUF.java index 08863d5..8c0072c 100644 --- a/Union-Find/src/QuickFindUF.java +++ b/Union-Find/src/QuickFindUF.java @@ -1,23 +1,30 @@ public class QuickFindUF extends UF { + public QuickFindUF(int N) { super(N); } + @Override public int find(int p) { return id[p]; } + @Override public void union(int p, int q) { + int pID = find(p); int qID = find(q); - if (pID == qID) + if (pID == qID) { return; + } - for (int i = 0; i < id.length; i++) - if (id[i] == pID) + for (int i = 0; i < id.length; i++) { + if (id[i] == pID) { id[i] = qID; + } + } } } diff --git a/Union-Find/src/QuickUnionUF.java b/Union-Find/src/QuickUnionUF.java index 1b37500..dedce87 100644 --- a/Union-Find/src/QuickUnionUF.java +++ b/Union-Find/src/QuickUnionUF.java @@ -1,20 +1,28 @@ public class QuickUnionUF extends UF { + public QuickUnionUF(int N) { super(N); } + @Override public int find(int p) { - while (p != id[p]) + + while (p != id[p]) { p = id[p]; + } return p; } + @Override public void union(int p, int q) { + int pRoot = find(p); int qRoot = find(q); - if (pRoot != qRoot) + + if (pRoot != qRoot) { id[pRoot] = qRoot; + } } } diff --git a/Union-Find/src/Test.java b/Union-Find/src/Test.java index e3a57b5..71e6351 100644 --- a/Union-Find/src/Test.java +++ b/Union-Find/src/Test.java @@ -4,27 +4,37 @@ public class Test { private final int N = 10; + @org.junit.Test public void QuickFindUFTest() { test(new QuickFindUF(N)); } + @org.junit.Test public void QuickUnionUFTest() { test(new QuickUnionUF(N)); } + @org.junit.Test public void WeightedQuickUnionUFTest() { test(new WeightedQuickUnionUF(N)); } + private void test(UF uf) { + uf.union(0, 1); + Assert.assertTrue(uf.connected(0, 1)); Assert.assertFalse(uf.connected(0, 2)); + uf.union(2, 3); uf.union(1, 2); + Assert.assertTrue(uf.connected(0, 3)); + } + } diff --git a/Union-Find/src/UF.java b/Union-Find/src/UF.java index b172ded..bc808e8 100644 --- a/Union-Find/src/UF.java +++ b/Union-Find/src/UF.java @@ -1,10 +1,12 @@ public abstract class UF { + protected int[] id; public UF(int N) { id = new int[N]; - for (int i = 0; i < N; i++) + for (int i = 0; i < N; i++) { id[i] = i; + } } public boolean connected(int p, int q) { diff --git a/Union-Find/src/WeightedQuickUnionUF.java b/Union-Find/src/WeightedQuickUnionUF.java index b817dff..7686c60 100644 --- a/Union-Find/src/WeightedQuickUnionUF.java +++ b/Union-Find/src/WeightedQuickUnionUF.java @@ -3,25 +3,33 @@ public class WeightedQuickUnionUF extends UF { // 保存节点的数量信息 private int[] sz; + public WeightedQuickUnionUF(int N) { super(N); this.sz = new int[N]; - for (int i = 0; i < N; i++) + for (int i = 0; i < N; i++) { this.sz[i] = 1; + } } + @Override public int find(int p) { - while (p != id[p]) + while (p != id[p]) { p = id[p]; + } return p; } + @Override public void union(int p, int q) { + int i = find(p); int j = find(q); + if (i == j) return; + if (sz[i] < sz[j]) { id[i] = j; sz[j] += sz[i]; diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..86387ba --- /dev/null +++ b/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + + groupId + Algorithm + 1.0-SNAPSHOT + + + + log4j + log4j + 1.2.17 + + + + \ No newline at end of file