├── _config.yml ├── .gitignore ├── src ├── main │ └── java │ │ └── com │ │ └── github │ │ └── andavid │ │ └── ds │ │ ├── datastructure │ │ ├── tree │ │ │ ├── TreeNode.java │ │ │ ├── ArrayBinaryTree.java │ │ │ ├── BinarySearchTree.java │ │ │ └── BinaryTree.java │ │ ├── hash │ │ │ ├── HashtableUsage.java │ │ │ ├── LruCache.java │ │ │ ├── LinkedHashMapUsage.java │ │ │ ├── HashMapUsage.java │ │ │ ├── ConsistentHash.java │ │ │ ├── MyLinkedHashMap.java │ │ │ └── MyHashMap.java │ │ ├── linkedlist │ │ │ ├── FindMiddleNode.java │ │ │ ├── ListNode.java │ │ │ ├── RemoveNthNode.java │ │ │ ├── ReverseLinkedList.java │ │ │ ├── MergeTwoLinkedList.java │ │ │ ├── CycleLinkedList.java │ │ │ ├── CircularLinkedList.java │ │ │ ├── DoublyLinkedList.java │ │ │ └── SinglyLinkedList.java │ │ ├── array │ │ │ ├── MergeTwoSortedArray.java │ │ │ ├── SortedArray.java │ │ │ └── DynamicArray.java │ │ ├── heap │ │ │ ├── Topk.java │ │ │ ├── MedianFinder.java │ │ │ ├── PriorityQueueUsage.java │ │ │ ├── MergeSortedArray.java │ │ │ └── Heap.java │ │ ├── stack │ │ │ ├── StackUsage.java │ │ │ ├── LinkedStack.java │ │ │ ├── ArrayStack.java │ │ │ └── SampleBrowser.java │ │ ├── queue │ │ │ ├── ArrayQueue.java │ │ │ ├── QueueUsage.java │ │ │ ├── LinkedQueue.java │ │ │ └── CircularQueue.java │ │ ├── graph │ │ │ ├── TopoGraph.java │ │ │ └── Graph.java │ │ └── skiplist │ │ │ └── SkipList.java │ │ └── algorithm │ │ ├── sort │ │ ├── ShellSort.java │ │ ├── SelectionSort.java │ │ ├── BubbleSort.java │ │ ├── InsertionSort.java │ │ ├── FindKthLargest.java │ │ ├── QuickSort.java │ │ ├── MergeSort.java │ │ ├── HeapSort.java │ │ ├── RadixSort.java │ │ ├── CountingSort.java │ │ └── BucketSort.java │ │ ├── recursion │ │ ├── Permutation.java │ │ ├── Factorial.java │ │ └── Fibonacci.java │ │ ├── backtracking │ │ ├── Package.java │ │ └── EightQueen.java │ │ ├── stringmatch │ │ ├── KmpDfa.java │ │ ├── BruteForce.java │ │ ├── Kmp.java │ │ ├── TrieTreeFrequency.java │ │ ├── TrieTree.java │ │ ├── RabinKarp.java │ │ └── AhoCorasick.java │ │ ├── divideandconquer │ │ └── CountInversePairs.java │ │ ├── greedy │ │ └── Huffman.java │ │ └── search │ │ └── BinarySearch.java └── test │ └── java │ └── com │ └── github │ └── andavid │ └── ds │ ├── algorithm │ ├── backtracking │ │ ├── EightQueenTest.java │ │ └── PackageTest.java │ ├── sort │ │ ├── FindKthLargestTest.java │ │ ├── HeapSortTest.java │ │ ├── MergeSortTest.java │ │ ├── QuickSortTest.java │ │ ├── ShellSortTest.java │ │ ├── BubbleSortTest.java │ │ ├── RadixSortTest.java │ │ ├── CountingSortTest.java │ │ ├── SelectionSortTest.java │ │ ├── InsertionSortTest.java │ │ ├── BucketSortTest.java │ │ └── SortTest.java │ ├── recursion │ │ ├── PermutationTest.java │ │ ├── FibonacciTest.java │ │ └── FactorialTest.java │ ├── stringmatch │ │ ├── KmpTest.java │ │ ├── BruteForceTest.java │ │ ├── AhoCorasickTest.java │ │ ├── TrieTreeTest.java │ │ ├── RabinKarpTest.java │ │ ├── KmpDfaTest.java │ │ └── TrieTreeFrequencyTest.java │ ├── divideandconquer │ │ └── CountInversePairsTest.java │ ├── greedy │ │ └── HuffmanTest.java │ └── search │ │ └── BinarySearchTest.java │ └── datastructure │ ├── heap │ ├── TopkTest.java │ ├── MedianFinderTest.java │ └── MergeSortedArrayTest.java │ ├── queue │ ├── ArrayQueueTest.java │ ├── CircularQueueTest.java │ └── LinkedQueueTest.java │ ├── stack │ ├── ArrayStackTest.java │ ├── LinkedStackTest.java │ └── SampleBrowserTest.java │ ├── tree │ ├── ArrayBinaryTreeTest.java │ ├── BinarySearchTreeTest.java │ └── BinaryTreeTest.java │ ├── array │ ├── MergeTwoSortedArrayTest.java │ ├── SortedArrayTest.java │ └── DynamicArrayTest.java │ ├── linkedlist │ ├── FindMiddleNodeTest.java │ ├── CircularLinkedListTest.java │ ├── ReverseLinkedListTest.java │ ├── DoublyLinkedListTest.java │ ├── SinglyLinkedListTest.java │ ├── RemoveNthNodeTest.java │ ├── CycleLinkedListTest.java │ └── MergeTwoLinkedListTest.java │ ├── hash │ ├── LruCacheTest.java │ ├── MyLinkedHashMapTest.java │ ├── ConsistentHashTest.java │ └── MyHashMapTest.java │ ├── graph │ ├── TopoGraphTest.java │ └── GraphTest.java │ └── skiplist │ └── SkipListTest.java ├── pom.xml ├── note └── tree │ └── 二叉树遍历.md └── README.md /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | *.log 4 | 5 | hs_err_pid* 6 | 7 | .classpath 8 | .project 9 | .settings/ 10 | 11 | *.iml 12 | *.idea 13 | 14 | .vscode/ 15 | 16 | target/ 17 | out/ 18 | build/ 19 | 20 | .DS_Store -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/tree/TreeNode.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.tree; 2 | 3 | public class TreeNode { 4 | int val; 5 | TreeNode left; 6 | TreeNode right; 7 | 8 | public TreeNode(int x) { 9 | val = x; 10 | } 11 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/backtracking/EightQueenTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.backtracking; 2 | 3 | import org.junit.Test; 4 | 5 | public class EightQueenTest { 6 | 7 | @Test 8 | public void testEightQueen() { 9 | EightQueen instance = new EightQueen(); 10 | instance.cal8queens(0); 11 | } 12 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/FindKthLargestTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import org.junit.Test; 4 | 5 | public class FindKthLargestTest { 6 | 7 | @Test 8 | public void testFindKthLargest() { 9 | FindKthLargest instance = new FindKthLargest(); 10 | int[] data = {3,2,1,5,6,4}; 11 | System.out.println(instance.findKthLargest(data, 2)); 12 | } 13 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/heap/TopkTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.heap; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class TopkTest { 8 | 9 | @Test 10 | public void testTopk() { 11 | int[] data = {1,2,3,4,5,6,7,8,9,10}; 12 | Topk topk = new Topk(); 13 | int[] result = topk.topk(data, 5); 14 | System.out.println(Arrays.toString(result)); 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/backtracking/PackageTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.backtracking; 2 | 3 | import org.junit.Test; 4 | 5 | public class PackageTest { 6 | 7 | @Test 8 | public void testPackage() { 9 | int[] items = new int[] {10, 20, 30, 40, 35, 45, 55, 75}; 10 | Package pkg = new Package(); 11 | pkg.calMaxWeight(0, 0, items, 8, 102); 12 | System.out.println("最大值: " + pkg.maxWeight); 13 | } 14 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/heap/MedianFinderTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.heap; 2 | 3 | import org.junit.Test; 4 | 5 | public class MedianFinderTest { 6 | 7 | @Test 8 | public void testMedianFinder() { 9 | MedianFinder median = new MedianFinder(); 10 | median.addNum(1); 11 | median.addNum(2); 12 | median.addNum(3); 13 | median.addNum(4); 14 | System.out.println(median.findMedian()); 15 | } 16 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/recursion/PermutationTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.recursion; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.List; 6 | 7 | public class PermutationTest { 8 | 9 | @Test 10 | public void testPermutation() { 11 | Permutation instance = new Permutation(); 12 | int[] nums = {1, 2, 3}; 13 | List> result = instance.permute(nums); 14 | System.out.println(result); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/queue/ArrayQueueTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.queue; 2 | 3 | import org.junit.Test; 4 | 5 | public class ArrayQueueTest { 6 | 7 | @Test 8 | public void testArrayQueue() { 9 | ArrayQueue queue = new ArrayQueue(5); 10 | queue.enqueue("a"); 11 | queue.enqueue("b"); 12 | queue.enqueue("c"); 13 | queue.enqueue("d"); 14 | queue.enqueue("e"); 15 | queue.enqueue("f"); 16 | queue.dequeue(); 17 | queue.printAll(); 18 | } 19 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/stack/ArrayStackTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.stack; 2 | 3 | import org.junit.Test; 4 | 5 | public class ArrayStackTest { 6 | 7 | @Test 8 | public void testArrayStack() { 9 | ArrayStack stack = new ArrayStack(); 10 | stack.push(1); 11 | stack.push(2); 12 | stack.push(3); 13 | stack.push(4); 14 | System.out.println(stack.pop()); 15 | System.out.println(stack.peek()); 16 | System.out.println(stack.size()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/HeapSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class HeapSortTest { 8 | 9 | @Test 10 | public void testHeapSort() { 11 | HeapSort heapSort = new HeapSort(); 12 | int[] data = {8,2,5,9,7,3}; 13 | System.out.println("before heap sort: " + Arrays.toString(data)); 14 | heapSort.sort(data); 15 | System.out.println("after heap sort: " + Arrays.toString(data)); 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/heap/MergeSortedArrayTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.heap; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class MergeSortedArrayTest { 8 | 9 | @Test 10 | public void testMergeSortedArray() { 11 | MergeSortedArray instance = new MergeSortedArray(); 12 | int[][] array = {{1,3,5,7},{2,4,6},{8,9,10}}; 13 | int[] result = instance.mergeSortedArray(array); 14 | System.out.println(Arrays.toString(result)); 15 | } 16 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/stack/LinkedStackTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.stack; 2 | 3 | import org.junit.Test; 4 | 5 | public class LinkedStackTest { 6 | 7 | @Test 8 | public void testLinkedStack() { 9 | LinkedStack stack = new LinkedStack(); 10 | stack.push(1); 11 | stack.push(2); 12 | stack.push(3); 13 | stack.push(4); 14 | System.out.println(stack.pop()); 15 | System.out.println(stack.peek()); 16 | System.out.println(stack.size()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/tree/ArrayBinaryTreeTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.tree; 2 | 3 | import org.junit.Test; 4 | 5 | public class ArrayBinaryTreeTest { 6 | 7 | @Test 8 | public void testArrayBinaryTree() { 9 | int capacity = 7; 10 | 11 | ArrayBinaryTree tree = new ArrayBinaryTree(capacity); 12 | for (int i = 1; i <= capacity; i++) { 13 | tree.insert(i); 14 | } 15 | 16 | tree.preOrder(1); 17 | tree.inOrder(1); 18 | tree.postOrder(1); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/hash/HashtableUsage.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | import java.util.Hashtable; 4 | 5 | public class HashtableUsage { 6 | public static void main(String[] args) { 7 | Hashtable numbers = new Hashtable<>(); 8 | numbers.put("one", 1); 9 | numbers.put("two", 2); 10 | numbers.put("three", 3); 11 | 12 | Integer n = numbers.get("two"); 13 | if (n != null) { 14 | System.out.println("two = " + n); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/linkedlist/FindMiddleNode.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | public class FindMiddleNode { 4 | 5 | /** 6 | * 返回链表中间节点。 7 | * 如果链表有偶数个节点,那么中间节点有两个,返回后面的那个节点。 8 | */ 9 | public ListNode findMiddleNode(ListNode head) { 10 | ListNode slow = head; 11 | ListNode fast = head; 12 | 13 | while (fast != null && fast.next != null) { 14 | slow = slow.next; 15 | fast = fast.next.next; 16 | } 17 | 18 | return slow; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/MergeSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class MergeSortTest { 8 | @Test 9 | public void testMergeSort() { 10 | MergeSort mergeSort = new MergeSort(); 11 | int[] data = {9,8,7,6,5,4,3,2,1}; 12 | System.out.println("before merge sort: " + Arrays.toString(data)); 13 | mergeSort.sort(data); 14 | System.out.println("after merge sort: " + Arrays.toString(data)); 15 | } 16 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/QuickSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class QuickSortTest { 8 | 9 | @Test 10 | public void testQuickSort() { 11 | QuickSort quickSort = new QuickSort(); 12 | int[] data = {9,8,7,6,5,4,3,2,1}; 13 | System.out.println("before quick sort: " + Arrays.toString(data)); 14 | quickSort.sort(data); 15 | System.out.println("after quick sort: " + Arrays.toString(data)); 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/ShellSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class ShellSortTest { 8 | 9 | @Test 10 | public void testShellSort() { 11 | ShellSort shellSort = new ShellSort(); 12 | int[] data = {9,8,7,6,5,4,3,2,1}; 13 | System.out.println("before shell sort: " + Arrays.toString(data)); 14 | shellSort.sort(data); 15 | System.out.println("after shell sort: " + Arrays.toString(data)); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/array/MergeTwoSortedArrayTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.array; 2 | 3 | import java.util.Arrays; 4 | import org.junit.Test; 5 | 6 | public class MergeTwoSortedArrayTest { 7 | 8 | @Test 9 | public void testMerge() { 10 | MergeTwoSortedArray array = new MergeTwoSortedArray(); 11 | int[] arr1 = {1, 3, 5, 7}; 12 | int[] arr2 = {2, 4, 6, 8}; 13 | int[] arr = array.mergeTwoSortedArray(arr1, arr2); 14 | System.out.println(Arrays.toString(arr)); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/BubbleSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class BubbleSortTest { 8 | 9 | @Test 10 | public void testBubbleSort() { 11 | BubbleSort bubbleSort = new BubbleSort(); 12 | int[] data = {9,8,7,6,5,4,3,2,1}; 13 | System.out.println("before bubble sort: " + Arrays.toString(data)); 14 | bubbleSort.sort(data); 15 | System.out.println("after bubble sort: " + Arrays.toString(data)); 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/RadixSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class RadixSortTest { 8 | 9 | @Test 10 | public void testRadixSort() { 11 | RadixSort radixSort = new RadixSort(); 12 | int[] data = {892,846,821,199,810,700}; 13 | System.out.println("before radix sort: " + Arrays.toString(data)); 14 | radixSort.sort(data); 15 | System.out.println("after radix sort: " + Arrays.toString(data)); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/hash/LruCache.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | public class LruCache extends MyLinkedHashMap { 4 | private static final int MAX_CACHE_SIZE = 100; 5 | private int limit; 6 | 7 | public LruCache() { 8 | this(16, MAX_CACHE_SIZE); 9 | } 10 | 11 | public LruCache(int initialCapacity, int limit) { 12 | super(initialCapacity, true); 13 | this.limit = limit; 14 | } 15 | 16 | protected boolean removeEldestEntry(Entry eldest) { 17 | return size() > limit; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/CountingSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class CountingSortTest { 8 | 9 | @Test 10 | public void testCountingSort() { 11 | CountingSort countingSort = new CountingSort(); 12 | int[] data = {2,5,3,0,2,3,0,3}; 13 | System.out.println("before counting sort: " + Arrays.toString(data)); 14 | countingSort.sort(data); 15 | System.out.println("before counting sort: " + Arrays.toString(data)); 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/SelectionSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class SelectionSortTest { 8 | 9 | @Test 10 | public void testBubbleSort() { 11 | SelectionSort selectionSort = new SelectionSort(); 12 | int[] data = {9,8,7,6,5,4,3,2,1}; 13 | System.out.println("before selection sort: " + Arrays.toString(data)); 14 | selectionSort.sort(data); 15 | System.out.println("after selection sort: " + Arrays.toString(data)); 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/InsertionSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class InsertionSortTest { 8 | 9 | @Test 10 | public void testInsertionSort() { 11 | InsertionSort insertionSort = new InsertionSort(); 12 | int[] data = {9,8,7,6,5,4,3,2,1}; 13 | System.out.println("before insertion sort: " + Arrays.toString(data)); 14 | insertionSort.sort(data); 15 | System.out.println("after insertion sort: " + Arrays.toString(data)); 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/BucketSortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class BucketSortTest { 8 | 9 | @Test 10 | public void testBucketSort() { 11 | BucketSort bucketSort = new BucketSort(); 12 | int[] data = {22,5,11,41,45,26,29,10,7,8,30,27,42,43,40}; 13 | System.out.println("before bucket sort: " + Arrays.toString(data)); 14 | bucketSort.sort(data); 15 | System.out.println("after bucket sort: " + Arrays.toString(data)); 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/array/SortedArrayTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.array; 2 | 3 | import org.junit.Test; 4 | 5 | public class SortedArrayTest { 6 | 7 | @Test 8 | public void testSortedArray() { 9 | SortedArray array = new SortedArray(5); 10 | array.add(3); 11 | array.add(1); 12 | array.add(5); 13 | array.add(2); 14 | array.add(4); 15 | System.out.println(array); 16 | 17 | array.remove(2); 18 | System.out.println(array); 19 | 20 | array.add(6); 21 | array.add(7); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/stringmatch/KmpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | import org.junit.Test; 4 | 5 | public class KmpTest { 6 | 7 | @Test 8 | public void testKmp() { 9 | String pattern = "search"; 10 | Kmp kmp = new Kmp(pattern); 11 | String src = "substring searching algorithm"; 12 | System.out.println(src); 13 | int index = kmp.match(src); 14 | for (int i = 0; i < index; i++) { 15 | System.out.print(" "); 16 | } 17 | System.out.println(pattern); 18 | System.out.println(index); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/linkedlist/FindMiddleNodeTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | import org.junit.Test; 4 | 5 | public class FindMiddleNodeTest { 6 | 7 | @Test 8 | public void testFindMiddleNode() { 9 | ListNode head = new ListNode(1); 10 | head.next = new ListNode(2); 11 | head.next.next = new ListNode(3); 12 | System.out.println(head); 13 | 14 | FindMiddleNode instance = new FindMiddleNode(); 15 | ListNode middleNode = instance.findMiddleNode(head); 16 | System.out.println(middleNode.val); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/linkedlist/CircularLinkedListTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | import org.junit.Test; 4 | 5 | public class CircularLinkedListTest { 6 | 7 | @Test 8 | public void testCircularLinkedList() { 9 | CircularLinkedList list = new CircularLinkedList(); 10 | list.print(); 11 | 12 | list.insertHead(1); 13 | list.print(); 14 | 15 | list.insertHead(2); 16 | list.insertTail(3); 17 | list.print(); 18 | 19 | list.deleteHead(); 20 | list.print(); 21 | 22 | list.deleteTail(); 23 | list.print(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/linkedlist/ListNode.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | public class ListNode { 4 | public int val; 5 | public ListNode next; 6 | 7 | public ListNode(int val) { 8 | this.val = val; 9 | } 10 | 11 | public String toString() { 12 | StringBuilder sb = new StringBuilder(); 13 | sb.append("["); 14 | for (ListNode p = this; p != null; p = p.next) { 15 | sb.append(p.val); 16 | if (p.next != null) { 17 | sb.append(",").append(" "); 18 | } 19 | } 20 | sb.append("]"); 21 | return sb.toString(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/divideandconquer/CountInversePairsTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.divideandconquer; 2 | 3 | import org.junit.Test; 4 | 5 | public class CountInversePairsTest { 6 | 7 | @Test 8 | public void testCountInversePairs() { 9 | CountInversePairs instance = new CountInversePairs(); 10 | int[] data1 = {7, 5, 6, 4}; 11 | System.out.println(instance.count(data1)); 12 | 13 | int[] data2 = {5, 6, 7, 8, 1, 2, 3, 4}; 14 | System.out.println(instance.count(data2)); 15 | 16 | int[] data3 = {4, 3, 11, 15, 13, 2, 8}; 17 | System.out.println(instance.count(data3)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/stringmatch/BruteForceTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | import org.junit.Test; 4 | 5 | public class BruteForceTest { 6 | 7 | @Test 8 | public void testBruteForce() { 9 | BruteForce bf = new BruteForce(); 10 | System.out.println(bf.match("abcdef", "def")); 11 | System.out.println(bf.match("aaaaab", "ab")); 12 | System.out.println(bf.match("aaaaaa", "ab")); 13 | System.out.println(); 14 | System.out.println(bf.find("abcdef", "def")); 15 | System.out.println(bf.find("aaaaab", "ab")); 16 | System.out.println(bf.find("aaaaaa", "ab")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/queue/CircularQueueTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.queue; 2 | 3 | import org.junit.Test; 4 | 5 | public class CircularQueueTest { 6 | 7 | @Test 8 | public void testCircularQueue() { 9 | CircularQueue queue = new CircularQueue(5); 10 | System.out.println(queue); 11 | 12 | queue.enqueue("a"); 13 | queue.enqueue("b"); 14 | queue.enqueue("c"); 15 | queue.enqueue("d"); 16 | queue.enqueue("e"); 17 | queue.enqueue("f"); 18 | System.out.println(queue); 19 | 20 | queue.dequeue(); 21 | queue.dequeue(); 22 | System.out.println(queue); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/linkedlist/RemoveNthNode.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | /** 4 | * 删除链表倒数第 N 个节点 5 | */ 6 | public class RemoveNthNode { 7 | public ListNode removeNthFromEnd(ListNode head, int n) { 8 | ListNode dummy = new ListNode(0); 9 | dummy.next = head; 10 | ListNode slow = dummy; 11 | ListNode fast = dummy; 12 | 13 | for (int i = 0; i < n; i++) { 14 | fast = fast.next; 15 | } 16 | 17 | while (fast.next != null) { 18 | slow = slow.next; 19 | fast = fast.next; 20 | } 21 | 22 | slow.next = slow.next.next; 23 | 24 | return dummy.next; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/hash/LruCacheTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | import org.junit.Test; 4 | 5 | public class LruCacheTest { 6 | 7 | @Test 8 | public void testLruCache() { 9 | LruCache cache = new LruCache(4, 6); 10 | cache.put("1", "a"); 11 | cache.put("4", "d"); 12 | cache.put("2", "b"); 13 | cache.put("3", "c"); 14 | cache.put("5", "e"); 15 | cache.put("8", "h"); 16 | cache.put("6", "f"); 17 | cache.put("7", "g"); 18 | cache.printAll(); 19 | 20 | cache.remove("5"); 21 | cache.get("6"); 22 | cache.put("2", "x"); 23 | cache.put("9", "y"); 24 | cache.printAll(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/queue/LinkedQueueTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.queue; 2 | 3 | import org.junit.Test; 4 | 5 | public class LinkedQueueTest { 6 | 7 | @Test 8 | public void testLinkedQueue() { 9 | LinkedQueue queue = new LinkedQueue(); 10 | System.out.println(queue); 11 | queue.enqueue(1); 12 | queue.enqueue(2); 13 | queue.enqueue(3); 14 | queue.enqueue(4); 15 | System.out.println(queue); 16 | 17 | queue.dequeue(); 18 | queue.dequeue(); 19 | System.out.println(queue); 20 | 21 | queue.dequeue(); 22 | queue.dequeue(); 23 | System.out.println(queue); 24 | 25 | queue.dequeue(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/stringmatch/AhoCorasickTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | import org.junit.Test; 4 | 5 | public class AhoCorasickTest { 6 | 7 | @Test 8 | public void test() { 9 | String[] patterns = {"at", "art", "oars", "soar"}; 10 | AhoCorasick ac = new AhoCorasick(patterns); 11 | System.out.println(ac.match("soarsoars")); 12 | 13 | 14 | String[] patterns2 = {"Fxtec Pro1", "谷歌 Pixel"}; 15 | ac = new AhoCorasick(patterns2); 16 | String txt = "一家总部位于伦敦的公司 Fxtex 在 MWC 上就推出了一款名为 Fxtec Pro1 的手机,该机最大的亮点就是采用了侧滑式全键盘设计。DxOMark 年度总榜发布 华为 P20 Pro / 谷歌 Pixel 3 争冠"; 17 | System.out.println(ac.match(txt)); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/graph/TopoGraphTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.graph; 2 | 3 | import org.junit.Test; 4 | 5 | public class TopoGraphTest { 6 | 7 | @Test 8 | public void testTopoGraph() { 9 | TopoGraph graph = new TopoGraph(4); 10 | graph.addEdge(0, 1); 11 | graph.addEdge(0, 2); 12 | graph.addEdge(1, 2); 13 | graph.addEdge(1, 3); 14 | graph.addEdge(2, 3); 15 | graph.kahn(); 16 | System.out.println(); 17 | 18 | graph = new TopoGraph(4); 19 | graph.addEdge(0, 1); 20 | graph.addEdge(0, 2); 21 | graph.addEdge(1, 2); 22 | graph.addEdge(2, 3); 23 | graph.addEdge(3, 1); 24 | graph.kahn(); 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/hash/MyLinkedHashMapTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | import org.junit.Test; 4 | 5 | public class MyLinkedHashMapTest { 6 | 7 | @Test 8 | public void testMyLinkedHashMap() { 9 | MyLinkedHashMap m1 = new MyLinkedHashMap(4); 10 | m1.put("1", "a"); 11 | m1.put("4", "d"); 12 | m1.put("2", "b"); 13 | m1.put("3", "c"); 14 | m1.printAll(); 15 | 16 | MyLinkedHashMap m2 = new MyLinkedHashMap(4, true); 17 | m2.put("3", "11"); 18 | m2.put("1", "12"); 19 | m2.put("5", "23"); 20 | m2.put("2", "22"); 21 | 22 | m2.put("3", "26"); 23 | m2.get("5"); 24 | m2.remove("1"); 25 | m2.printAll(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/linkedlist/ReverseLinkedListTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | import org.junit.Test; 4 | 5 | public class ReverseLinkedListTest { 6 | 7 | @Test 8 | public void testReverseLinkedList() { 9 | ListNode head = new ListNode(1); 10 | head.next = new ListNode(2); 11 | head.next.next = new ListNode(3); 12 | head.next.next.next = new ListNode(4); 13 | System.out.println(head); 14 | 15 | ReverseLinkedList instance = new ReverseLinkedList(); 16 | ListNode node = instance.reverseList(head); 17 | System.out.println(node); 18 | 19 | node = instance.reverseListRecursively(node); 20 | System.out.println(node); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/ShellSort.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | public class ShellSort { 4 | 5 | public void sort(int[] array) { 6 | if (array == null || array.length <= 1) { 7 | return; 8 | } 9 | shellSort(array, array.length); 10 | } 11 | 12 | public void shellSort(int[] array, int n) { 13 | int gap = n / 2; 14 | while (gap >= 1) { 15 | for (int i = gap; i < n; i++) { 16 | int temp = array[i]; 17 | int j = i - gap; 18 | while (j >= 0 && array[j] > temp) { 19 | array[j + gap] = array[j]; 20 | j = j - gap; 21 | } 22 | array[j + gap] = temp; 23 | } 24 | gap = gap / 2; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/linkedlist/DoublyLinkedListTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | import org.junit.Test; 4 | 5 | public class DoublyLinkedListTest { 6 | 7 | @Test 8 | public void testDoublyLinkedList() { 9 | DoublyLinkedList list = new DoublyLinkedList(); 10 | list.print(); 11 | 12 | list.insertHead(1); 13 | list.print(); 14 | 15 | list.insertHead(2); 16 | list.insertTail(3); 17 | list.insertTail(4); 18 | list.print(); 19 | list.reversePrint(); 20 | 21 | list.deleteHead(); 22 | list.print(); 23 | 24 | list.deleteTail(); 25 | list.print(); 26 | 27 | list.deleteHead(); 28 | list.deleteTail(); 29 | list.print(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/stringmatch/TrieTreeTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | import org.junit.Test; 4 | 5 | public class TrieTreeTest { 6 | 7 | @Test 8 | public void testTrieTree() { 9 | TrieTree trie = new TrieTree(); 10 | trie.insert("hello"); 11 | trie.insert("her"); 12 | trie.insert("hi"); 13 | trie.insert("how"); 14 | trie.insert("so"); 15 | trie.insert("see"); 16 | trie.insert("so"); 17 | trie.insert("here"); 18 | System.out.println(trie); 19 | 20 | System.out.println(trie.contains("how")); 21 | System.out.println(trie.contains("hero")); 22 | 23 | System.out.println(trie.search("h")); 24 | System.out.println(trie.search("he")); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/linkedlist/SinglyLinkedListTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | import org.junit.Test; 4 | 5 | public class SinglyLinkedListTest { 6 | 7 | @Test 8 | public void testSinglyLinkedTest() { 9 | SinglyLinkedList list = new SinglyLinkedList(); 10 | list.insertHead(1); 11 | list.insertTail(2); 12 | ListNode node = new ListNode(4); 13 | list.insertTail(node); 14 | list.insertBefore(node, 3); 15 | list.insertAfter(node, 5); 16 | list.print(); 17 | 18 | list.delete(node); 19 | list.deleteFirst(5); 20 | list.print(); 21 | 22 | list.insertTail(2); 23 | list.print(); 24 | 25 | list.deleteAll(2); 26 | list.print(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/linkedlist/ReverseLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | public class ReverseLinkedList { 4 | public ListNode reverseList(ListNode head) { 5 | ListNode prev = null; 6 | ListNode curr = head; 7 | while (curr != null) { 8 | ListNode next = curr.next; 9 | curr.next = prev; 10 | prev = curr; 11 | curr = next; 12 | } 13 | return prev; 14 | } 15 | 16 | public ListNode reverseListRecursively(ListNode head) { 17 | if (head == null || head.next == null) { 18 | return head; 19 | } 20 | ListNode node = reverseListRecursively(head.next); 21 | head.next.next = head; 22 | head.next = null; 23 | return node; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/SelectionSort.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | public class SelectionSort { 4 | 5 | public void sort(int[] a) { 6 | if (a == null || a.length <= 1) { 7 | return; 8 | } 9 | selectionSort(a, a.length); 10 | } 11 | 12 | public void selectionSort(int[] a, int n) { 13 | if (n <= 1) { 14 | return; 15 | } 16 | 17 | for (int i = 0; i < n - 1; i++) { 18 | int minIndex = i; 19 | for (int j = i + 1; j < n; j++) { 20 | if (a[j] < a[minIndex]) { 21 | minIndex = j; 22 | } 23 | } 24 | 25 | if (minIndex != i) { 26 | int temp = a[i]; 27 | a[i] = a[minIndex]; 28 | a[minIndex] = temp; 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/array/MergeTwoSortedArray.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.array; 2 | 3 | /** 4 | * 将两个有序数组合并为一个有序数组 5 | */ 6 | public class MergeTwoSortedArray { 7 | 8 | public int[] mergeTwoSortedArray(int[] arr1, int[] arr2) { 9 | int n1 = arr1.length; 10 | int n2 = arr2.length; 11 | 12 | int n = n1 + n2; 13 | int[] arr = new int[n]; 14 | 15 | int i = 0; 16 | int j = 0; 17 | 18 | for (int k = 0; k < n; k++) { 19 | if (i >= n1) { 20 | arr[k] = arr2[j++]; 21 | } else if (j >= n2) { 22 | arr[k] = arr1[i++]; 23 | } else if (arr1[i] > arr2[j]) { 24 | arr[k] = arr2[j++]; 25 | } else { 26 | arr[k] = arr1[i++]; 27 | } 28 | } 29 | 30 | return arr; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/heap/Topk.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.heap; 2 | 3 | import java.util.PriorityQueue; 4 | 5 | public class Topk { 6 | 7 | public int[] topk(int[] data, int k) { 8 | PriorityQueue queue = new PriorityQueue<>(k); 9 | 10 | for (int i = 0; i < data.length; i++) { 11 | if (queue.size() < k) { 12 | queue.offer(data[i]); 13 | } else { 14 | int value = queue.peek(); 15 | if (value < data[i]) { 16 | queue.poll(); 17 | queue.offer(data[i]); 18 | } 19 | } 20 | } 21 | 22 | int[] result = new int[k]; 23 | int index = 0; 24 | while (!queue.isEmpty()) { 25 | result[index++] = queue.poll(); 26 | } 27 | 28 | return result; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/greedy/HuffmanTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.greedy; 2 | 3 | import org.junit.Test; 4 | 5 | public class HuffmanTest { 6 | 7 | @Test 8 | public void testHuffman() { 9 | Huffman instance = new Huffman(); 10 | 11 | String huffmanCode = instance.encode("ABRACADABRA!"); 12 | System.out.println(huffmanCode); 13 | System.out.println(instance.decode(huffmanCode)); 14 | 15 | huffmanCode = instance.encode("it was the best of times it was the worst of times."); 16 | System.out.println(huffmanCode); 17 | System.out.println(instance.decode(huffmanCode)); 18 | 19 | huffmanCode = instance.encode("beep boop beer!"); 20 | System.out.println(huffmanCode); 21 | System.out.println(instance.decode(huffmanCode)); 22 | } 23 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/stringmatch/RabinKarpTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | import org.junit.Test; 4 | 5 | public class RabinKarpTest { 6 | 7 | @Test 8 | public void testRabinKarp() { 9 | String pattern = "y similar t"; 10 | RabinKarp rk = new RabinKarp(pattern); 11 | String txt = "Technically, this algorithm is only similar to the true number in a non-decimal"; 12 | int index = rk.search(txt); 13 | System.out.println(txt); 14 | if (index == -1) { 15 | System.out.println("no match"); 16 | } else { 17 | for (int i = 0; i < index; i++) { 18 | System.out.print(" "); 19 | } 20 | System.out.println(pattern); 21 | System.out.println("match index: " + index); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/stack/StackUsage.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.stack; 2 | 3 | import java.util.Stack; 4 | 5 | public class StackUsage { 6 | public static void main(String[] args) { 7 | // 1. Initialize a stack. 8 | Stack s = new Stack<>(); 9 | // 2. Push new element. 10 | s.push(5); 11 | s.push(13); 12 | s.push(8); 13 | s.push(6); 14 | // 3. Check if stack is empty. 15 | if (s.empty()) { 16 | System.out.println("Stack is empty!"); 17 | return; 18 | } 19 | // 4. Pop an element. 20 | s.pop(); 21 | // 5. Get the top element. 22 | System.out.println("The top element is: " + s.peek()); 23 | // 6. Get the size of the stack. 24 | System.out.println("The size is: " + s.size()); 25 | } 26 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/linkedlist/RemoveNthNodeTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | import org.junit.Test; 4 | 5 | public class RemoveNthNodeTest { 6 | 7 | @Test 8 | public void testRemoveNthNode() { 9 | ListNode head = new ListNode(1); 10 | head.next = new ListNode(2); 11 | head.next.next = new ListNode(3); 12 | head.next.next.next = new ListNode(4); 13 | System.out.println(head); 14 | 15 | RemoveNthNode instance = new RemoveNthNode(); 16 | ListNode node = instance.removeNthFromEnd(head, 1); 17 | System.out.println(node); 18 | 19 | node = instance.removeNthFromEnd(node, 2); 20 | System.out.println(node); 21 | 22 | node = instance.removeNthFromEnd(node, 2); 23 | System.out.println(node); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/stack/SampleBrowserTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.stack; 2 | 3 | import org.junit.Test; 4 | 5 | public class SampleBrowserTest { 6 | 7 | @Test 8 | public void testSampleBrowser() { 9 | SampleBrowser browser = new SampleBrowser(); 10 | browser.open("http://www.baidu.com"); 11 | browser.open("http://news.baidu.com"); 12 | browser.open("http://news.baidu.com/ent"); 13 | browser.goBack(); 14 | browser.goBack(); 15 | browser.goForward(); 16 | browser.open("http://www.qq.com"); 17 | browser.goForward(); 18 | browser.goBack(); 19 | browser.goForward(); 20 | browser.goBack(); 21 | browser.goBack(); 22 | browser.goBack(); 23 | browser.goBack(); 24 | browser.checkCurrentPage(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | public class BubbleSort { 4 | 5 | public void sort(int[] a) { 6 | if (a == null || a.length <= 1) { 7 | return; 8 | } 9 | bubbleSort(a, a.length); 10 | } 11 | 12 | public void bubbleSort(int[] a, int n) { 13 | if (n <= 1) { 14 | return; 15 | } 16 | 17 | for (int i = 0; i < n; i++) { 18 | boolean flag = false; 19 | for (int j = 0; j < n - 1 - i; j++) { 20 | if (a[j] > a[j+1]) { 21 | int temp = a[j]; 22 | a[j] = a[j+1]; 23 | a[j+1] = temp; 24 | flag = true; 25 | } 26 | } 27 | if (!flag) { 28 | // no data swap, exit the loop 29 | break; 30 | } 31 | } 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/linkedlist/CycleLinkedListTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | import org.junit.Test; 4 | 5 | public class CycleLinkedListTest { 6 | 7 | @Test 8 | public void testCycleLinkedList() { 9 | ListNode head = new ListNode(0); 10 | ListNode node1 = new ListNode(1); 11 | ListNode node2 = new ListNode(2); 12 | ListNode node3 = new ListNode(3); 13 | 14 | head.next = node1; 15 | node1.next = node2; 16 | node2.next = node3; 17 | node3.next = node1; 18 | 19 | CycleLinkedList instance = new CycleLinkedList(); 20 | System.out.println("链表是否有环: " + instance.hasCycle(head)); 21 | System.out.println("链表入口节点: " + instance.getCycleEntryNode(head).val); 22 | System.out.println("链表环的长度: " + instance.getCycleLength(head)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/recursion/FibonacciTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.recursion; 2 | 3 | import org.junit.Test; 4 | 5 | public class FibonacciTest { 6 | 7 | @Test 8 | public void testFibonacci() { 9 | Fibonacci instance = new Fibonacci(); 10 | 11 | int n = 30; 12 | 13 | long time = System.currentTimeMillis(); 14 | System.out.println(instance.f1(n)); 15 | System.out.println("f1: " + (System.currentTimeMillis() - time) + "ms"); 16 | 17 | time = System.currentTimeMillis(); 18 | System.out.println(instance.f2(n)); 19 | System.out.println("f2: " + (System.currentTimeMillis() - time) + "ms"); 20 | 21 | time = System.currentTimeMillis(); 22 | System.out.println(instance.f3(n)); 23 | System.out.println("f3: " + (System.currentTimeMillis() - time) + "ms"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/recursion/FactorialTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.recursion; 2 | 3 | import org.junit.Test; 4 | 5 | public class FactorialTest { 6 | 7 | @Test 8 | public void testFactorial() { 9 | Factorial instance = new Factorial(); 10 | 11 | int n = 9; 12 | 13 | long time = System.currentTimeMillis(); 14 | System.out.println(instance.f1(n)); 15 | System.out.println("f1: " + (System.currentTimeMillis() - time) + "ms"); 16 | 17 | time = System.currentTimeMillis(); 18 | System.out.println(instance.f2(n)); 19 | System.out.println("f2: " + (System.currentTimeMillis() - time) + "ms"); 20 | 21 | time = System.currentTimeMillis(); 22 | System.out.println(instance.f3(n)); 23 | System.out.println("f3: " + (System.currentTimeMillis() - time) + "ms"); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/queue/ArrayQueue.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.queue; 2 | 3 | public class ArrayQueue { 4 | private String[] items; 5 | private int n = 0; 6 | private int head = 0; 7 | private int tail = 0; 8 | 9 | public ArrayQueue(int capacity) { 10 | items = new String[capacity]; 11 | n = capacity; 12 | } 13 | 14 | public boolean enqueue(String item) { 15 | if (tail == n) { 16 | return false; 17 | } 18 | items[tail++] = item; 19 | return true; 20 | } 21 | 22 | public String dequeue() { 23 | if (head == tail) { 24 | return null; 25 | } 26 | return items[head++]; 27 | } 28 | 29 | public void printAll() { 30 | for (int i = head; i < tail; i++) { 31 | System.out.println(items[i] + " "); 32 | } 33 | System.out.println(); 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/recursion/Permutation.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.recursion; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Permutation { 7 | public List> permute(int[] nums) { 8 | List> answer = new ArrayList<>(); 9 | List track = new ArrayList<>(); 10 | permute(nums, track, answer); 11 | return answer; 12 | } 13 | 14 | public void permute(int[] nums, List track, List> answer) { 15 | if (track.size() == nums.length) { 16 | answer.add(new ArrayList<>(track)); 17 | } else { 18 | for (int num : nums) { 19 | if (track.contains(num)) continue; 20 | track.add(num); 21 | permute(nums, track, answer); 22 | track.remove(track.size() - 1); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/InsertionSort.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | public class InsertionSort { 4 | 5 | public void sort(int[] a) { 6 | if (a == null || a.length <= 1) { 7 | return; 8 | } 9 | insertionSort(a, a.length); 10 | } 11 | 12 | /** 13 | * 插入排序核心思想: 14 | * 取未排序区间中的元素,在已排序区间中找到合适的插入位置将其插入。 15 | * 移动元素的次数等于逆序度。 16 | */ 17 | public void insertionSort(int[] a, int n) { 18 | if (n <= 1) { 19 | return; 20 | } 21 | 22 | for (int i = 1; i < n; i++) { 23 | int value = a[i]; 24 | int j = i - 1; 25 | 26 | // 查找插入的位置 27 | for (; j >= 0; j--) { 28 | if (a[j] > value) { 29 | a[j+1] = a[j]; // 移动数据 30 | } else { 31 | break; 32 | } 33 | } 34 | 35 | a[j+1] = value; // 插入数据 36 | } 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/recursion/Factorial.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.recursion; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class Factorial { 7 | public int f1(int n) { 8 | if (n <= 0) return 1; 9 | if (n == 1) return 1; 10 | return n * f1(n - 1); 11 | } 12 | 13 | private Map map = new HashMap<>(); 14 | public int f2(int n) { 15 | if (n <= 0) return 1; 16 | if (n == 1) return 1; 17 | 18 | if (map.containsKey(n)) { 19 | return map.get(n); 20 | } 21 | 22 | int result = n * f2(n - 1); 23 | map.put(n, result); 24 | return result; 25 | } 26 | 27 | public int f3(int n) { 28 | if (n <= 0) return 1; 29 | if (n == 1) return 1; 30 | 31 | int result = 1; 32 | for (int i = 2; i <= n; i++) { 33 | result *= i; 34 | } 35 | return result; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/graph/GraphTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.graph; 2 | 3 | import org.junit.Test; 4 | 5 | public class GraphTest { 6 | 7 | @Test 8 | public void testGraph() { 9 | // 0 -- 1 -- 2 10 | // | | | 11 | // 3 -- 4 -- 5 12 | // | | 13 | // 6 -- 7 14 | Graph graph = new Graph(8); 15 | graph.addEdge(0, 1); 16 | graph.addEdge(0, 3); 17 | graph.addEdge(1, 2); 18 | graph.addEdge(1, 4); 19 | graph.addEdge(2, 5); 20 | graph.addEdge(3, 4); 21 | graph.addEdge(4, 5); 22 | graph.addEdge(4, 6); 23 | graph.addEdge(5, 7); 24 | graph.addEdge(6, 7); 25 | 26 | graph.bfs(0, 6); 27 | System.out.println(); 28 | graph.dfs(0, 6); 29 | System.out.println(); 30 | System.out.println(graph.getLevelByBfs(0, 3)); 31 | System.out.println(graph.getLevelByDfs(0, 3)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/skiplist/SkipListTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.skiplist; 2 | 3 | import com.github.andavid.ds.datastructure.skiplist.SkipList.Node; 4 | import org.junit.Test; 5 | 6 | public class SkipListTest { 7 | 8 | @Test 9 | public void testSkipList() { 10 | SkipList skipList = new SkipList(); 11 | for (int i = 1; i <= 32; i++) { 12 | skipList.insert(i); 13 | } 14 | System.out.println(skipList); 15 | 16 | Node node = skipList.find(11); 17 | if (node != null) { 18 | System.out.println(node); 19 | } else { 20 | System.out.println("not found"); 21 | } 22 | 23 | skipList.delete(11); 24 | System.out.println(skipList); 25 | 26 | node = skipList.find(11); 27 | if (node != null) { 28 | System.out.println(node); 29 | } else { 30 | System.out.println("not found"); 31 | } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/FindKthLargest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | public class FindKthLargest { 4 | 5 | public int findKthLargest(int[] data, int k) { 6 | return partition(data, k, 0, data.length - 1); 7 | } 8 | 9 | public int partition(int[] data, int k, int low, int high) { 10 | int pivot = data[high]; 11 | int i = low; 12 | for (int j = low; j < high; j++) { 13 | if (data[j] > pivot) { 14 | swap(data, i, j); 15 | i++; 16 | } 17 | } 18 | swap(data, i, high); 19 | 20 | if (i + 1 == k) { 21 | return data[i]; 22 | } else if (i + 1 < k) { 23 | return partition(data, k, i + 1, high); 24 | } else { 25 | return partition(data, k, low, i - 1); 26 | } 27 | } 28 | 29 | public void swap(int[] data, int i, int j) { 30 | int temp = data[i]; 31 | data[i] = data[j]; 32 | data[j] = temp; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/queue/QueueUsage.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.queue; 2 | 3 | import java.util.Queue; 4 | import java.util.LinkedList; 5 | 6 | public class QueueUsage { 7 | public static void main(String[] args) { 8 | // 1. Initialize a queue. 9 | Queue q = new LinkedList<>(); 10 | // 2. Get the first element - return null if queue is empty. 11 | System.out.println("The first element is: " + q.peek()); 12 | // 3. Push new element. 13 | q.offer(5); 14 | q.offer(13); 15 | q.offer(8); 16 | q.offer(6); 17 | // 4. Pop an element. 18 | q.poll(); 19 | // 5. Get the first element. 20 | System.out.println("The first element is: " + q.peek()); 21 | // 7. Get the size of the queue. 22 | System.out.println("The size is: " + q.size()); 23 | // 8. Check if queue is empty. 24 | System.out.println("The queue is empty: " + q.isEmpty()); 25 | } 26 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/hash/ConsistentHashTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class ConsistentHashTest { 9 | 10 | @Test 11 | public void testConsistentHash() { 12 | List servers = new ArrayList<>(); 13 | servers.add("192.168.1.1"); 14 | servers.add("192.168.1.2"); 15 | servers.add("192.168.1.3"); 16 | 17 | ConsistentHash hash = new ConsistentHash(2, servers); 18 | hash.print(); 19 | 20 | System.out.println(); 21 | hash.add("192.168.1.4"); 22 | hash.print(); 23 | 24 | System.out.println(); 25 | hash.remove("192.168.1.2"); 26 | hash.print(); 27 | 28 | System.out.println(); 29 | for (int i = 1; i <= 10; i++) { 30 | System.out.println(i + " --> " + hash.hash(i) + " --> " + hash.get(i)); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/heap/MedianFinder.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.heap; 2 | 3 | import java.util.Collections; 4 | import java.util.PriorityQueue; 5 | 6 | public class MedianFinder { 7 | 8 | /** 大顶堆,保存前半部分数据 */ 9 | private PriorityQueue maxHeap; 10 | 11 | /** 小顶堆,保存后半部分数据 */ 12 | private PriorityQueue minHeap; 13 | 14 | 15 | public MedianFinder() { 16 | minHeap = new PriorityQueue<>(); 17 | maxHeap = new PriorityQueue<>(Collections.reverseOrder()); 18 | } 19 | 20 | public void addNum(int num) { 21 | maxHeap.offer(num); 22 | minHeap.offer(maxHeap.poll()); 23 | if (maxHeap.size() < minHeap.size()) { 24 | maxHeap.offer(minHeap.poll()); 25 | } 26 | } 27 | 28 | public double findMedian() { 29 | if (maxHeap.size() == minHeap.size()) { 30 | return (maxHeap.peek() + minHeap.peek()) * 0.5; 31 | } else { 32 | return maxHeap.peek(); 33 | } 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/stringmatch/KmpDfaTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | import org.junit.Test; 4 | 5 | public class KmpDfaTest { 6 | 7 | @Test 8 | public void testKmpDfa() { 9 | test("abacadabrabracabracadabrabrabracad", "abracadabra"); 10 | test("abacadabrabracabracadabrabrabracad", "rab"); 11 | test("abacadabrabracabracadabrabrabracad", "bcara"); 12 | } 13 | 14 | private void test(String txt, String pattern) { 15 | KmpDfa kmp = new KmpDfa(pattern); 16 | int offset = kmp.search(txt); 17 | 18 | System.out.println("text: " + txt); 19 | 20 | System.out.print("pattern: "); 21 | for (int i = 0; i < offset; i++) { 22 | System.out.print(" "); 23 | } 24 | System.out.println(pattern); 25 | 26 | if (offset != -1) { 27 | System.out.println("match position: " + offset); 28 | } else { 29 | System.out.println("no match"); 30 | } 31 | 32 | System.out.println(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/stringmatch/TrieTreeFrequencyTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | import java.util.Arrays; 4 | import org.junit.Test; 5 | 6 | public class TrieTreeFrequencyTest { 7 | 8 | @Test 9 | public void testTrieTreeFrequency() { 10 | TrieTreeFrequency trieTree = new TrieTreeFrequency(); 11 | 12 | String txt = "he her hello home so see say just so so hello world"; 13 | String[] words = txt.split(" "); 14 | System.out.println("total words: " + words.length); 15 | System.out.println(Arrays.toString(words)); 16 | 17 | for (String word : words) { 18 | trieTree.insert(word); 19 | } 20 | System.out.println("trieTree: "); 21 | System.out.println(trieTree); 22 | 23 | System.out.println("so" + " : " + trieTree.frequency("so")); 24 | System.out.println("he" + " : " + trieTree.frequency("he")); 25 | System.out.println("hello" + " : " + trieTree.frequency("hello")); 26 | System.out.println("hel" + " : " + trieTree.frequency("hel")); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/QuickSort.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | public class QuickSort { 4 | 5 | public void sort(int[] data) { 6 | quicksort(data, 0, data.length - 1); 7 | } 8 | 9 | public void quicksort(int[] data, int low, int high) { 10 | if (low >= high) return; 11 | int mid = partition(data, low, high); 12 | quicksort(data, low, mid - 1); 13 | quicksort(data, mid + 1, high); 14 | } 15 | 16 | public int partition(int[] data, int low, int high) { 17 | int pivot = data[high]; 18 | int i = low; 19 | for (int j = low; j < high; j++) { 20 | if (data[j] < pivot) { 21 | swap(data, i, j); 22 | i++; 23 | } 24 | } 25 | swap(data, i, high); 26 | return i; 27 | } 28 | 29 | public void swap(int[] data, int i, int j) { 30 | int temp = data[i]; 31 | data[i] = data[j]; 32 | data[j] = temp; 33 | } 34 | 35 | public void print(int[] data) { 36 | for (int item : data) { 37 | System.out.print("" + item + ","); 38 | } 39 | System.out.println(); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/hash/LinkedHashMapUsage.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | import java.util.HashMap; 4 | import java.util.LinkedHashMap; 5 | import java.util.Map; 6 | 7 | public class LinkedHashMapUsage { 8 | public static void main(String[] args) { 9 | HashMap m1 = new LinkedHashMap<>(); 10 | m1.put("1", "a"); 11 | m1.put("4", "d"); 12 | m1.put("2", "b"); 13 | m1.put("3", "c"); 14 | System.out.println(m1); 15 | 16 | for (Map.Entry entry : m1.entrySet()) { 17 | System.out.println(entry.getKey() + "=" + entry.getValue()); 18 | } 19 | 20 | // 10 是初始大小,0.75 是装载因子,true 是表示按照访问时间排序 21 | HashMap m2 = new LinkedHashMap<>(10, 0.75f, true); 22 | m2.put(3, 11); 23 | m2.put(1, 12); 24 | m2.put(5, 23); 25 | m2.put(2, 22); 26 | 27 | m2.put(3, 26); 28 | m2.get(5); 29 | 30 | System.out.println(m2); 31 | 32 | for (Map.Entry entry : m2.entrySet()) { 33 | System.out.println(entry.getKey() + "=" + entry.getValue()); 34 | } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/hash/MyHashMapTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | import org.junit.Test; 4 | 5 | public class MyHashMapTest { 6 | 7 | @Test 8 | public void testMyHashMap() { 9 | MyHashMap m = new MyHashMap(4); 10 | m.put("1", "a"); 11 | m.put("4", "d"); 12 | m.put("2", "b"); 13 | m.put("3", "c"); 14 | m.put("5", "e"); 15 | m.put("8", "h"); 16 | m.put("6", "f"); 17 | m.put("7", "g"); 18 | m.put("9", "i"); 19 | m.printAll(); 20 | 21 | System.out.println(); 22 | System.out.println("删除 key = 2, value = " + m.remove("2")); 23 | m.printAll(); 24 | 25 | System.out.println(); 26 | System.out.println("put(5, x)"); 27 | m.put("5", "x"); 28 | m.printAll(); 29 | 30 | System.out.println(); 31 | System.out.println("contains key 9: " + m.containsKey("9")); 32 | System.out.println("contains key 2: " + m.containsKey("2")); 33 | System.out.println("contains value x: " + m.containsValue("x")); 34 | System.out.println("contains value z: " + m.containsValue("z")); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/stack/LinkedStack.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.stack; 2 | 3 | import com.github.andavid.ds.datastructure.linkedlist.ListNode; 4 | 5 | public class LinkedStack { 6 | private ListNode head; 7 | private int count; 8 | 9 | public LinkedStack() { 10 | head = null; 11 | count = 0; 12 | } 13 | 14 | public int push(int item) { 15 | ListNode newNode = new ListNode(item); 16 | newNode.next = head; 17 | head = newNode; 18 | count++; 19 | return item; 20 | } 21 | 22 | public int pop() { 23 | if (count == 0) { 24 | throw new IllegalArgumentException("Stack empty"); 25 | } 26 | 27 | int obj = head.val; 28 | head = head.next; 29 | count--; 30 | 31 | return obj; 32 | } 33 | 34 | public int peek() { 35 | if (count == 0) { 36 | throw new IllegalArgumentException("Stack empty"); 37 | } 38 | 39 | int obj = head.val; 40 | return obj; 41 | } 42 | 43 | public boolean empty() { 44 | return size() == 0; 45 | } 46 | 47 | public int size() { 48 | return count; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/MergeSort.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | public class MergeSort { 4 | private int[] aux; 5 | 6 | public void sort(int[] data) { 7 | if (data == null || data.length <= 1) { 8 | return; 9 | } 10 | aux = new int[data.length]; 11 | mergeSort(data, 0, data.length - 1); 12 | } 13 | 14 | public void mergeSort(int[] data, int low, int high) { 15 | if (low >= high) return; 16 | int mid = low + (high - low) / 2; 17 | mergeSort(data, low, mid); 18 | mergeSort(data, mid + 1, high); 19 | merge(data, low, mid, high); 20 | } 21 | 22 | public void merge(int[] data, int low, int mid, int high) { 23 | int i = low; 24 | int j = mid + 1; 25 | 26 | System.arraycopy(data, low, aux, low, high - low + 1); 27 | 28 | for (int k = low; k <= high; k++) { 29 | if (i > mid) { 30 | data[k] = aux[j++]; 31 | } else if (j > high) { 32 | data[k] = aux[i++]; 33 | } else if (aux[i] > aux[j]) { 34 | data[k] = aux[j++]; 35 | } else { 36 | data[k] = aux[i++]; 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/backtracking/Package.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.backtracking; 2 | 3 | public class Package { 4 | /** 背包中物品总重量的最大值 */ 5 | public int maxWeight = Integer.MIN_VALUE; 6 | 7 | /** 8 | * 计算背包能装下物品总重量的最大值 9 | * 10 | * @param index 当前考察物品的索引 11 | * @param currentWeight 当前已经装进去的物品的总重量 12 | * @param items 每个物品的重量 13 | * @param n 物品个数 14 | * @param capacity 背包能够承受的重量 15 | */ 16 | public void calMaxWeight(int index, int currentWeight, int[] items, int n, int capacity) { 17 | if (index == n || currentWeight == capacity) { 18 | // index == n 表示已经考察完所有的物品 19 | // currentWeight == capacity 表示背包已经装满了 20 | if (currentWeight > maxWeight) { 21 | maxWeight = currentWeight; 22 | } 23 | return; 24 | } 25 | 26 | // 选择将当前考察物品不装入背包,直接考察下一个物品 27 | calMaxWeight(index + 1, currentWeight, items, n, capacity); 28 | 29 | // 选择将当前考察物品装入背包 30 | // 这里使用了剪枝,如果将当前考察物品装入背包后超过背包能够承受的重量,就不装了 31 | if (currentWeight + items[index] <= capacity) { 32 | calMaxWeight(index + 1, currentWeight + items[index], items, n, capacity); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/hash/HashMapUsage.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | import java.util.HashMap; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | 7 | public class HashMapUsage { 8 | public static void main(String[] args) { 9 | HashMap m = new HashMap<>(); 10 | m.put("1", "a"); 11 | m.put("4", "d"); 12 | m.put("2", "b"); 13 | m.put("3", "c"); 14 | System.out.println("打印 map: " + m); 15 | 16 | System.out.println("删除 key = 4"); 17 | m.remove("4"); 18 | System.out.println("打印 map: " + m); 19 | 20 | System.out.println("contains key 4: " + m.containsKey("4")); 21 | System.out.println("contains value b: " + m.containsValue("b")); 22 | 23 | Iterator iterator = m.entrySet().iterator(); 24 | while (iterator.hasNext()) { 25 | Map.Entry entry = (Map.Entry) iterator.next(); 26 | System.out.println("next: " + entry.getKey() + "->" + entry.getValue()); 27 | } 28 | 29 | System.out.println("add null key and value"); 30 | m.put(null, "z"); 31 | m.put("4", null); 32 | System.out.println("打印 map: " + m); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/queue/LinkedQueue.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.queue; 2 | 3 | import com.github.andavid.ds.datastructure.linkedlist.ListNode; 4 | 5 | public class LinkedQueue { 6 | ListNode head; 7 | ListNode tail; 8 | 9 | public void enqueue(int value) { 10 | ListNode newNode = new ListNode(value); 11 | if (tail == null) { 12 | head = tail = newNode; 13 | } else { 14 | tail.next = newNode; 15 | tail = newNode; 16 | } 17 | } 18 | 19 | public int dequeue() { 20 | if (head == null) { 21 | throw new IllegalArgumentException("queue empty"); 22 | } 23 | 24 | int value = head.val; 25 | head = head.next; 26 | if (head == null) { 27 | tail = null; 28 | } 29 | return value; 30 | } 31 | 32 | public String toString() { 33 | StringBuilder sb = new StringBuilder(); 34 | sb.append("["); 35 | for (ListNode p = head; p != null; p = p.next) { 36 | sb.append(p.val); 37 | if (p.next != null) { 38 | sb.append(",").append(" "); 39 | } 40 | } 41 | sb.append("]"); 42 | return sb.toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/linkedlist/MergeTwoLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | public class MergeTwoLinkedList { 4 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 5 | ListNode dummy = new ListNode(-1); 6 | ListNode p = dummy; 7 | while (l1 != null || l2 != null) { 8 | if (l1 == null) { 9 | p.next = l2; 10 | break; 11 | } 12 | if (l2 == null) { 13 | p.next = l1; 14 | break; 15 | } 16 | if (l1.val <= l2.val) { 17 | p.next = l1; 18 | l1 = l1.next; 19 | } else { 20 | p.next = l2; 21 | l2 = l2.next; 22 | } 23 | p = p.next; 24 | } 25 | 26 | return dummy.next; 27 | } 28 | 29 | public ListNode mergeTwoListsRecursively(ListNode l1, ListNode l2) { 30 | if (l1 == null) { 31 | return l2; 32 | } 33 | if (l2 == null) { 34 | return l1; 35 | } 36 | if (l1.val <= l2.val) { 37 | l1.next = mergeTwoListsRecursively(l1.next, l2); 38 | return l1; 39 | } else { 40 | l2.next = mergeTwoListsRecursively(l1, l2.next); 41 | return l2; 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/recursion/Fibonacci.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.recursion; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class Fibonacci { 7 | public int f1(int n) { 8 | if (n <= 0) return 0; 9 | if (n == 1) return 1; 10 | if (n == 2) return 1; 11 | return f1(n - 1) + f1(n - 2); 12 | } 13 | 14 | private Map map = new HashMap<>(); 15 | 16 | public int f2(int n) { 17 | if (n <= 0) return 0; 18 | if (n == 1) return 1; 19 | if (n == 2) return 1; 20 | 21 | if (map.containsKey(n)) { 22 | return map.get(n); 23 | } 24 | 25 | int result = f2(n - 1) + f2(n - 2); 26 | map.put(n, result); 27 | return result; 28 | } 29 | 30 | public int f3(int n) { 31 | if (n <= 0) return 0; 32 | if (n == 1) return 1; 33 | if (n == 2) return 1; 34 | 35 | int one_step_before = 1; 36 | int two_steps_before = 1; 37 | int result = 0; 38 | 39 | for (int i = 2; i < n; i++) { 40 | result = one_step_before + two_steps_before; 41 | two_steps_before = one_step_before; 42 | one_step_before = result; 43 | } 44 | 45 | return result; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/queue/CircularQueue.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.queue; 2 | 3 | public class CircularQueue { 4 | private String[] items; 5 | private int n = 0; 6 | private int head = 0; 7 | private int tail = 0; 8 | 9 | public CircularQueue(int capacity) { 10 | items = new String[capacity]; 11 | n = capacity; 12 | } 13 | 14 | public boolean enqueue(String item) { 15 | if ((tail + 1) % n == head) { 16 | // 队满,tail 指向的位置不存储数据,实际存储的数据个数为 n-1 17 | return false; 18 | } 19 | items[tail] = item; 20 | tail = (tail + 1) % n; 21 | return true; 22 | } 23 | 24 | public String dequeue() { 25 | if (head == tail) { 26 | // 队空 27 | return null; 28 | } 29 | String item = items[head]; 30 | head = (head + 1) % n; 31 | return item; 32 | } 33 | 34 | public String toString() { 35 | StringBuilder sb = new StringBuilder(); 36 | sb.append("["); 37 | for (int i = head; i % n != tail; i++) { 38 | sb.append(items[i]); 39 | if ((i + 1) % n != tail) { 40 | sb.append(",").append(" "); 41 | } 42 | } 43 | sb.append("]"); 44 | return sb.toString(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/stack/ArrayStack.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.stack; 2 | 3 | public class ArrayStack { 4 | private int[] data; 5 | private int count; 6 | 7 | public ArrayStack() { 8 | this(10); 9 | } 10 | 11 | public ArrayStack(int initialCapacity) { 12 | if (initialCapacity < 0) { 13 | throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); 14 | } 15 | 16 | data = new int[initialCapacity]; 17 | } 18 | 19 | public int push(int item) { 20 | if (count == data.length) { 21 | throw new IllegalArgumentException("Stack full"); 22 | } 23 | 24 | data[count++] = item; 25 | return item; 26 | } 27 | 28 | public int pop() { 29 | if (count == 0) { 30 | throw new IllegalArgumentException("Stack empty"); 31 | } 32 | 33 | int obj = data[count - 1]; 34 | count--; 35 | 36 | return obj; 37 | } 38 | 39 | public int peek() { 40 | if (count == 0) { 41 | throw new IllegalArgumentException("Stack empty"); 42 | } 43 | 44 | return data[count - 1]; 45 | } 46 | 47 | public boolean empty() { 48 | return size() == 0; 49 | } 50 | 51 | public int size() { 52 | return count; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/linkedlist/MergeTwoLinkedListTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | import org.junit.Test; 4 | 5 | public class MergeTwoLinkedListTest { 6 | 7 | @Test 8 | public void testMergeTwoLinkedList() { 9 | ListNode l1 = new ListNode(1); 10 | l1.next = new ListNode(3); 11 | l1.next.next = new ListNode(5); 12 | System.out.println(l1); 13 | 14 | ListNode l2 = new ListNode(2); 15 | l2.next = new ListNode(4); 16 | l2.next.next = new ListNode(6); 17 | System.out.println(l2); 18 | 19 | MergeTwoLinkedList instance = new MergeTwoLinkedList(); 20 | ListNode node = instance.mergeTwoLists(l1, l2); 21 | System.out.println(node); 22 | } 23 | 24 | @Test 25 | public void testMergeTwoLinkedListRecursively() { 26 | ListNode l1 = new ListNode(1); 27 | l1.next = new ListNode(3); 28 | l1.next.next = new ListNode(5); 29 | System.out.println(l1); 30 | 31 | ListNode l2 = new ListNode(2); 32 | l2.next = new ListNode(4); 33 | l2.next.next = new ListNode(6); 34 | System.out.println(l2); 35 | 36 | MergeTwoLinkedList instance = new MergeTwoLinkedList(); 37 | ListNode node = instance.mergeTwoListsRecursively(l1, l2); 38 | System.out.println(node); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/stringmatch/KmpDfa.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | public class KmpDfa { 4 | private int R; 5 | private int[][] dfa; 6 | private String pattern; 7 | 8 | public KmpDfa(String pattern) { 9 | this(pattern, 256); 10 | } 11 | 12 | public KmpDfa(String pattern, int R) { 13 | this.R = R; 14 | this.pattern = pattern; 15 | buildDfa(); 16 | } 17 | 18 | private void buildDfa() { 19 | // dfa[c][j] 表示状态 j 遇到字符 c 转移到哪个状态 20 | dfa = new int[R][pattern.length()]; 21 | // base case,起始状态 0 遇到模式串的第一个字符,将转移到状态 1 22 | dfa[pattern.charAt(0)][0] = 1; 23 | // 重启状态初始为 0 24 | int x = 0; 25 | // 当前状态从 1 开始 26 | for (int j = 1; j < pattern.length(); j++) { 27 | for (int c = 0; c < R; c++) { 28 | dfa[c][j] = dfa[c][x]; 29 | } 30 | // 状态 j 遇到模式串索引 j 的字符,将转移到状态 j+1 31 | dfa[pattern.charAt(j)][j] = j + 1; 32 | // 更新重启状态 33 | x = dfa[pattern.charAt(j)][x]; 34 | } 35 | } 36 | 37 | public int search(String txt) { 38 | int i = 0; 39 | int j = 0; 40 | 41 | while (i < txt.length() && j < pattern.length()) { 42 | j = dfa[txt.charAt(i)][j]; 43 | i++; 44 | } 45 | 46 | if (j == pattern.length()) { 47 | return i - j; 48 | } 49 | return -1; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/HeapSort.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | public class HeapSort { 4 | 5 | public void sort(int[] data) { 6 | if (data == null || data.length <= 1) { 7 | return; 8 | } 9 | heapSort(data, data.length); 10 | } 11 | 12 | public void heapSort(int[] data, int n) { 13 | if (n <= 1) { 14 | return; 15 | } 16 | 17 | buildHeap(data, n); 18 | 19 | int k = n; 20 | while (k > 1) { 21 | swap(data, 0, k - 1); 22 | --k; 23 | heapify(data, k, 0); 24 | } 25 | } 26 | 27 | private void buildHeap(int[] data, int n) { 28 | for (int i = (n - 1) / 2; i >= 0; --i) { 29 | heapify(data, n, i); 30 | } 31 | } 32 | 33 | private void heapify(int[] data, int n, int i) { 34 | while (true) { 35 | int maxPos = i; 36 | if (i * 2 + 1 < n && data[i] < data[i * 2 + 1]) { 37 | maxPos = i * 2 + 1; 38 | } 39 | if (i * 2 + 2 < n && data[maxPos] < data[i * 2 + 2]) { 40 | maxPos = i * 2 + 2; 41 | } 42 | if (maxPos == i) { 43 | break; 44 | } 45 | swap(data, i, maxPos); 46 | i = maxPos; 47 | } 48 | } 49 | 50 | private void swap(int[] data, int i, int j) { 51 | int temp = data[i]; 52 | data[i] = data[j]; 53 | data[j] = temp; 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/RadixSort.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class RadixSort { 6 | 7 | public void sort(int[] array) { 8 | if (array == null || array.length <= 1) { 9 | return; 10 | } 11 | radixSort(array, array.length); 12 | } 13 | 14 | public void radixSort(int[] array, int n) { 15 | if (n <= 1) { 16 | return; 17 | } 18 | 19 | int max = array[0]; 20 | for (int i = 0; i < n; i++) { 21 | if (array[i] > max) { 22 | max = array[i]; 23 | } 24 | } 25 | 26 | ArrayList> bucketList = new ArrayList<>(); 27 | for (int i = 0; i < 10; i++) { 28 | bucketList.add(new ArrayList<>()); 29 | } 30 | 31 | int d = 1; 32 | while (true) { 33 | if (max < d) { 34 | break; 35 | } 36 | 37 | for (int i = 0; i < n; i++) { 38 | int number = (array[i] / d) % 10; 39 | bucketList.get(number).add(array[i]); 40 | } 41 | 42 | int index = 0; 43 | for (int i = 0; i < 10; i++) { 44 | int size = bucketList.get(i).size(); 45 | for (int j = 0; j < size; j++) { 46 | array[index++] = bucketList.get(i).get(j); 47 | } 48 | bucketList.get(i).clear(); 49 | } 50 | 51 | d *= 10; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/heap/PriorityQueueUsage.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.heap; 2 | 3 | import java.util.Comparator; 4 | import java.util.PriorityQueue; 5 | import java.util.Queue; 6 | 7 | public class PriorityQueueUsage { 8 | 9 | public static void main(String[] args) { 10 | Queue queue1 = new PriorityQueue(); 11 | queue1.add(2); 12 | queue1.add(1); 13 | queue1.add(3); 14 | 15 | while (!queue1.isEmpty()) { 16 | System.out.println(queue1.poll()); 17 | } 18 | 19 | Comparator comparator = new Comparator() { 20 | @Override 21 | public int compare(Student o1, Student o2) { 22 | return o1.id - o2.id; 23 | } 24 | }; 25 | 26 | Queue queue2 = new PriorityQueue(comparator); 27 | queue2.add(new Student(2, "B")); 28 | queue2.add(new Student(1, "A")); 29 | queue2.add(new Student(3, "C")); 30 | 31 | while (!queue2.isEmpty()) { 32 | System.out.println(queue2.poll().toString()); 33 | } 34 | } 35 | 36 | public static class Student { 37 | private int id; 38 | private String name; 39 | 40 | public Student(int id, String name) { 41 | this.id = id; 42 | this.name = name; 43 | } 44 | 45 | public String toString() { 46 | return id + "-" + name; 47 | } 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/array/DynamicArrayTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.array; 2 | 3 | import org.junit.Test; 4 | 5 | public class DynamicArrayTest { 6 | 7 | @Test 8 | public void testDynamicArray() { 9 | DynamicArray array = new DynamicArray<>(2); 10 | 11 | array.add(1); // 1 12 | array.addFirst(2); // 2, 1 13 | System.out.println(array); 14 | System.out.println("capacity = " + array.getCapacity()); 15 | 16 | array.addLast(3); // 2, 1, 3 17 | array.addElement(1, 4); // 2, 4, 1, 3 18 | System.out.println(array); 19 | System.out.println("capacity = " + array.getCapacity()); 20 | 21 | array.add(5); // 2, 4, 1, 3, 5 22 | array.add(6); // 2, 4, 1, 3, 5, 6 23 | System.out.println(array); 24 | System.out.println("capacity = " + array.getCapacity()); 25 | System.out.println("size = " + array.getSize()); 26 | 27 | array.remove(); // 2, 4, 1, 3, 5 28 | array.removeFirst(); // 4, 1, 3, 5 29 | array.removeLast(); // 4, 1, 3 30 | array.removeElement(1); // 4, 3 31 | System.out.println(array); 32 | System.out.println("capacity = " + array.getCapacity()); 33 | System.out.println("size = " + array.getSize()); 34 | 35 | array.set(1, 6); // 4, 6 36 | System.out.println(array); 37 | System.out.println("array[1] = " + array.get(1)); // 6 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/CountingSort.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | public class CountingSort { 4 | 5 | public void sort(int[] a) { 6 | if (a == null || a.length <= 1) { 7 | return; 8 | } 9 | countingSort(a, a.length); 10 | } 11 | 12 | public void countingSort(int[] a, int n) { 13 | if (n <= 1) { 14 | return; 15 | } 16 | 17 | // 找到数组最大值 18 | int max = a[0]; 19 | for (int i = 1; i < n; ++i) { 20 | if (a[i] > max) { 21 | max = a[i]; 22 | } 23 | } 24 | 25 | // 申请一个计数数组 c,下标 [0, max] 26 | int[] c = new int[max + 1]; 27 | for (int i = 0; i <= max; ++i) { 28 | c[i] = 0; 29 | } 30 | 31 | // 遍历数组,计算每个元素的个数 32 | for (int i = 0; i < n; ++i) { 33 | c[a[i]]++; 34 | } 35 | 36 | // 累加数组,c[i] 表示值小于等于 i 的元素数量 37 | for (int i = 1; i <= max; ++i) { 38 | c[i] = c[i - 1] + c[i]; 39 | } 40 | 41 | // 申请一个临时数组 r,保存排序之后的结果 42 | int[] r = new int[n]; 43 | for (int i = n - 1; i >= 0; --i) { 44 | // 从后往前扫描数组 a,取出元素 a[i] 45 | // 值小于等于 a[i] 的元素数量为 c[a[i]] 46 | // 直接把 a[i] 放到排序后的数组索引为 c[a[i]] - 1 的位置 47 | int index = c[a[i]] - 1; 48 | r[index] = a[i]; 49 | c[a[i]]--; // 元素 a[i] 已经放到指定位置,计数数组相应值减一 50 | } 51 | 52 | // 将排序之后的结果拷贝回源数组 53 | for (int i = 0; i < n; ++i) { 54 | a[i] = r[i]; 55 | } 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/stringmatch/BruteForce.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | /** 4 | * 字符串朴素匹配算法 5 | */ 6 | public class BruteForce { 7 | 8 | public int match(String txt, String pattern) { 9 | if (txt == null || pattern == null || txt.length() < pattern.length()) { 10 | return -1; 11 | } 12 | 13 | int i = 0; 14 | int j = 0; 15 | while (i < txt.length() && j < pattern.length()) { 16 | if (txt.charAt(i) == pattern.charAt(j)) { 17 | // 当前字符匹配成功,主串和模式串都往后移动一位 18 | i++; 19 | j++; 20 | } else { 21 | // 当前字符匹配失败,主串回溯到匹配开始位置(i-j)的后面一位(i-j+1),模式串从头开始匹配 22 | i = i - j + 1; 23 | j = 0; 24 | } 25 | } 26 | 27 | if (j == pattern.length()) { 28 | return i - j; 29 | } 30 | return -1; 31 | } 32 | 33 | public int find(String txt, String pattern) { 34 | if (txt == null || pattern == null || txt.length() < pattern.length()) { 35 | return -1; 36 | } 37 | 38 | // 遍历主串 39 | for (int i = 0; i + pattern.length() <= txt.length(); i++) { 40 | // 遍历模式串 41 | if (match(txt, pattern, i)) { 42 | return i; 43 | } 44 | } 45 | 46 | return -1; 47 | } 48 | 49 | private boolean match(String txt, String pattern, int start) { 50 | for (int i = 0; i < pattern.length(); i++) { 51 | if (pattern.charAt(i) != txt.charAt(i + start)) { 52 | return false; 53 | } 54 | } 55 | return true; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/sort/BucketSort.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | 6 | public class BucketSort { 7 | 8 | public void sort(int[] array) { 9 | if (array == null || array.length <= 1) { 10 | return; 11 | } 12 | bucketSort(array, array.length); 13 | } 14 | 15 | public void bucketSort(int[] array, int n) { 16 | if (n <= 1) { 17 | return; 18 | } 19 | 20 | int max = array[0]; 21 | int min = array[0]; 22 | 23 | for (int i = 1; i < n; i++) { 24 | if (array[i] > max) { 25 | max = array[i]; 26 | } else if (array[i] < min) { 27 | min = array[i]; 28 | } 29 | } 30 | 31 | ArrayList> bucketList = new ArrayList<>(); 32 | for (int i = 0; i < n; i++) { 33 | bucketList.add(new ArrayList<>()); 34 | } 35 | 36 | int diff = max - min; 37 | float section = (float) diff / (float) (n - 1); 38 | 39 | for (int i = 0; i < n; i++) { 40 | int num = (int) (array[i] / section) - 1; 41 | if (num < 0) { 42 | num = 0; 43 | } 44 | bucketList.get(num).add(array[i]); 45 | } 46 | 47 | for (int i = 0; i < bucketList.size(); i++) { 48 | Collections.sort(bucketList.get(i)); 49 | } 50 | 51 | int index = 0; 52 | for (ArrayList bucket : bucketList) { 53 | for (int value : bucket) { 54 | array[index] = value; 55 | index++; 56 | } 57 | } 58 | 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/heap/MergeSortedArray.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.heap; 2 | 3 | import java.util.Comparator; 4 | import java.util.PriorityQueue; 5 | import java.util.Queue; 6 | 7 | public class MergeSortedArray { 8 | 9 | public int[] mergeSortedArray(int[][] array) { 10 | if (array == null) { 11 | return new int[0]; 12 | } 13 | 14 | Comparator comparator = new Comparator() { 15 | @Override 16 | public int compare(Element o1, Element o2) { 17 | return o1.value - o2.value; 18 | } 19 | }; 20 | 21 | Queue queue = new PriorityQueue(array.length, comparator); 22 | 23 | int len = 0; 24 | for (int i = 0; i < array.length; i++) { 25 | if (array[i].length > 0) { 26 | queue.offer(new Element(i, 0, array[i][0])); 27 | len += array[i].length; 28 | } 29 | } 30 | 31 | int[] result = new int[len]; 32 | int index = 0; 33 | while (!queue.isEmpty()) { 34 | Element element = queue.poll(); 35 | result[index++] = element.value; 36 | if (element.col + 1 < array[element.row].length) { 37 | queue.add(new Element(element.row, element.col + 1, array[element.row][element.col + 1])); 38 | } 39 | } 40 | 41 | return result; 42 | } 43 | 44 | public class Element { 45 | public int row, col, value; 46 | public Element(int row, int col, int value) { 47 | this.row = row; 48 | this.col = col; 49 | this.value = value; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/divideandconquer/CountInversePairs.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.divideandconquer; 2 | 3 | public class CountInversePairs { 4 | private int num = 0; 5 | 6 | /** 7 | * 输入一个数组,求出这个数组中的逆序对总数。 8 | * 采用分治算法,利用二路归并排序实现。 9 | */ 10 | public int count(int[] data) { 11 | if (data == null || data.length < 2) { 12 | return 0; 13 | } 14 | 15 | num = 0; 16 | mergeSort(data, 0, data.length - 1); 17 | return num; 18 | } 19 | 20 | public void mergeSort(int[] data, int low, int high) { 21 | if (low >= high) return; 22 | int mid = low + (high - low) / 2; 23 | mergeSort(data, low, mid); 24 | mergeSort(data, mid + 1, high); 25 | merge(data, low, mid, high); 26 | } 27 | 28 | public void merge(int[] data, int low, int mid, int high) { 29 | int[] temp = new int[high - low + 1]; 30 | int left = low; 31 | int right = mid + 1; 32 | int index = 0; 33 | 34 | while (left <= mid && right <= high) { 35 | if (data[left] > data[right]) { 36 | // 合并两个有序数组过程中,right 存在逆序对数量为 left 到 mid 的元素数量 37 | num += mid - left + 1; 38 | temp[index++] = data[right++]; 39 | } else { 40 | temp[index++] = data[left++]; 41 | } 42 | } 43 | 44 | while (left <= mid) { 45 | temp[index++] = data[left++]; 46 | } 47 | 48 | while (right <= high) { 49 | temp[index++] = data[right++]; 50 | } 51 | 52 | for (int i = low; i <= high; i++) { 53 | data[i] = temp[i - low]; 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/graph/TopoGraph.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.graph; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | /** 7 | * 拓扑排序 8 | */ 9 | public class TopoGraph { 10 | 11 | private int v; 12 | private LinkedList[] adj; 13 | 14 | public TopoGraph(int v) { 15 | this.v = v; 16 | adj = new LinkedList[v]; 17 | for (int i = 0; i < v; i++) { 18 | adj[i] = new LinkedList<>(); 19 | } 20 | } 21 | 22 | public void addEdge(int s, int t) { 23 | adj[s].add(t); 24 | } 25 | 26 | /** 27 | * Kahn 算法。 从有向图中找到一个入度为 0 的顶点,将其输出到拓扑排序的结果序列,然后将这个顶点从图中删除。 28 | * 重复以上过程,直到所有的顶点都被输出。 29 | * 如果最后输出的顶点个数,少于图中顶点个数,图中还有入度不为 0 的顶点,说明图中有环。 30 | */ 31 | public void kahn() { 32 | int[] inDegree = new int[v]; 33 | for (int i = 0; i < v; i++) { 34 | for (int j = 0; j < adj[i].size(); j++) { 35 | inDegree[adj[i].get(j)]++; 36 | } 37 | } 38 | 39 | Queue queue = new LinkedList<>(); 40 | for (int i = 0; i < v; i++) { 41 | if (inDegree[i] == 0) { 42 | queue.offer(i); 43 | } 44 | } 45 | 46 | while (!queue.isEmpty()) { 47 | int i = queue.poll(); 48 | System.out.println(i + " "); 49 | for (int j = 0; j < adj[i].size(); j++) { 50 | int k = adj[i].get(j); 51 | inDegree[k]--; 52 | if (inDegree[k] == 0) { 53 | queue.offer(k); 54 | } 55 | } 56 | } 57 | 58 | for (int i = 0; i < v; i++) { 59 | if (inDegree[i] != 0) { 60 | System.out.println("exist circle"); 61 | break; 62 | } 63 | } 64 | } 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/linkedlist/CycleLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | public class CycleLinkedList { 4 | 5 | public boolean hasCycle(ListNode head) { 6 | ListNode slow = head; 7 | ListNode fast = head; 8 | 9 | while (fast != null && fast.next != null) { 10 | slow = slow.next; 11 | fast = fast.next.next; 12 | if (slow == fast) { 13 | return true; 14 | } 15 | } 16 | 17 | return false; 18 | } 19 | 20 | /** 21 | * 返回第一个进入环的节点。 22 | * 从头节点和快慢指针碰撞节点出发,相遇的节点就是入口节点。 23 | */ 24 | public ListNode getCycleEntryNode(ListNode head) { 25 | ListNode slow = head; 26 | ListNode fast = head; 27 | 28 | while (fast != null && fast.next != null) { 29 | slow = slow.next; 30 | fast = fast.next.next; 31 | if (slow == fast) { 32 | slow = head; 33 | while (slow != fast) { 34 | slow = slow.next; 35 | fast = fast.next; 36 | } 37 | return slow; 38 | } 39 | } 40 | 41 | return null; 42 | } 43 | 44 | /** 45 | * 求链表环的长度。 46 | * 快慢指针从相遇节点开始,再次相遇时,慢指针走过的距离就是环的长度。 47 | */ 48 | public int getCycleLength(ListNode head) { 49 | ListNode slow = head; 50 | ListNode fast = head; 51 | int len = 0; 52 | 53 | while (fast != null && fast.next != null) { 54 | slow = slow.next; 55 | fast = fast.next.next; 56 | if (slow == fast) { 57 | do { 58 | len++; 59 | slow = slow.next; 60 | fast = fast.next.next; 61 | } while (slow != fast); 62 | return len; 63 | } 64 | } 65 | 66 | return 0; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/stringmatch/Kmp.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | public class Kmp { 4 | private String pattern; 5 | private int[] next; 6 | 7 | public Kmp(String pattern) { 8 | this.pattern = pattern; 9 | generateNext(); 10 | } 11 | 12 | private void generateNext() { 13 | int len = pattern.length(); 14 | next = new int[len]; 15 | next[0] = -1; 16 | 17 | int k = -1; 18 | int j = 0; 19 | while (j < len - 1) { 20 | // next[j] = k 表示索引 j 之前的字符串有最大长度为 k 的相同前缀和后缀 21 | if (k == -1 || (pattern.charAt(k) == pattern.charAt(j))) { 22 | // 如果 p[k] = p[j],next[j+1] = next[j] + 1 = k + 1 23 | k++; 24 | j++; 25 | // next 数组的优化 26 | if (pattern.charAt(k) != pattern.charAt(j)) { 27 | next[j] = k; 28 | } else { 29 | // 如果失配时,下一跳的位置和当前位置的字符一样,肯定还是不匹配,所以需要继续往前跳 30 | next[j] = next[k]; 31 | } 32 | } else { 33 | // 继续查找次长的相同前缀和后缀 34 | k = next[k]; 35 | } 36 | } 37 | } 38 | 39 | public int match(String src) { 40 | if (src == null || pattern == null || src.length() < pattern.length()) { 41 | return -1; 42 | } 43 | 44 | int i = 0; 45 | int j = 0; 46 | while (i < src.length() && j < pattern.length()) { 47 | if (j == -1 || src.charAt(i) == pattern.charAt(j)) { 48 | // 当前字符匹配成功,主串和模式串都往后移动一位 49 | // 或者 j == -1 时,主串后移一位,模式串从头(j = 0)开始匹配 50 | i++; 51 | j++; 52 | } else { 53 | // 当前字符匹配失败,主串位置不变,模式串相对于主串向右移动 j - next[j] 位 54 | j = next[j]; 55 | } 56 | } 57 | 58 | if (j == pattern.length()) { 59 | return i - j; 60 | } 61 | return -1; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/tree/ArrayBinaryTree.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.tree; 2 | 3 | public class ArrayBinaryTree { 4 | 5 | /** 6 | * 完全二叉树,数组顺序存储。 7 | * 为了方便获取左右孩子节点以及父亲节点,从下标 1 开始存储数据。 8 | * 数组下标为 i 的节点,左孩子节点下标为 i * 2 9 | * 右孩子节点下标为 i * 2 + 1 10 | * 父亲节点下标为 i / 2 11 | */ 12 | private int[] array; 13 | 14 | /** 二叉树存储的最大数据个数 */ 15 | private int n; 16 | 17 | /** 二叉树已经存储的数据个数 */ 18 | private int count; 19 | 20 | public ArrayBinaryTree(int capacity) { 21 | array = new int[capacity + 1]; 22 | n = capacity; 23 | count = 0; 24 | } 25 | 26 | public void insert(int data) { 27 | if (count >= n) { 28 | return; 29 | } 30 | 31 | count++; 32 | array[count] = data; 33 | } 34 | 35 | public void preOrder(int index) { 36 | if (index > count) { 37 | return; 38 | } 39 | 40 | System.out.print(array[index]); 41 | if (index == count) { 42 | System.out.println(); 43 | } else { 44 | System.out.print("->"); 45 | } 46 | 47 | preOrder(index * 2); 48 | preOrder(index * 2 + 1); 49 | } 50 | 51 | public void inOrder(int index) { 52 | if (index > count) { 53 | return; 54 | } 55 | 56 | inOrder(index * 2); 57 | 58 | System.out.print(array[index]); 59 | if (index == count) { 60 | System.out.println(); 61 | } else { 62 | System.out.print("->"); 63 | } 64 | 65 | inOrder(index * 2 + 1); 66 | } 67 | 68 | public void postOrder(int index) { 69 | if (index > count) { 70 | return; 71 | } 72 | 73 | postOrder(index * 2); 74 | postOrder(index * 2 + 1); 75 | 76 | System.out.print(array[index]); 77 | if (index == 1) { 78 | System.out.println(); 79 | } else { 80 | System.out.print("->"); 81 | } 82 | } 83 | 84 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/backtracking/EightQueen.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.backtracking; 2 | 3 | public class EightQueen { 4 | private static final int QUEEN_SIZE = 8; 5 | 6 | /** 记录每一行的 Queen 存储在哪一列 */ 7 | private int[] result = new int[QUEEN_SIZE]; 8 | 9 | /** 记录可以摆放的数量 */ 10 | private int count = 0; 11 | 12 | public void cal8queens(int row) { 13 | if (row == QUEEN_SIZE) { 14 | count++; 15 | System.out.println(count + ":"); 16 | printQueens(result); 17 | return; 18 | } 19 | // 遍历每一行 Queen 可以放的列 20 | for (int column = 0; column < QUEEN_SIZE; column++) { 21 | if (isOk(row, column)) { 22 | result[row] = column; 23 | cal8queens(row + 1); 24 | } 25 | } 26 | } 27 | 28 | private boolean isOk(int row, int column) { 29 | int leftup = column - 1; 30 | int rightup = column + 1; 31 | // 遍历前面的 row - 1 行 32 | for (int i = row - 1; i >= 0; i--) { 33 | // 第 i 行的 column 列有 Queen 34 | if (result[i] == column) { 35 | return false; 36 | } 37 | // 左上对角线,第 i 行的 leftup 列有 Queen 38 | if (leftup >= 0 && result[i] == leftup) { 39 | return false; 40 | } 41 | // 右上对角线,第 i 行的 rightup 列有 Queen 42 | if (rightup < QUEEN_SIZE && result[i] == rightup) { 43 | return false; 44 | } 45 | leftup--; 46 | rightup++; 47 | } 48 | return true; 49 | } 50 | 51 | private void printQueens(int[] result) { 52 | for (int row = 0; row < QUEEN_SIZE; row++) { 53 | for (int column = 0; column < QUEEN_SIZE; column++) { 54 | if (result[row] == column) { 55 | System.out.print("Q "); 56 | } else { 57 | System.out.print("* "); 58 | } 59 | } 60 | System.out.println(); 61 | } 62 | System.out.println(); 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/sort/SortTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.sort; 2 | 3 | import java.util.Arrays; 4 | 5 | import org.junit.Test; 6 | 7 | public class SortTest { 8 | 9 | @Test 10 | public void testSort() { 11 | int len = 32768; 12 | int[] a = new int[len]; 13 | final int HASH_INCREMENT = 0x61c88647; 14 | int next = 0; 15 | 16 | // 生成均匀分布且不包含重复数字的数组 17 | for (int i = 0; i < len; i++) { 18 | a[i] = next & (len - 1); 19 | next += HASH_INCREMENT; 20 | } 21 | 22 | int[] a1 = Arrays.copyOf(a, len); 23 | InsertionSort insertionSort = new InsertionSort(); 24 | long time = System.currentTimeMillis(); 25 | insertionSort.sort(a1); 26 | System.out.println("insertion sort " + (System.currentTimeMillis() - time) + "ms"); 27 | 28 | int[] a2 = Arrays.copyOf(a, len); 29 | BubbleSort bubbleSort = new BubbleSort(); 30 | time = System.currentTimeMillis(); 31 | bubbleSort.sort(a2); 32 | System.out.println("bubble sort " + (System.currentTimeMillis() - time) + "ms"); 33 | 34 | int[] a3 = Arrays.copyOf(a, len); 35 | SelectionSort selectionSort = new SelectionSort(); 36 | time = System.currentTimeMillis(); 37 | selectionSort.sort(a3); 38 | System.out.println("selection sort " + (System.currentTimeMillis() - time) + "ms"); 39 | 40 | int[] a4 = Arrays.copyOf(a, len); 41 | QuickSort quickSort = new QuickSort(); 42 | time = System.currentTimeMillis(); 43 | quickSort.sort(a4); 44 | System.out.println("quick sort " + (System.currentTimeMillis() - time) + "ms"); 45 | 46 | int[] a5 = Arrays.copyOf(a, len); 47 | MergeSort mergeSort = new MergeSort(); 48 | time = System.currentTimeMillis(); 49 | mergeSort.sort(a5); 50 | System.out.println("merge sort " + (System.currentTimeMillis() - time) + "ms"); 51 | 52 | } 53 | } -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/algorithm/search/BinarySearchTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.search; 2 | 3 | import org.junit.Test; 4 | 5 | public class BinarySearchTest { 6 | 7 | private BinarySearch search = new BinarySearch(); 8 | 9 | @Test 10 | public void testBinarySearch() { 11 | int[] data = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 12 | for (int i = 0; i < data.length; i++) { 13 | int index = search.bsearch(data, data[i]); 14 | System.out.println("查找元素 " + data[i] + " 的索引为: " + index); 15 | } 16 | } 17 | 18 | @Test 19 | public void testBinarySearchRecursion() { 20 | int[] data = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 21 | for (int i = 0; i < data.length; i++) { 22 | int index = search.bsearchRecursion(data, data[i]); 23 | System.out.println("查找元素 " + data[i] + " 的索引为: " + index); 24 | } 25 | } 26 | 27 | @Test 28 | public void testBinarySearchFirst() { 29 | int[] data = new int[] {0, 1, 2, 3, 4, 4, 4, 5, 6, 7, 8, 9, 10}; 30 | int value = 4; 31 | int index = search.bsearchFirst(data, value); 32 | System.out.println("查找第一个值等于 " + value + " 的索引为 " + index); 33 | } 34 | 35 | @Test 36 | public void testBinarySearchLast() { 37 | int[] data = new int[] {0, 1, 2, 3, 4, 4, 4, 5, 6, 7, 8, 9, 10}; 38 | int value = 4; 39 | int index = search.bsearchLast(data, value); 40 | System.out.println("查找最后一个值等于 " + value + " 的索引为 " + index); 41 | } 42 | 43 | @Test 44 | public void testBinarySearchFirstGreater() { 45 | int[] data = new int[] {3, 4, 6, 7, 10}; 46 | int value = 5; 47 | int index = search.bsearchFirstGreater(data, value); 48 | System.out.println("查找第一个值大于等于 " + value + " 的索引为 " + index); 49 | } 50 | 51 | @Test 52 | public void testBinarySearchLastLess() { 53 | int[] data = new int[] {3, 5, 6, 8, 9, 10}; 54 | int value = 7; 55 | int index = search.bsearchLastLess(data, value); 56 | System.out.println("查找最后一个值小于等于 " + value + " 的索引为 " + index); 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/linkedlist/CircularLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | public class CircularLinkedList { 4 | ListNode head = null; 5 | ListNode tail = null; 6 | 7 | public void insertHead(int value) { 8 | ListNode newNode = new ListNode(value); 9 | insertHead(newNode); 10 | } 11 | 12 | public void insertHead(ListNode newNode) { 13 | if (head == null) { 14 | newNode.next = newNode; 15 | head = tail = newNode; 16 | } else { 17 | newNode.next = head; 18 | tail.next = newNode; 19 | head = newNode; 20 | } 21 | } 22 | 23 | public void insertTail(int value) { 24 | ListNode newNode = new ListNode(value); 25 | insertTail(newNode); 26 | } 27 | 28 | public void insertTail(ListNode newNode) { 29 | if (head == null) { 30 | newNode.next = newNode; 31 | head = tail = newNode; 32 | } else { 33 | newNode.next = head; 34 | tail.next = newNode; 35 | tail = newNode; 36 | } 37 | } 38 | 39 | public void deleteHead() { 40 | if (head == null) { 41 | return; 42 | } 43 | 44 | if (head == tail) { 45 | head = tail = null; 46 | return; 47 | } 48 | 49 | head = head.next; 50 | tail.next = head; 51 | } 52 | 53 | public void deleteTail() { 54 | if (tail == null) { 55 | return; 56 | } 57 | 58 | if (head == tail) { 59 | head = tail = null; 60 | return; 61 | } 62 | 63 | ListNode p = head; 64 | while (p.next != tail) { 65 | p = p.next; 66 | } 67 | p.next = head; 68 | tail = p; 69 | } 70 | 71 | public void print() { 72 | StringBuilder sb = new StringBuilder(); 73 | sb.append("["); 74 | for (ListNode p = head; p != null; p = p.next) { 75 | sb.append(p.val); 76 | if (p.next != head) { 77 | sb.append(",").append(" "); 78 | } else { 79 | break; 80 | } 81 | } 82 | sb.append("]"); 83 | System.out.println(sb.toString()); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/array/SortedArray.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.array; 2 | 3 | /** 4 | * 实现一个大小固定的有序数组 5 | */ 6 | public class SortedArray { 7 | 8 | /** 9 | * 默认容量 10 | */ 11 | public static final int DEFAULT_CAPACITY = 20; 12 | 13 | int capacity; 14 | int size; 15 | int[] data; 16 | 17 | public SortedArray() { 18 | this(DEFAULT_CAPACITY); 19 | } 20 | 21 | public SortedArray(int initialCapacity) { 22 | capacity = initialCapacity; 23 | data = new int[capacity]; 24 | } 25 | 26 | /** 27 | * 添加元素 28 | */ 29 | public void add(int element) { 30 | if (size == capacity) { 31 | throw new IllegalArgumentException("add fail. array is full."); 32 | } 33 | 34 | int i = size - 1; 35 | for (; i >= 0; i--) { 36 | if (element < data[i]) { 37 | data[i + 1] = data[i]; 38 | } else { 39 | break; 40 | } 41 | } 42 | data[i + 1] = element; 43 | size++; 44 | } 45 | 46 | /** 47 | * 删除指定索引的元素 48 | */ 49 | public int remove(int index) { 50 | if (index < 0 || index > size - 1) { 51 | throw new IllegalArgumentException("remove fail. index out of range."); 52 | } 53 | 54 | int element = data[index]; 55 | for (int i = index; i < size - 1; i++) { 56 | data[i] = data[i + 1]; 57 | } 58 | data[size - 1] = 0; 59 | size--; 60 | 61 | return element; 62 | } 63 | 64 | public int get(int index) { 65 | if (index < 0 || index > size - 1) { 66 | throw new IllegalArgumentException("get fail. index out of range."); 67 | } 68 | return data[index]; 69 | } 70 | 71 | public boolean isEmpty() { 72 | return size == 0; 73 | } 74 | 75 | public int getSize() { 76 | return size; 77 | } 78 | 79 | public String toString() { 80 | if (isEmpty()) { 81 | return "[]"; 82 | } 83 | 84 | StringBuilder sb = new StringBuilder(); 85 | sb.append("["); 86 | for (int i = 0; i < size; i++) { 87 | sb.append(get(i)); 88 | if (i == size - 1) { 89 | sb.append("]"); 90 | } else { 91 | sb.append(',').append(' '); 92 | } 93 | } 94 | 95 | return sb.toString(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/stringmatch/TrieTreeFrequency.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | public class TrieTreeFrequency { 9 | 10 | public class TrieNode { 11 | public char data; 12 | public int frequency; 13 | public boolean isEndingChar = false; 14 | Map children = new HashMap<>(); 15 | public TrieNode(char data) { 16 | this.data = data; 17 | } 18 | } 19 | 20 | private TrieNode root = new TrieNode('/'); 21 | 22 | public void insert(String word) { 23 | TrieNode p = root; 24 | 25 | for (Character ch : word.toCharArray()) { 26 | if (!p.children.containsKey(ch)) { 27 | p.children.put(ch, new TrieNode(ch)); 28 | } 29 | p = p.children.get(ch); 30 | p.frequency++; 31 | } 32 | 33 | p.isEndingChar = true; 34 | } 35 | 36 | public int frequency(TrieNode p) { 37 | if (p.children.size() == 0) { 38 | return p.frequency; 39 | } else { 40 | int childrenFrequency = 0; 41 | for (TrieNode child : p.children.values()) { 42 | childrenFrequency += frequency(child); 43 | } 44 | return p.frequency - childrenFrequency; 45 | } 46 | } 47 | 48 | public int frequency(String word) { 49 | TrieNode p = root; 50 | for (Character ch : word.toCharArray()) { 51 | if (!p.children.containsKey(ch)) { 52 | return 0; 53 | } 54 | p = p.children.get(ch); 55 | } 56 | 57 | if (p.isEndingChar) { 58 | return frequency(p); 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | private void traverse(List list, TrieNode trieNode, String prefix) { 65 | if (trieNode == null) { 66 | return; 67 | } 68 | 69 | if (trieNode.isEndingChar) { 70 | list.add(prefix); 71 | } 72 | 73 | for (TrieNode child : trieNode.children.values()) { 74 | if (child != null) { 75 | traverse(list, child, prefix + child.data); 76 | } 77 | } 78 | } 79 | 80 | @Override 81 | public String toString() { 82 | List list = new ArrayList<>(); 83 | traverse(list, root, ""); 84 | return list.toString(); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/stringmatch/TrieTree.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class TrieTree { 7 | 8 | public class TrieNode { 9 | public char data; 10 | public TrieNode[] children = new TrieNode[26]; 11 | public boolean isEndingChar = false; 12 | public TrieNode(char data) { 13 | this.data = data; 14 | } 15 | } 16 | 17 | private TrieNode root = new TrieNode('/'); 18 | 19 | /** 20 | * 将关键词插入到 Trie 树 21 | */ 22 | public void insert(String word) { 23 | TrieNode p = root; 24 | 25 | for (char ch : word.toCharArray()) { 26 | int index = ch - 'a'; 27 | if (p.children[index] == null) { 28 | p.children[index] = new TrieNode(ch); 29 | } 30 | p = p.children[index]; 31 | } 32 | 33 | p.isEndingChar = true; 34 | } 35 | 36 | /** 37 | * 在 Trie 树中查询一个关键词 38 | */ 39 | public boolean contains(String word) { 40 | TrieNode p = root; 41 | 42 | for (char ch : word.toCharArray()) { 43 | int index = ch - 'a'; 44 | if (p.children[index] == null) { 45 | return false; 46 | } 47 | p = p.children[index]; 48 | } 49 | 50 | return p.isEndingChar; 51 | } 52 | 53 | /** 54 | * 在 Trie 树中查询所有 prefix 前缀的关键词 55 | */ 56 | public List search(String prefix) { 57 | List list = new ArrayList<>(); 58 | TrieNode p = root; 59 | 60 | for (char ch : prefix.toCharArray()) { 61 | int index = ch - 'a'; 62 | if (p.children[index] == null) { 63 | return list; 64 | } 65 | p = p.children[index]; 66 | } 67 | 68 | traverse(list, p, prefix); 69 | 70 | return list; 71 | } 72 | 73 | private void traverse(List list, TrieNode trieNode, String prefix) { 74 | if (trieNode == null) { 75 | return; 76 | } 77 | 78 | if (trieNode.isEndingChar) { 79 | list.add(prefix); 80 | } 81 | 82 | for (TrieNode child : trieNode.children) { 83 | if (child != null) { 84 | traverse(list, child, prefix + child.data); 85 | } 86 | } 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | List list = new ArrayList<>(); 92 | traverse(list, root, ""); 93 | return list.toString(); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/tree/BinarySearchTreeTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.tree; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | 7 | public class BinarySearchTreeTest { 8 | 9 | @Test 10 | public void testBinarySearchTree() { 11 | TreeNode root = new TreeNode(3); 12 | TreeNode node2 = new TreeNode(2); 13 | TreeNode node3 = new TreeNode(5); 14 | TreeNode node4 = new TreeNode(4); 15 | TreeNode node5 = new TreeNode(6); 16 | root.left = node2; 17 | root.right = node3; 18 | node3.left = node4; 19 | node3.right = node5; 20 | 21 | BinaryTree tree = new BinaryTree(); 22 | System.out.println(tree.levelOrder(root)); 23 | 24 | BinarySearchTree bst = new BinarySearchTree(root); 25 | System.out.println("insert 1"); 26 | bst.insert(1); 27 | System.out.println(tree.levelOrder(root)); 28 | 29 | TreeNode node = bst.find(5); 30 | if (node != null) { 31 | System.out.println("find node " + node.val); 32 | } 33 | 34 | System.out.println("delete 5"); 35 | bst.delete(5); 36 | System.out.println(tree.levelOrder(root)); 37 | 38 | System.out.println("max node " + bst.maximum().val); 39 | System.out.println("min node " + bst.minimum().val); 40 | 41 | int data = 4; 42 | System.out.println("Predecessor node of " + data + " is: "); 43 | if (bst.predecessor(data) != null) { 44 | System.out.println(bst.predecessor(data).val); 45 | } else { 46 | System.out.println("null"); 47 | } 48 | 49 | System.out.println("Successor node of " + data + " is: "); 50 | if (bst.successor(data) != null) { 51 | System.out.println(bst.successor(data).val); 52 | } else { 53 | System.out.println("null"); 54 | } 55 | } 56 | 57 | @Test 58 | public void testSerialize() { 59 | TreeNode root = new TreeNode(5); 60 | TreeNode node2 = new TreeNode(3); 61 | TreeNode node3 = new TreeNode(6); 62 | TreeNode node4 = new TreeNode(2); 63 | TreeNode node5 = new TreeNode(7); 64 | root.left = node2; 65 | root.right = node3; 66 | node2.left = node4; 67 | node3.right = node5; 68 | 69 | BinarySearchTree bst = new BinarySearchTree(root); 70 | System.out.println(bst.serialize(root)); 71 | 72 | String list = "5,3,2,6,7,"; 73 | assertEquals(bst.serialize(bst.deserialize(list)), list); 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/linkedlist/DoublyLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | public class DoublyLinkedList { 4 | 5 | class Node { 6 | public int val; 7 | public Node prev; 8 | public Node next; 9 | 10 | public Node(int val) { 11 | this.val = val; 12 | } 13 | } 14 | 15 | Node head = null; 16 | Node tail = null; 17 | 18 | public void insertHead(int value) { 19 | Node newNode = new Node(value); 20 | insertHead(newNode); 21 | } 22 | 23 | public void insertHead(Node newNode) { 24 | if (head == null) { 25 | head = tail = newNode; 26 | } else { 27 | newNode.next = head; 28 | head.prev = newNode; 29 | head = newNode; 30 | } 31 | } 32 | 33 | public void insertTail(int value) { 34 | Node newNode = new Node(value); 35 | insertTail(newNode); 36 | } 37 | 38 | public void insertTail(Node newNode) { 39 | if (head == null) { 40 | head = tail = newNode; 41 | } else { 42 | newNode.prev = tail; 43 | tail.next = newNode; 44 | tail = newNode; 45 | } 46 | } 47 | 48 | public void deleteHead() { 49 | if (head == null) { 50 | return; 51 | } 52 | 53 | if (head == tail) { 54 | head = tail = null; 55 | return; 56 | } 57 | 58 | head = head.next; 59 | } 60 | 61 | public void deleteTail() { 62 | if (head == null) { 63 | return; 64 | } 65 | 66 | if (head == tail) { 67 | head = tail = null; 68 | return; 69 | } 70 | 71 | tail = tail.prev; 72 | } 73 | 74 | public void print() { 75 | StringBuilder sb = new StringBuilder(); 76 | sb.append("["); 77 | for (Node p = head; p != null; p = p.next) { 78 | sb.append(p.val); 79 | if (p != tail) { 80 | sb.append(",").append(" "); 81 | } else { 82 | break; 83 | } 84 | } 85 | sb.append("]"); 86 | System.out.println(sb.toString()); 87 | } 88 | 89 | public void reversePrint() { 90 | StringBuilder sb = new StringBuilder(); 91 | sb.append("["); 92 | for (Node p = tail; p != null; p = p.prev) { 93 | sb.append(p.val); 94 | if (p != head) { 95 | sb.append(",").append(" "); 96 | } else { 97 | break; 98 | } 99 | } 100 | sb.append("]"); 101 | System.out.println(sb.toString()); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/heap/Heap.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.heap; 2 | 3 | public class Heap { 4 | 5 | /** 6 | * 为了方便获取左右孩子节点以及父亲节点,从下标 1 开始存储数据。 7 | * 数组下标为 i 的节点,左孩子节点下标为 i * 2,右孩子节点下标为 i * 2 + 1,父亲节点下标为 i / 2 8 | */ 9 | private int[] array; 10 | 11 | /** 堆存储的最大数据个数 */ 12 | private int n; 13 | 14 | /** 堆中已经存储的数据个数 */ 15 | private int count; 16 | 17 | public Heap(int capacity) { 18 | array = new int[capacity + 1]; 19 | n = capacity; 20 | count = 0; 21 | } 22 | 23 | /** 24 | * 往大顶堆中插入一个元素。 25 | * 把新插入的元素放到堆的最后,然后采用从下往上的堆化方法进行堆化 26 | */ 27 | public void insert(int data) { 28 | if (count >= n) { 29 | return; 30 | } 31 | 32 | count++; 33 | array[count] = data; 34 | 35 | int i = count; 36 | while (i / 2 > 0 && array[i] > array[i / 2]) { 37 | swap(array, i, i / 2); 38 | i = i / 2; 39 | } 40 | } 41 | 42 | /** 43 | * 删除大顶堆的堆顶元素。 44 | * 把最后一个节点放到堆顶,然后采用从上往下的堆化方法进行堆化 45 | */ 46 | public void removeMax() { 47 | if (count == 0) { 48 | return; 49 | } 50 | 51 | array[1] = array[count]; 52 | count--; 53 | 54 | heapify(array, count, 1); 55 | } 56 | 57 | /** 58 | * 大顶堆,从上往下堆化 59 | */ 60 | private void heapify(int[] array, int n, int i) { 61 | while (true) { 62 | int maxPos = i; 63 | if (i * 2 <= n && array[i] < array[i * 2]) { 64 | maxPos = i * 2; 65 | } 66 | if (i * 2 + 1 <= n && array[maxPos] < array[i * 2 + 1]) { 67 | maxPos = i * 2 + 1; 68 | } 69 | if (maxPos == i) { 70 | break; 71 | } 72 | swap(array, i, maxPos); 73 | i = maxPos; 74 | } 75 | } 76 | 77 | /** 78 | * 建大顶堆。 79 | * 由于叶子节点不需要堆化,所以从第一个非叶子节点(下标为 n / 2)开始,从后往前处理数组元素。 80 | * 从后往前处理的原因是保证排序是稳定的。 81 | * 建堆的时间复杂度是 O(n),因为每个节点堆化的过程中,需要比较和交换的节点个数和节点的高度成正比。 82 | * 将每个非叶子节点的高度求和就可以得到建堆的时间复杂度。 83 | */ 84 | private void buildHeap(int[] array, int n) { 85 | for (int i = n / 2; i >= 1; --i) { 86 | heapify(array, n, i); 87 | } 88 | } 89 | 90 | /** 91 | * 排序。 92 | * 先构建大顶堆,每次从堆顶取出一个元素放到末尾,重新构建堆,直到堆中只剩下一个元素。 93 | */ 94 | public void sort(int[] array, int n) { 95 | buildHeap(array, n); 96 | int k = n; 97 | while (k > 1) { 98 | swap(array, 1, k); 99 | --k; 100 | heapify(array, k, 1); 101 | } 102 | } 103 | 104 | private void swap(int[] array, int i, int j) { 105 | int temp = array[i]; 106 | array[i] = array[j]; 107 | array[j] = temp; 108 | } 109 | 110 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/stack/SampleBrowser.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.stack; 2 | 3 | public class SampleBrowser { 4 | private LinkedListStack backStack; 5 | private LinkedListStack forwardStack; 6 | private String currentUrl; 7 | 8 | public SampleBrowser() { 9 | backStack = new LinkedListStack(); 10 | forwardStack = new LinkedListStack(); 11 | } 12 | 13 | public void open(String url) { 14 | if (currentUrl != null) { 15 | backStack.push(currentUrl); 16 | forwardStack.clear(); 17 | } 18 | loadUrl(url, "open"); 19 | } 20 | 21 | public boolean canGoBack() { 22 | return !backStack.empty(); 23 | } 24 | 25 | public void goBack() { 26 | if (canGoBack()) { 27 | forwardStack.push(currentUrl); 28 | String url = backStack.pop(); 29 | loadUrl(url, "back"); 30 | } else { 31 | System.out.println("can't go back."); 32 | } 33 | } 34 | 35 | public boolean canGoForward() { 36 | return !forwardStack.empty(); 37 | } 38 | 39 | public void goForward() { 40 | if (canGoForward()) { 41 | backStack.push(currentUrl); 42 | String url = forwardStack.pop(); 43 | loadUrl(url, "forward"); 44 | } else { 45 | System.out.println("can't go forward"); 46 | } 47 | } 48 | 49 | public void loadUrl(String url, String prefix) { 50 | currentUrl = url; 51 | System.out.println(prefix + " url: " + url); 52 | } 53 | 54 | public void checkCurrentPage() { 55 | System.out.println("current url: " + currentUrl); 56 | } 57 | 58 | public static class LinkedListStack { 59 | private Node head; 60 | private int count = 0; 61 | 62 | public LinkedListStack() { 63 | head = null; 64 | count = 0; 65 | } 66 | 67 | public void push(String data) { 68 | head = new Node(data, head); 69 | count++; 70 | } 71 | 72 | public String pop() { 73 | if (head == null) { 74 | throw new IllegalArgumentException("Stack empty"); 75 | } 76 | 77 | String data = head.data; 78 | head = head.next; 79 | count--; 80 | return data; 81 | } 82 | 83 | public void clear() { 84 | head = null; 85 | count = 0; 86 | } 87 | 88 | public int size() { 89 | return count; 90 | } 91 | 92 | public boolean empty() { 93 | return size() == 0; 94 | } 95 | 96 | } 97 | 98 | public static class Node { 99 | private String data; 100 | private Node next; 101 | 102 | public Node(String data) { 103 | this(data, null); 104 | } 105 | 106 | public Node(String data, Node next) { 107 | this.data = data; 108 | this.next = next; 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/stringmatch/RabinKarp.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | /** 4 | * RK 字符串匹配算法 5 | * 6 | * https://novoland.github.io/%E7%AE%97%E6%B3%95/2014/07/26/Hash%20&%20Rabin-Karp%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%9F%A5%E6%89%BE%E7%AE%97%E6%B3%95.html 7 | */ 8 | public class RabinKarp { 9 | 10 | /** 一个很大的素数 */ 11 | private static long M = 1000000000000000003L; 12 | //M = BigInteger.valueOf((long) Math.pow(10, 18)).nextProbablePrime().longValue(); 13 | 14 | /** 进制 */ 15 | private static int R = 31; 16 | 17 | /** 模式字符串 */ 18 | private String pattern; 19 | 20 | /** 模式字符串的长度 */ 21 | private int K; 22 | 23 | /** 模式字符串的 hash 值 */ 24 | private long patternHash; 25 | 26 | /** R^K % M */ 27 | private long RK; 28 | 29 | public RabinKarp(String pattern) { 30 | this.pattern = pattern; 31 | if (pattern != null) { 32 | K = pattern.length(); 33 | } 34 | 35 | patternHash = hash(pattern); 36 | System.out.println("patternHash = " + patternHash); 37 | 38 | RK = 1; 39 | for (int i = 0; i < K; i++) { 40 | RK = (RK * R) % M; 41 | } 42 | } 43 | 44 | public int search(String txt) { 45 | if (txt == null || txt.length() < K) { 46 | return -1; 47 | } 48 | 49 | long txtHash = hash(txt, 0, K); 50 | System.out.println("0.txtHash = " + txtHash); 51 | 52 | // 匹配第一个子串 53 | if ((txtHash == patternHash) && match(txt, 0)) { 54 | return 0; 55 | } 56 | 57 | for (int i = 1; i + K <= txt.length(); i++) { 58 | // 根据前一个子串的哈希值计算下一个子串的哈希值 59 | // 假设原来的字符串为 s,H(i) 表示从第 i 个字符开始的 K 个子字符串的哈希值 60 | // H(i) = s[i] * R^(K-1) + s[i+1] * R^(K-2) + ... + s[i+k-1] * R^0 61 | // H(i+1) = s[i+1] * R^(K-1) + s[i] * R^(K-2) + ... + s[i+k] * R^0 62 | // H(i+1) = (H(i) - s[i] * R^(K-1)) * R + S[i+K] 63 | // 即 i+1 处子串的 hash 可以由 i 处子串的 hash 直接计算而得,为了防止溢出在中间结果 % M 64 | // H(i+1) % M = [H(i) % M * R + s[i+k] - s[i] * R^k % M + M] % M 65 | txtHash = (txtHash * R + txt.charAt(i + K - 1) - txt.charAt(i - 1) * RK % M + M ) % M; 66 | System.out.println(i + ".txtHash = " + txtHash); 67 | if ((txtHash == patternHash) && match(txt, i)) { 68 | return i; 69 | } 70 | } 71 | 72 | return -1; 73 | } 74 | 75 | private boolean match(String txt, int start) { 76 | for (int i = 0; i < K; i++) { 77 | if (pattern.charAt(i) != txt.charAt(i + start)) { 78 | return false; 79 | } 80 | } 81 | return true; 82 | } 83 | 84 | private long hash(String str) { 85 | return hash(str, 0, str.length()); 86 | } 87 | 88 | private long hash(String str, int start, int end) { 89 | long hash = 0; 90 | for (int i = start; i < end; i++) { 91 | hash = (hash * R + str.charAt(i)) % M; 92 | } 93 | return hash; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | com.github.andavid.ds 8 | ds-algo-java 9 | 1.0-SNAPSHOT 10 | 11 | ds-algo-java 12 | 13 | http://www.example.com 14 | 15 | 16 | UTF-8 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | junit 24 | junit 25 | 4.11 26 | test 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | maven-clean-plugin 36 | 3.1.0 37 | 38 | 39 | 40 | maven-resources-plugin 41 | 3.0.2 42 | 43 | 44 | maven-compiler-plugin 45 | 3.8.0 46 | 47 | 48 | maven-surefire-plugin 49 | 2.22.1 50 | 51 | 52 | maven-jar-plugin 53 | 3.0.2 54 | 55 | 56 | maven-install-plugin 57 | 2.5.2 58 | 59 | 60 | maven-deploy-plugin 61 | 2.8.2 62 | 63 | 64 | 65 | maven-site-plugin 66 | 3.7.1 67 | 68 | 69 | maven-project-info-reports-plugin 70 | 3.0.0 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/hash/ConsistentHash.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | import java.util.Collection; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.SortedMap; 7 | import java.util.TreeMap; 8 | 9 | /** 10 | * 带虚拟结点的一致性哈希算法 11 | */ 12 | public class ConsistentHash { 13 | /** 14 | * 虚拟结点个数 15 | */ 16 | private int virtualNodeNumber; 17 | 18 | private final static int DEFAULT_VIRTUAL_NODE_NUMBER = 32; 19 | 20 | /** 21 | * 存储虚拟结点的哈希值到真实结点的映射 22 | */ 23 | private SortedMap circle; 24 | 25 | /** 26 | * 真实结点列表 27 | */ 28 | private List realNodes; 29 | 30 | public ConsistentHash(Collection nodes) { 31 | this(DEFAULT_VIRTUAL_NODE_NUMBER, nodes); 32 | } 33 | 34 | public ConsistentHash(int virtualNodeNumber, Collection nodes) { 35 | this.virtualNodeNumber = virtualNodeNumber; 36 | 37 | circle = new TreeMap<>(); 38 | realNodes = new LinkedList<>(); 39 | 40 | for (T node : nodes) { 41 | add(node); 42 | } 43 | } 44 | 45 | public void add(T node) { 46 | realNodes.add(node); 47 | for (int i = 0; i < virtualNodeNumber; i++) { 48 | String virtualNode = node.toString() + "#" + i; 49 | circle.put(hash(virtualNode), node); 50 | } 51 | } 52 | 53 | public void remove(T node) { 54 | realNodes.remove(node); 55 | for (int i = 0; i < virtualNodeNumber; i++) { 56 | String virtualNode = node.toString() + "#" + i; 57 | circle.remove(hash(virtualNode)); 58 | } 59 | } 60 | 61 | public T get(Object key) { 62 | if (circle.isEmpty()) { 63 | return null; 64 | } 65 | 66 | int hash = hash(key); 67 | if (!circle.containsKey(hash)) { 68 | // 在 int 范围内找到第一个大于该哈希值的 int 值,如果没有,则返回 TreeMap 的第一个 key 值。 69 | SortedMap tailMap = circle.tailMap(hash); 70 | if (tailMap.isEmpty()) { 71 | hash = circle.firstKey(); 72 | } else { 73 | hash = tailMap.firstKey(); 74 | } 75 | } 76 | 77 | return circle.get(hash); 78 | } 79 | 80 | public void print() { 81 | int count = 0; 82 | for (T node : realNodes) { 83 | for (int i = 0; i < virtualNodeNumber; i++) { 84 | String virtualNode = node.toString() + "#" + i; 85 | System.out.println(++count + ": " + virtualNode + " --> " + hash(virtualNode)); 86 | } 87 | } 88 | } 89 | 90 | public int hash(Object obj) { 91 | // String 的 hashCode 方法会产生负数,并且分布不均匀,因此需要找个算法重新计算 Hash 值 92 | // 这里使用 FNV1_32_HASH 算法计算 Hash 值 93 | String str = obj.toString(); 94 | final int p = 16777619; 95 | int hash = (int) 2166136261L; 96 | for (int i = 0; i < str.length(); i++) hash = (hash ^ str.charAt(i)) * p; 97 | hash += hash << 13; 98 | hash ^= hash >> 7; 99 | hash += hash << 3; 100 | hash ^= hash >> 17; 101 | hash += hash << 5; 102 | 103 | // 如果算出来的值为负数则取其绝对值 104 | if (hash < 0) hash = Math.abs(hash); 105 | return hash; 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/greedy/Huffman.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.greedy; 2 | 3 | import java.util.PriorityQueue; 4 | import java.util.Queue; 5 | 6 | public class Huffman { 7 | 8 | private static final int R = 256; 9 | 10 | private Node root; 11 | 12 | private class Node implements Comparable { 13 | private char ch; 14 | private int freq; 15 | private Node left; 16 | private Node right; 17 | 18 | Node(char ch, int freq, Node left, Node right) { 19 | this.ch = ch; 20 | this.freq = freq; 21 | this.left = left; 22 | this.right = right; 23 | } 24 | 25 | public boolean isLeaf() { 26 | return (left == null) && (right == null); 27 | } 28 | 29 | public int compareTo(Node that) { 30 | return this.freq - that.freq; 31 | } 32 | } 33 | 34 | public String encode(String src) { 35 | char[] input = src.toCharArray(); 36 | 37 | // 统计每个字符出现的次数 38 | int[] freq = new int[R]; 39 | for (int i = 0; i < input.length; i++) { 40 | freq[input[i]]++; 41 | } 42 | 43 | // 根据每个字符出现的次数构建哈夫曼树 44 | root = buildTrie(freq); 45 | 46 | // 根据哈夫曼树构建哈夫曼编码表 47 | String[] st = new String[R]; 48 | buildCode(st, root, ""); 49 | 50 | // 打印哈夫曼编码表 51 | printCode(st); 52 | 53 | // 使用哈夫曼编码表对字符串进行编码 54 | StringBuilder sb = new StringBuilder(); 55 | for (int i = 0; i < input.length; i++) { 56 | sb.append(st[input[i]]); 57 | } 58 | 59 | return sb.toString(); 60 | } 61 | 62 | public String decode(String code) { 63 | StringBuilder sb = new StringBuilder(); 64 | 65 | for (int i = 0; i < code.length(); ) { 66 | Node x = root; 67 | 68 | while (!x.isLeaf()) { 69 | if (code.charAt(i) == '0') { 70 | x = x.left; 71 | } else { 72 | x = x.right; 73 | } 74 | i++; 75 | } 76 | 77 | sb.append(x.ch); 78 | } 79 | 80 | return sb.toString(); 81 | } 82 | 83 | private Node buildTrie(int[] freq) { 84 | Queue pq = new PriorityQueue(); 85 | 86 | for (char i = 0; i < R; i++) { 87 | if (freq[i] > 0) { 88 | pq.offer(new Node(i, freq[i], null, null)); 89 | } 90 | } 91 | 92 | if (pq.size() == 1) { 93 | if (freq['\0'] == 0) { 94 | pq.offer(new Node('\0', 0, null, null)); 95 | } else { 96 | pq.offer(new Node('\1', 0, null, null)); 97 | } 98 | } 99 | 100 | while (pq.size() > 1) { 101 | Node left = pq.poll(); 102 | Node right = pq.poll(); 103 | Node parent = new Node('\0', left.freq + right.freq, left, right); 104 | pq.offer(parent); 105 | } 106 | 107 | return pq.poll(); 108 | } 109 | 110 | private void buildCode(String[] st, Node x, String s) { 111 | if (!x.isLeaf()) { 112 | buildCode(st, x.left, s + "0"); 113 | buildCode(st, x.right, s + "1"); 114 | } else { 115 | st[x.ch] = s; 116 | } 117 | } 118 | 119 | private void printCode(String[] st) { 120 | for (char i = 0; i < R; i++) { 121 | if (st[i] != null && st[i].length() > 0) { 122 | System.out.println(i + " --> " + st[i]); 123 | } 124 | } 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/search/BinarySearch.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.search; 2 | 3 | public class BinarySearch { 4 | 5 | public int bsearch(int[] data, int value) { 6 | int low = 0; 7 | int high = data.length - 1; 8 | 9 | while (low <= high) { 10 | int mid = low + ((high - low) >> 1); 11 | if (data[mid] == value) { 12 | return mid; 13 | } else if (data[mid] < value) { 14 | low = mid + 1; 15 | } else { 16 | high = mid - 1; 17 | } 18 | } 19 | 20 | return -1; 21 | } 22 | 23 | public int bsearchRecursion(int[] data, int value) { 24 | return bsearchRecursionHelper(data, 0, data.length - 1, value); 25 | } 26 | 27 | public int bsearchRecursionHelper(int[] data, int low, int high, int value) { 28 | if (low > high) return -1; 29 | 30 | int mid = low + ((high - low) >> 1); 31 | if (data[mid] == value) { 32 | return mid; 33 | } else if (data[mid] < value) { 34 | return bsearchRecursionHelper(data, mid + 1, high, value); 35 | } else { 36 | return bsearchRecursionHelper(data, low, mid - 1, value); 37 | } 38 | } 39 | 40 | public int bsearchFirst(int[] data, int value) { 41 | int low = 0; 42 | int high = data.length - 1; 43 | 44 | while (low <= high) { 45 | int mid = low + ((high - low) >> 1); 46 | if (data[mid] < value) { 47 | low = mid + 1; 48 | } else if (data[mid] > value) { 49 | high = mid - 1; 50 | } else { 51 | if (mid == 0 || data[mid -1] != value) { 52 | return mid; 53 | } else { 54 | high = mid - 1; 55 | } 56 | } 57 | } 58 | 59 | return -1; 60 | } 61 | 62 | public int bsearchLast(int[] data, int value) { 63 | int low = 0; 64 | int high = data.length - 1; 65 | 66 | while (low <= high) { 67 | int mid = low + ((high - low) >> 1); 68 | if (data[mid] < value) { 69 | low = mid + 1; 70 | } else if (data[mid] > value) { 71 | high = mid - 1; 72 | } else { 73 | if (mid == data.length - 1 || data[mid + 1] != value) { 74 | return mid; 75 | } else { 76 | low = mid + 1; 77 | } 78 | } 79 | } 80 | 81 | return -1; 82 | } 83 | 84 | public int bsearchFirstGreater(int[] data, int value) { 85 | int low = 0; 86 | int high = data.length - 1; 87 | 88 | while (low <= high) { 89 | int mid = low + ((high - low) >> 1); 90 | if (data[mid] >= value) { 91 | if (mid == 0 || data[mid - 1] < value) { 92 | return mid; 93 | } else { 94 | high = mid - 1; 95 | } 96 | } else { 97 | low = mid + 1; 98 | } 99 | } 100 | 101 | return -1; 102 | } 103 | 104 | public int bsearchLastLess(int[] data, int value) { 105 | int low = 0; 106 | int high = data.length - 1; 107 | 108 | while (low <= high) { 109 | int mid = low + ((high - low) >> 1); 110 | if (data[mid] <= value) { 111 | if (mid == data.length - 1 || data[mid + 1] > value) { 112 | return mid; 113 | } else { 114 | low = mid + 1; 115 | } 116 | } else { 117 | high = mid - 1; 118 | } 119 | } 120 | 121 | return -1; 122 | } 123 | 124 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/linkedlist/SinglyLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.linkedlist; 2 | 3 | public class SinglyLinkedList { 4 | ListNode head = null; 5 | 6 | public void insertHead(int value) { 7 | ListNode newNode = new ListNode(value); 8 | insertHead(newNode); 9 | } 10 | 11 | public void insertHead(ListNode newNode) { 12 | if (head == null) { 13 | head = newNode; 14 | } else { 15 | newNode.next = head; 16 | head = newNode; 17 | } 18 | } 19 | 20 | public void insertTail(int value) { 21 | ListNode newNode = new ListNode(value); 22 | insertTail(newNode); 23 | } 24 | 25 | public void insertTail(ListNode newNode) { 26 | if (head == null) { 27 | head = newNode; 28 | } else { 29 | ListNode p = head; 30 | while (p.next != null) { 31 | p = p.next; 32 | } 33 | p.next = newNode; 34 | } 35 | } 36 | 37 | public void insertAfter(ListNode p, int value) { 38 | ListNode newNode = new ListNode(value); 39 | insertAfter(p, newNode); 40 | } 41 | 42 | public void insertAfter(ListNode p, ListNode newNode) { 43 | if (p == null) { 44 | return; 45 | } 46 | newNode.next = p.next; 47 | p.next = newNode; 48 | } 49 | 50 | public void insertBefore(ListNode p, int value) { 51 | ListNode newNode = new ListNode(value); 52 | insertBefore(p, newNode); 53 | } 54 | 55 | public void insertBefore(ListNode p, ListNode newNode) { 56 | if (p == null) { 57 | return; 58 | } 59 | if (p == head) { 60 | insertHead(newNode); 61 | } 62 | ListNode q = head; 63 | while (q != null && q.next != p) { 64 | q = q.next; 65 | } 66 | if (q == null) { 67 | return; 68 | } 69 | newNode.next = p; 70 | q.next = newNode; 71 | } 72 | 73 | public void delete(ListNode p) { 74 | if (p == null || head == null) { 75 | return; 76 | } 77 | 78 | if (p == head) { 79 | head = head.next; 80 | return; 81 | } 82 | 83 | ListNode q = head; 84 | while (q != null && q.next != p) { 85 | q = q.next; 86 | } 87 | 88 | if (q == null) { 89 | return; 90 | } 91 | 92 | q.next = q.next.next; 93 | } 94 | 95 | public void deleteFirst(int value) { 96 | if (head == null) { 97 | return; 98 | } 99 | 100 | if (value == head.val) { 101 | head = head.next; 102 | return; 103 | } 104 | 105 | ListNode p = head; 106 | while (p.next != null && p.next.val != value) { 107 | p = p.next; 108 | } 109 | 110 | if (p.next == null) { 111 | return; 112 | } 113 | 114 | p.next = p.next.next; 115 | } 116 | 117 | public void deleteAll(int value) { 118 | ListNode dummy = new ListNode(-1); 119 | dummy.next = head; 120 | ListNode p = dummy; 121 | while (p.next != null) { 122 | if (p.next.val == value) { 123 | p.next = p.next.next; 124 | continue; 125 | } 126 | p = p.next; 127 | } 128 | head = dummy.next; 129 | } 130 | 131 | public void print() { 132 | StringBuilder sb = new StringBuilder(); 133 | sb.append("["); 134 | for (ListNode p = head; p != null; p = p.next) { 135 | sb.append(p.val); 136 | if (p.next != null) { 137 | sb.append(",").append(" "); 138 | } 139 | } 140 | sb.append("]"); 141 | System.out.println(sb.toString()); 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/algorithm/stringmatch/AhoCorasick.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.algorithm.stringmatch; 2 | 3 | import java.util.HashMap; 4 | import java.util.LinkedList; 5 | import java.util.Map; 6 | import java.util.Queue; 7 | 8 | /** 9 | * AC 自动机 10 | */ 11 | public class AhoCorasick { 12 | 13 | public class AcNode { 14 | private String data; 15 | private Map children; 16 | private boolean isEndingChar; 17 | private int length; 18 | private AcNode fail; 19 | 20 | public AcNode(String data) { 21 | this.data = data; 22 | this.children = new HashMap<>(); 23 | this.isEndingChar = false; 24 | this.length = 0; 25 | this.fail = null; 26 | } 27 | } 28 | 29 | private AcNode root; 30 | 31 | public AhoCorasick() { 32 | this.root = new AcNode("/"); 33 | } 34 | 35 | public AhoCorasick(String[] patterns) { 36 | this(); 37 | 38 | for (String pattern : patterns) { 39 | insert(pattern); 40 | } 41 | 42 | buildFailurePointer(); 43 | } 44 | 45 | /** 46 | * 往 AC 自动机插入一个模式字符串 47 | */ 48 | public void insert(String pattern) { 49 | AcNode p = root; 50 | 51 | for (int i = 0; i < pattern.length(); i++) { 52 | String c = pattern.charAt(i) + ""; 53 | if (!p.children.containsKey(c)) { 54 | p.children.put(c, new AcNode(c)); 55 | } 56 | p = p.children.get(c); 57 | } 58 | 59 | p.isEndingChar = true; 60 | p.length = pattern.length(); 61 | } 62 | 63 | /** 64 | * 构建失败指针 65 | */ 66 | private void buildFailurePointer() { 67 | Queue queue = new LinkedList<>(); 68 | queue.offer(root); 69 | 70 | while (!queue.isEmpty()) { 71 | AcNode p = queue.poll(); 72 | 73 | for (AcNode pChild : p.children.values()) { 74 | if (pChild == null) { 75 | continue; 76 | } 77 | 78 | if (p == root) { 79 | pChild.fail = root; 80 | } else { 81 | // 节点 p 的失败指针指向节点 q 82 | AcNode q = p.fail; 83 | while (q != null) { 84 | AcNode qChild = q.children.get(pChild.data); 85 | if (qChild != null) { 86 | // 如果找到节点 q 的一个子节点 qChild,跟节点 p 的子节点 pChild 字符相同, 87 | // 则将节点 pChild 的失败指针指向节点 qChild 88 | pChild.fail = qChild; 89 | break; 90 | } 91 | // 如果节点 q 中没有子节点的字符等于节点 pChild 包含的字符,继续查找下一个失败指针 92 | q = q.fail; 93 | } 94 | 95 | if (q == null) { 96 | pChild.fail = root; 97 | } 98 | } 99 | 100 | queue.offer(pChild); 101 | } 102 | } 103 | } 104 | 105 | public boolean match(String txt) { 106 | AcNode p = root; 107 | 108 | for (int i = 0; i < txt.length(); i++) { 109 | String c = txt.charAt(i) + ""; 110 | 111 | // 如果 p 指向的所有节点都没能匹配当前字符,则跳到 p 的失败指针 112 | while (p != root && p.children.get(c) == null) { 113 | p = p.fail; 114 | } 115 | p = p.children.get(c); 116 | 117 | if (p == null) { 118 | // 如果没有匹配的,从 root 重新开始匹配 119 | p = root; 120 | } 121 | 122 | AcNode temp = p; 123 | // 检查是否有失败指针为结尾字符 124 | while (temp != root) { 125 | if (temp.isEndingChar) { 126 | System.out.println("匹配起始下标: " + (i - temp.length + 1) + "; 长度: " + temp.length); 127 | return true; 128 | } 129 | temp = temp.fail; 130 | } 131 | } 132 | 133 | return false; 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/test/java/com/github/andavid/ds/datastructure/tree/BinaryTreeTest.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.tree; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | 7 | public class BinaryTreeTest { 8 | 9 | @Test 10 | public void testBinaryTree() { 11 | TreeNode root = new TreeNode(1); 12 | TreeNode node2 = new TreeNode(2); 13 | TreeNode node3 = new TreeNode(3); 14 | TreeNode node4 = new TreeNode(4); 15 | TreeNode node5 = new TreeNode(5); 16 | TreeNode node6 = new TreeNode(6); 17 | TreeNode node7 = new TreeNode(7); 18 | root.left = node2; 19 | root.right = node3; 20 | node2.left = node4; 21 | node2.right = node5; 22 | node3.left = node6; 23 | node3.right = node7; 24 | 25 | BinaryTree tree = new BinaryTree(); 26 | 27 | // 前序遍历 28 | System.out.println("preorder:"); 29 | tree.preorder(root); 30 | System.out.println(); 31 | 32 | System.out.println("preorderTraversal1:"); 33 | System.out.println(tree.preorderTraversal1(root).toString()); 34 | 35 | System.out.println("preorderTraversal2:"); 36 | System.out.println(tree.preorderTraversal2(root).toString()); 37 | 38 | // 中序遍历 39 | System.out.println("inorder:"); 40 | tree.inorder(root); 41 | System.out.println(); 42 | 43 | System.out.println("inorderTraversal1:"); 44 | System.out.println(tree.inorderTraversal(root).toString()); 45 | 46 | // 后序遍历 47 | System.out.println("postorder:"); 48 | tree.postorder(root); 49 | System.out.println(); 50 | 51 | System.out.println("postorderTraversal1:"); 52 | System.out.println(tree.postorderTraversal1(root).toString()); 53 | 54 | System.out.println("postorderTraversal2:"); 55 | System.out.println(tree.postorderTraversal2(root).toString()); 56 | 57 | // 按层遍历 58 | System.out.println("level order:"); 59 | System.out.println(tree.levelOrder(root)); 60 | 61 | // 树的高度 62 | System.out.println("max depth = " + tree.maxDepth(root)); 63 | 64 | // 平衡二叉树 65 | System.out.println("isBalanced = " + tree.isBalanced(root)); 66 | } 67 | 68 | @Test 69 | public void testSymmetric() { 70 | TreeNode root = new TreeNode(1); 71 | TreeNode node2 = new TreeNode(2); 72 | TreeNode node3 = new TreeNode(2); 73 | TreeNode node4 = new TreeNode(3); 74 | TreeNode node5 = new TreeNode(4); 75 | TreeNode node6 = new TreeNode(4); 76 | TreeNode node7 = new TreeNode(3); 77 | root.left = node2; 78 | root.right = node3; 79 | node2.left = node4; 80 | node2.right = node5; 81 | node3.left = node6; 82 | node3.right = node7; 83 | 84 | BinaryTree tree = new BinaryTree(); 85 | System.out.println("isSymmetric = " + tree.isSymmetric(root)); 86 | } 87 | 88 | @Test 89 | public void testSerialize() { 90 | TreeNode root = new TreeNode(1); 91 | TreeNode node2 = new TreeNode(2); 92 | TreeNode node3 = new TreeNode(3); 93 | TreeNode node4 = new TreeNode(4); 94 | TreeNode node5 = new TreeNode(5); 95 | root.left = node2; 96 | root.right = node3; 97 | node3.left = node4; 98 | node3.right = node5; 99 | 100 | BinaryTree tree = new BinaryTree(); 101 | System.out.println(tree.serialize(root)); 102 | System.out.println(tree.serialize(null)); 103 | } 104 | 105 | @Test 106 | public void testDeserialize() { 107 | BinaryTree tree = new BinaryTree(); 108 | 109 | String list = "[1,2,3,null,null,4,5]"; 110 | assertEquals(tree.serialize(tree.deserialize(list)), list); 111 | 112 | list = "[5,4,7,3,null,2,null,-1,null,9]"; 113 | assertEquals(tree.serialize(tree.deserialize(list)), list); 114 | 115 | list = "[1,null,2,3]"; 116 | assertEquals(tree.serialize(tree.deserialize(list)), list); 117 | } 118 | } -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/hash/MyLinkedHashMap.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | public class MyLinkedHashMap extends MyHashMap { 4 | 5 | /** 6 | * 双向链表头结点,最早插入或访问的结点 7 | */ 8 | Entry head; 9 | 10 | /** 11 | * 双向链表尾结点,最新插入或最近访问的结点 12 | */ 13 | Entry tail; 14 | 15 | /** 16 | * true 表示访问顺序,false 表示插入顺序,默认为 false 17 | */ 18 | boolean accessOrder; 19 | 20 | public MyLinkedHashMap() { 21 | super(); 22 | accessOrder = false; 23 | } 24 | 25 | public MyLinkedHashMap(int initialCapacity) { 26 | super(initialCapacity); 27 | accessOrder = false; 28 | } 29 | 30 | public MyLinkedHashMap(int initialCapacity, boolean accessOrder) { 31 | super(initialCapacity); 32 | this.accessOrder = accessOrder; 33 | } 34 | 35 | // 将结点插入到双向链表末尾 36 | private void linkNodeLast(Entry p) { 37 | Entry last = tail; 38 | tail = p; 39 | if (last == null) { 40 | head = p; 41 | } else { 42 | p.before = last; 43 | last.after = p; 44 | } 45 | } 46 | 47 | // 创建新结点,并插入到双向链表的末尾 48 | Node newNode(String key, String value, Node next) { 49 | Entry p = new Entry(key, value, next); 50 | linkNodeLast(p); 51 | return p; 52 | } 53 | 54 | // 从双向链表中删除结点 55 | void afterNodeRemoval(Node e) { 56 | Entry p = (Entry)e; 57 | Entry b = p.before; 58 | Entry a = p.after; 59 | p.before = p.after = null; 60 | 61 | if (b == null) { 62 | head = a; 63 | } else { 64 | b.after = a; 65 | } 66 | 67 | if (a == null) { 68 | tail = b; 69 | } else { 70 | a.before = b; 71 | } 72 | } 73 | 74 | // 删除最早插入或访问的结点 75 | void afterNodeInsertion() { 76 | Entry first = head; 77 | if (first != null && removeEldestEntry(first)) { 78 | String key = first.key; 79 | removeNode(key); 80 | } 81 | } 82 | 83 | public String get(String key) { 84 | Node e = getNode(key); 85 | if (e == null) { 86 | return null; 87 | } 88 | if (accessOrder) { 89 | afterNodeAccess(e); 90 | } 91 | return e.value; 92 | } 93 | 94 | // 如果是访问顺序,将结点移动到双向链表的末尾 95 | void afterNodeAccess(Node e) { 96 | Entry last = tail; 97 | if (accessOrder && last != e) { 98 | Entry p = (Entry)e; 99 | Entry b = p.before; 100 | Entry a = p.after; 101 | p.after = null; 102 | 103 | if (b == null) { 104 | head = a; 105 | } else { 106 | b.after = a; 107 | } 108 | 109 | if (a == null) { 110 | last = b; 111 | } else { 112 | a.before = b; 113 | } 114 | 115 | if (last == null) { 116 | head = p; 117 | } else { 118 | p.before = last; 119 | last.after = p; 120 | } 121 | 122 | tail = p; 123 | } 124 | } 125 | 126 | public boolean containsValue(String value) { 127 | for (Entry e = head; e != null; e = e.after) { 128 | if (value.equals(e.value)) { 129 | return true; 130 | } 131 | } 132 | return false; 133 | } 134 | 135 | public void clear() { 136 | super.clear(); 137 | head = tail = null; 138 | } 139 | 140 | protected boolean removeEldestEntry(Entry eldest) { 141 | return false; 142 | } 143 | 144 | public String toString() { 145 | StringBuilder sb = new StringBuilder(); 146 | sb.append("{"); 147 | for (Entry p = head; p != null; p = p.after) { 148 | sb.append(p.key); 149 | sb.append("="); 150 | sb.append(p.value); 151 | sb.append(",").append(" "); 152 | } 153 | sb.delete(sb.length() - 2, sb.length()); 154 | sb.append("}"); 155 | return sb.toString(); 156 | } 157 | 158 | class Entry extends MyHashMap.Node { 159 | Entry before, after; 160 | Entry(String key, String value, Node next) { 161 | super(key, value, next); 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/array/DynamicArray.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.array; 2 | 3 | /** 4 | * 实现一个支持动态扩容的数组 5 | */ 6 | public class DynamicArray { 7 | 8 | /** 9 | * 默认容量 10 | */ 11 | public static final int DEFAULT_CAPACITY = 10; 12 | 13 | /** 14 | * 最大容量 15 | */ 16 | public static final int MAX_CAPACITY = Integer.MAX_VALUE; 17 | 18 | /** 19 | * 当前容量 20 | */ 21 | int capacity; 22 | 23 | /** 24 | * 当前元素个数 25 | */ 26 | int size; 27 | 28 | /** 29 | * 数组容器 30 | */ 31 | E[] table; 32 | 33 | public DynamicArray() { 34 | this(DEFAULT_CAPACITY); 35 | } 36 | 37 | public DynamicArray(int initialCapacity) { 38 | capacity = initialCapacity; 39 | table = (E[]) new Object[capacity]; 40 | } 41 | 42 | public void add(E e) { 43 | addLast(e); 44 | } 45 | 46 | public void addFirst(E e) { 47 | addElement(0, e); 48 | } 49 | 50 | public void addLast(E e) { 51 | addElement(size, e); 52 | } 53 | 54 | public void addElement(int index, E e) { 55 | if (index < 0 || index > size) { 56 | throw new IllegalArgumentException("add fail. index out of range."); 57 | } 58 | 59 | if (size == MAX_CAPACITY) { 60 | throw new IllegalArgumentException("add fail. exceed max capacity."); 61 | } 62 | 63 | resize(); 64 | 65 | for (int i = size - 1; i >= index; i--) { 66 | table[i + 1] = table[i]; 67 | } 68 | table[index] = e; 69 | size++; 70 | } 71 | 72 | public E remove() { 73 | return removeLast(); 74 | } 75 | 76 | public E removeFirst() { 77 | return removeElement(0); 78 | } 79 | 80 | public E removeLast() { 81 | return removeElement(size - 1); 82 | } 83 | 84 | public E removeElement(int index) { 85 | if (index < 0 || index > size - 1) { 86 | throw new IllegalArgumentException("remove fail. index out of range."); 87 | } 88 | 89 | E element = table[index]; 90 | for (int i = index; i < size - 1; i++) { 91 | table[i] = table[i + 1]; 92 | } 93 | table[size - 1] = null; 94 | size--; 95 | 96 | resize(); 97 | 98 | return element; 99 | } 100 | 101 | /** 102 | * 获取元素 103 | */ 104 | public E get(int index) { 105 | if (index < 0 || index > size - 1) { 106 | throw new IllegalArgumentException("get fail. index out of range."); 107 | } 108 | return table[index]; 109 | } 110 | 111 | /** 112 | * 根据索引设置元素值 113 | */ 114 | public void set(int index, E value) { 115 | if (index < 0 || index > size - 1) { 116 | throw new IllegalArgumentException("set fail. index out of range."); 117 | } 118 | table[index] = value; 119 | } 120 | 121 | /** 122 | * 判断数组是否为空 123 | */ 124 | public boolean isEmpty() { 125 | return size == 0; 126 | } 127 | 128 | /** 129 | * 获取当前数组元素个数 130 | */ 131 | public int getSize() { 132 | return size; 133 | } 134 | 135 | /** 136 | * 获取当前数组容量 137 | */ 138 | public int getCapacity() { 139 | return capacity; 140 | } 141 | 142 | /** 143 | * 数组扩容 144 | */ 145 | public void resize() { 146 | int oldCapacity = capacity; 147 | 148 | // 扩容 149 | if (size == capacity) { 150 | // 容量已满,容量扩大一倍 151 | if (capacity > MAX_CAPACITY / 2) { 152 | capacity = MAX_CAPACITY; 153 | } else { 154 | capacity = capacity * 2; 155 | } 156 | } 157 | 158 | // 缩容 159 | if (size <= capacity / 4 && capacity / 2 != 0) { 160 | // 当实际元素个数小于等于容量的四分之一时,将容量缩小为原来的一半 161 | capacity = capacity / 2; 162 | } 163 | 164 | if (capacity != oldCapacity) { 165 | E[] newTable = (E[]) new Object[capacity]; 166 | System.arraycopy(table, 0, newTable, 0, size); 167 | table = newTable; 168 | } 169 | } 170 | 171 | public String toString() { 172 | if (isEmpty()) { 173 | return "[]"; 174 | } 175 | 176 | StringBuilder sb = new StringBuilder(); 177 | sb.append("["); 178 | for (int i = 0; i < size; i++) { 179 | sb.append(get(i)); 180 | if (i == size - 1) { 181 | sb.append("]"); 182 | } else { 183 | sb.append(',').append(' '); 184 | } 185 | } 186 | 187 | return sb.toString(); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/graph/Graph.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.graph; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.Queue; 7 | 8 | /** 9 | * 基于邻接表的无向图实现 10 | */ 11 | public class Graph { 12 | /** 顶点个数 */ 13 | private int v; 14 | 15 | /** 邻接表 */ 16 | private LinkedList[] adj; 17 | 18 | public Graph(int v) { 19 | this.v = v; 20 | adj = new LinkedList[v]; 21 | for (int i = 0; i < v; i++) { 22 | adj[i] = new LinkedList<>(); 23 | } 24 | } 25 | 26 | /** 27 | * 添加一条边 28 | */ 29 | public void addEdge(int s, int t) { 30 | adj[s].add(t); 31 | adj[t].add(s); 32 | } 33 | 34 | /** 35 | * 广度优先搜索 36 | * @param s 搜索起始顶点 37 | * @param t 搜索终止顶点 38 | */ 39 | public void bfs(int s, int t) { 40 | if (s == t) { 41 | return; 42 | } 43 | 44 | // 标识已经访问过的顶点,避免重复访问 45 | boolean[] visited = new boolean[v]; 46 | visited[s] = true; 47 | 48 | // 记录已经被访问、但相邻的还没被访问的顶点 49 | Queue queue = new LinkedList<>(); 50 | queue.offer(s); 51 | 52 | // 记录搜索路径 53 | int[] prev = new int[v]; 54 | for (int i = 0; i < v; i++) { 55 | prev[i] = -1; 56 | } 57 | 58 | while (queue.size() != 0) { 59 | int w = queue.poll(); 60 | // 遍历所有相邻的顶点 61 | for (int i = 0; i < adj[w].size(); i++) { 62 | int q = adj[w].get(i); 63 | // 如果相邻的顶点没有被访问 64 | if (!visited[q]) { 65 | // 记录访问路径 66 | prev[q] = w; 67 | if (q == t) { 68 | print(prev, s, t); 69 | return; 70 | } 71 | visited[q] = true; 72 | queue.offer(q); 73 | } 74 | } 75 | } 76 | } 77 | 78 | /** 79 | * 递归打印 s -> t 的路径 80 | * @param prev 81 | * @param s 82 | * @param t 83 | */ 84 | public void print(int[] prev, int s, int t) { 85 | if (prev[t] != -1 && t != s) { 86 | print(prev, s, prev[t]); 87 | System.out.print(" -> " + t); 88 | } else { 89 | System.out.print(t); 90 | } 91 | } 92 | 93 | boolean found = false; 94 | 95 | public void dfs(int s, int t) { 96 | found = false; 97 | boolean[] visited = new boolean[v]; 98 | int[] prev = new int[v]; 99 | for (int i = 0; i < v; i++) { 100 | prev[i] = -1; 101 | } 102 | 103 | dfsHelper(s, t, visited, prev); 104 | print(prev, s, t); 105 | } 106 | 107 | private void dfsHelper(int w, int t, boolean[] visited, int[] prev) { 108 | if (found) { 109 | return; 110 | } 111 | 112 | visited[w] = true; 113 | if (w == t) { 114 | found = true; 115 | return; 116 | } 117 | 118 | for (int i = 0; i < adj[w].size(); i++) { 119 | if (found) return; 120 | int q = adj[w].get(i); 121 | if (!visited[q]) { 122 | prev[q] = w; 123 | dfsHelper(q, t, visited, prev); 124 | } 125 | } 126 | } 127 | 128 | /** 129 | * 返回某个顶点的 N 度顶点 130 | */ 131 | public List> getLevelByBfs(int s, int level) { 132 | List> result = new ArrayList<>(); 133 | for (int i = 0; i < level; i++) { 134 | result.add(new ArrayList<>()); 135 | } 136 | 137 | boolean[] visited = new boolean[v]; 138 | visited[s] = true; 139 | 140 | Queue queue = new LinkedList<>(); 141 | queue.offer(s); 142 | 143 | int count = 0; 144 | 145 | while (count < level && !queue.isEmpty()) { 146 | int size = queue.size(); 147 | for (int i = 0; i < size; i++) { 148 | int w = queue.poll(); 149 | // 遍历所有相邻的顶点 150 | for (int j = 0; j < adj[w].size(); j++) { 151 | int q = adj[w].get(j); 152 | // 如果相邻的顶点没有被访问 153 | if (!visited[q]) { 154 | visited[q] = true; 155 | queue.offer(q); 156 | result.get(count).add(q); 157 | } 158 | } 159 | } 160 | count++; 161 | } 162 | 163 | return result; 164 | } 165 | 166 | /** 167 | * 返回某个顶点的 N 度顶点 168 | */ 169 | public List getLevelByDfs(int s, int level) { 170 | List result = new ArrayList<>(); 171 | boolean[] visited = new boolean[v]; 172 | dfsLevel(result, s, 0, level, visited); 173 | return result; 174 | } 175 | 176 | public void dfsLevel(List result, int s, int current, int level, boolean[] visited) { 177 | visited[s] = true; 178 | if (current >= level) return; 179 | for (int i = 0; i < adj[s].size(); i++) { 180 | int q = adj[s].get(i); 181 | if (!visited[q]) { 182 | result.add(q); 183 | } 184 | dfsLevel(result, q, current + 1, level, visited); 185 | } 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /note/tree/二叉树遍历.md: -------------------------------------------------------------------------------- 1 | # 二叉树的四种遍历方式 2 | 3 | ## 前序遍历 4 | 5 | 根 -> 左 -> 右 6 | 7 | ### 常规解法 8 | 9 | * 初始化栈,并将根节点入栈; 10 | * 当栈不为空时: 11 | * 弹出栈顶元素 node,并将值添加到结果中; 12 | * 如果 node 的右子树非空,将右子树入栈; 13 | * 如果 node 的左子树非空,将左子树入栈; 14 | 15 | ``` 16 | public List preorderTraversal(TreeNode root) { 17 | List result = new ArrayList<>(); 18 | if (root == null) { 19 | return result; 20 | } 21 | 22 | Stack stack = new Stack<>(); 23 | stack.push(root); 24 | 25 | while (!stack.isEmpty()) { 26 | TreeNode node = stack.pop(); 27 | result.add(node.val); 28 | 29 | if (node.right != null) { 30 | stack.push(node.right); 31 | } 32 | 33 | if (node.left != null) { 34 | stack.push(node.left); 35 | } 36 | } 37 | 38 | return result; 39 | } 40 | ``` 41 | 42 | ### 模板解法 43 | 44 | * 将根节点和所有的左孩子入栈并加入到结果,直到左孩子为空; 45 | * 每弹出一个栈顶元素,就切换到它的右孩子,重复上面的步骤,直到栈为空; 46 | 47 | ``` 48 | public List preorderTraversal(TreeNode root) { 49 | List result = new ArrayList<>(); 50 | Stack stack = new Stack<>(); 51 | TreeNode cur = root; 52 | 53 | while (cur != null || !stack.isEmpty()) { 54 | while (cur != null) { 55 | result.add(cur.val); 56 | stack.push(cur); 57 | cur = cur.left; 58 | } 59 | 60 | TreeNode tmp = stack.pop(); 61 | cur = tmp.right; 62 | } 63 | 64 | return result; 65 | } 66 | ``` 67 | 68 | ## 中序遍历 69 | 70 | 左 -> 根 -> 右 71 | 72 | 和前序遍历的模板解法基本相同,只是在出栈的时候才将节点 tmp 的值加入到结果中。 73 | 74 | ``` 75 | public List inorderTraversal(TreeNode root) { 76 | List result = new ArrayList<>(); 77 | Stack stack = new Stack<>(); 78 | TreeNode cur = root; 79 | 80 | while (cur != null || !stack.isEmpty()) { 81 | while (cur != null) { 82 | stack.push(cur); 83 | cur = cur.left; 84 | } 85 | 86 | TreeNode tmp = stack.pop(); 87 | result.add(tmp.val); 88 | cur = tmp.right; 89 | } 90 | 91 | return result; 92 | } 93 | ``` 94 | 95 | ## 后序遍历 96 | 97 | 左 -> 右 -> 根 98 | 99 | 类似前序遍历的常规解法,只不过入栈时额外加入一个标识 flag,然后每次从栈中弹出元素时, 100 | 如果 flag 为 0, 则需要将 flag 变为 1 并连同该节点再次入栈,只有当 flag 为 1 时才可将该节点加入到结果中。 101 | 102 | ``` 103 | public List postorderTraversal(TreeNode root) { 104 | List result = new ArrayList<>(); 105 | if (root == null) { 106 | return result; 107 | } 108 | 109 | Map map = new HashMap<>(); 110 | Stack stack = new Stack<>(); 111 | stack.push(root); 112 | map.put(root, 0); 113 | 114 | while (!stack.isEmpty()) { 115 | TreeNode node = stack.pop(); 116 | if (map.get(node) == 1) { 117 | result.add(node.val); 118 | } else { 119 | stack.push(node); 120 | map.put(node, 1); 121 | if (node.right != null) { 122 | stack.push(node.right); 123 | map.put(node.right, 0); 124 | } 125 | if (node.left != null) { 126 | stack.push(node.left); 127 | map.put(node.left, 0); 128 | } 129 | } 130 | } 131 | 132 | return result; 133 | } 134 | ``` 135 | 136 | 也可以类似前序遍历的模板解法,增加一个变量用来记录上一次访问的节点。 137 | 如果当前节点没有右孩子,或者当前节点的右孩子刚刚被访问过,将当前节点的值加入结果列表。 138 | 139 | ``` 140 | public List postorderTraversal(TreeNode root) { 141 | List result = new ArrayList<>(); 142 | Stack stack = new Stack<>(); 143 | TreeNode cur = root; 144 | TreeNode last = null; 145 | 146 | while (cur != null || !stack.isEmpty()) { 147 | while (cur != null) { 148 | stack.push(cur); 149 | cur = cur.left; 150 | } 151 | TreeNode tmp = stack.peek(); 152 | if (tmp.right == null || tmp.right == last) { 153 | result.add(tmp.val); 154 | stack.pop(); 155 | last = tmp; 156 | } else { 157 | cur = tmp.right; 158 | } 159 | } 160 | 161 | return result; 162 | } 163 | ``` 164 | 165 | ## 层序遍历 166 | 167 | 前面三种遍历都采用了深度优先搜索的方式,而层次遍历使用了广度优先搜索,广度优先搜索主要使用队列实现。 168 | 169 | * 初始化队列,并将根节点加入到队列中; 170 | * 当队列不为空时: 171 | * 队列中弹出节点,加入到结果中; 172 | * 如果左子树非空,左子树加入队列; 173 | * 如果右子树非空,右子树加入队列; 174 | 175 | ``` 176 | public List> levelOrder(TreeNode root) { 177 | List> result = new ArrayList<>(); 178 | if (root == null) { 179 | return result; 180 | } 181 | 182 | Queue queue = new LinkedList<>(); 183 | queue.offer(root); 184 | 185 | while (!queue.isEmpty()) { 186 | List level = new ArrayList<>(); 187 | int size = queue.size(); 188 | for (int i = 0; i < size; i++) { 189 | TreeNode node = queue.poll(); 190 | level.add(node.val); 191 | if (node.left != null) { 192 | queue.offer(node.left); 193 | } 194 | if (node.right != null) { 195 | queue.offer(node.right); 196 | } 197 | } 198 | result.add(level); 199 | } 200 | 201 | return result; 202 | } 203 | ``` -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/skiplist/SkipList.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.skiplist; 2 | 3 | import java.util.Random; 4 | 5 | public class SkipList { 6 | 7 | /** 8 | * 索引最大层数,包含原始链表那一层。 9 | */ 10 | private static final int MAX_LEVEL = 16; 11 | 12 | /** 13 | * 当前索引总层数。 14 | */ 15 | private int levelCount = 1; 16 | 17 | /** 18 | * 跳表头结点。 19 | * 类似链表里的带头链表,哨兵结点,本身不存储数据,下一跳指向各层索引的头结点。 20 | */ 21 | private Node head; 22 | 23 | /** 24 | * 用于生成随机数,避免链表中结点过多,导致性能下降。 25 | */ 26 | private Random r; 27 | 28 | public SkipList() { 29 | head = new Node(); 30 | r = new Random(); 31 | } 32 | 33 | /** 34 | * 往跳表插入一个数据,数据从小到大排序。 35 | */ 36 | public void insert(int value) { 37 | // 生成随机数 38 | int level = randomLevel(); 39 | Node newNode = new Node(); 40 | newNode.data = value; 41 | newNode.maxLevel = level; 42 | 43 | Node[] update = new Node[level]; 44 | for (int i = level - 1; i >= 0; i--) { 45 | update[i] = head; 46 | } 47 | 48 | Node p = head; 49 | for (int i = level - 1; i >= 0; i--) { 50 | // 找到第 i 层索引的插入位置,将插入位置前面的结点保存到 update 数组 51 | while (p.forwards[i] != null && p.forwards[i].data < value) { 52 | p = p.forwards[i]; 53 | } 54 | update[i] = p; 55 | } 56 | 57 | for (int i = level - 1; i >= 0; i--) { 58 | // 更新各层的 forwards 结点 59 | newNode.forwards[i] = update[i].forwards[i]; 60 | update[i].forwards[i] = newNode; 61 | } 62 | 63 | // 更新当前索引总层数 64 | if (levelCount < level) { 65 | levelCount = level; 66 | } 67 | } 68 | 69 | /** 70 | * 删除跳表数据 71 | */ 72 | public void delete(int value) { 73 | Node[] update = new Node[levelCount]; 74 | Node p = head; 75 | for (int i = levelCount - 1; i >= 0; i--) { 76 | while (p.forwards[i] != null && p.forwards[i].data < value) { 77 | p = p.forwards[i]; 78 | } 79 | update[i] = p; 80 | } 81 | 82 | if (p.forwards[0] != null && p.forwards[0].data == value) { 83 | for (int i = levelCount - 1; i >= 0; i--) { 84 | // 判断第 i 层索引是否有要删除的结点 85 | if (update[i].forwards[i] != null && update[i].forwards[i].data == value) { 86 | update[i].forwards[i] = update[i].forwards[i].forwards[i]; 87 | } 88 | } 89 | } 90 | } 91 | 92 | public Node find(int value) { 93 | Node p = head; 94 | // 从最上层开始查找,如果下一跳结点的值大于等于要查找的值,切换到下一层继续查找,直到第 0 层 95 | for (int i = levelCount - 1; i >= 0; i--) { 96 | while (p.forwards[i] != null && p.forwards[i].data < value) { 97 | p = p.forwards[i]; 98 | } 99 | } 100 | 101 | // 第 0 层存储了所有结点,如果找到要查找的值,返回该结点,否则返回 null 102 | if (p.forwards[0] != null && p.forwards[0].data == value) { 103 | return p.forwards[0]; 104 | } 105 | 106 | return null; 107 | } 108 | 109 | /** 110 | * 生成随机数 level = [1, MAX_LEVEL]。 111 | * 将结点添加到第 0 层到第 level-1 层索引中。 112 | */ 113 | private int randomLevel() { 114 | int level = 1; 115 | for (int i = 1; i < MAX_LEVEL; i++) { 116 | if (r.nextInt() % 2 == 1) { 117 | level++; 118 | } 119 | } 120 | return level; 121 | } 122 | 123 | /** 124 | * 打印每一层所有数据。 125 | */ 126 | @Override 127 | public String toString() { 128 | StringBuilder sb = new StringBuilder(); 129 | sb.append("SkipList Level Count = ").append(levelCount).append("\n"); 130 | for (int i = levelCount - 1; i >= 0; i--) { 131 | sb.append("level ").append(i).append(" --> "); 132 | for (Node p = head; p.forwards[i] != null; p = p.forwards[i]) { 133 | sb.append(p.forwards[i].data); 134 | if (p.forwards[i].forwards[i] != null) { 135 | sb.append(",").append(" "); 136 | } 137 | } 138 | sb.append("\n"); 139 | } 140 | return sb.toString(); 141 | } 142 | 143 | /** 144 | * 跳表结点。 145 | */ 146 | public class Node { 147 | 148 | /** 149 | * 结点存储的整数值。 150 | */ 151 | private int data = -1; 152 | 153 | /** 154 | * 当前索引总层数。 155 | * 索引从 0 开始计数,到 maxLevel-1 为止。 156 | * 第 0 层为原始链表,从下往上依次建立索引,最上层为第 maxLevel-1 层索引。 157 | */ 158 | private int maxLevel = 0; 159 | 160 | /** 161 | * 保存当前结点的所有下一跳结点。 162 | * forwards[i] 表示当前结点在第 i 层索引的下一跳结点,i in [0, maxLevel-1] 163 | */ 164 | private Node forwards[] = new Node[MAX_LEVEL]; 165 | 166 | @Override 167 | public String toString() { 168 | StringBuilder sb = new StringBuilder(); 169 | sb.append("SkipList Node ").append(data); 170 | sb.append(", maxLevel = ").append(maxLevel).append("\n"); 171 | for (int i = maxLevel - 1; i >= 0; i--) { 172 | sb.append("level ").append(i).append(" --> "); 173 | if (forwards[i] == null) { 174 | sb.append("null"); 175 | } else { 176 | sb.append(forwards[i].data); 177 | } 178 | sb.append("\n"); 179 | } 180 | return sb.toString(); 181 | } 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/hash/MyHashMap.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.hash; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 实现一个基于链表法解决冲突问题的散列表。 7 | * 实现较为简单,key 不能为空,不支持动态扩容。 8 | */ 9 | public class MyHashMap { 10 | 11 | private Node[] table; 12 | private int size; 13 | 14 | private static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 16 15 | 16 | public MyHashMap() { 17 | this(DEFAULT_INITIAL_CAPACITY); 18 | } 19 | 20 | public MyHashMap(int capacity) { 21 | table = new Node[capacity]; 22 | } 23 | 24 | public String get(String key) { 25 | Node p = getNode(key); 26 | return (p == null) ? null : p.value; 27 | } 28 | 29 | public Node getNode(String key) { 30 | int index = hash(key); 31 | Node p = table[index]; 32 | 33 | // 遍历整个链表 34 | while (p != null) { 35 | if (key.equals(p.key)) { 36 | break; 37 | } 38 | p = p.next; 39 | } 40 | 41 | return p; 42 | } 43 | 44 | public String put(String key, String value) { 45 | int index = hash(key); 46 | Node p = table[index]; 47 | 48 | if (p == null) { 49 | // 槽位为空,直接添加链表头结点 50 | table[index] = newNode(key, value, null); 51 | } else { 52 | Node target = null; 53 | Node prev = null; 54 | 55 | // 遍历链表,查找是否存在 key 56 | while (p != null) { 57 | if (key.equals(p.key)) { 58 | target = p; 59 | break; 60 | } 61 | prev = p; 62 | p = p.next; 63 | } 64 | 65 | if (target != null) { 66 | // 存在 key,替换 value 67 | String oldValue = target.value; 68 | target.value = value; 69 | afterNodeAccess(target); 70 | return oldValue; 71 | } else { 72 | // 不存在 key,在链表末尾添加一个结点 73 | prev.next = newNode(key, value, null); 74 | } 75 | } 76 | 77 | size++; 78 | afterNodeInsertion(); 79 | return null; 80 | } 81 | 82 | public String remove(String key) { 83 | Node node = removeNode(key); 84 | return (node == null) ? null : node.value; 85 | } 86 | 87 | public Node removeNode(String key) { 88 | int index = hash(key); 89 | Node p = table[index]; 90 | 91 | if (p != null) { 92 | Node first = p; 93 | Node target = null; 94 | Node prev = null; 95 | 96 | while (p != null) { 97 | if (key.equals(p.key)) { 98 | target = p; 99 | break; 100 | } 101 | prev = p; 102 | p = p.next; 103 | } 104 | 105 | if (target != null) { 106 | if (target == first) { 107 | // 删除的是链表第一个结点 108 | table[index] = target.next; 109 | } else { 110 | prev.next = target.next; 111 | } 112 | size--; 113 | afterNodeRemoval(target); 114 | // 返回删除的结点 115 | return target; 116 | } 117 | } 118 | 119 | return null; 120 | } 121 | 122 | Node newNode(String key, String value, Node next) { 123 | return new Node(key, value, next); 124 | } 125 | 126 | void afterNodeAccess(Node p) { } 127 | void afterNodeInsertion() { } 128 | void afterNodeRemoval(Node p) { } 129 | 130 | public void printAll() { 131 | System.out.println("size = " + size()); 132 | System.out.println(toString()); 133 | for (int i = 0; i < table.length; i++) { 134 | System.out.print("slot " + i + ": "); 135 | for (Node p = table[i]; p != null; p = p.next) { 136 | System.out.print("(" + p.key + "=" + p.value + ")"); 137 | if (p.next != null) { 138 | System.out.print(" --> "); 139 | } 140 | } 141 | System.out.println(); 142 | } 143 | } 144 | 145 | public String toString() { 146 | StringBuilder sb = new StringBuilder(); 147 | sb.append("{"); 148 | for (int i = 0; i < table.length; i++) { 149 | for (Node p = table[i]; p != null; p = p.next) { 150 | sb.append(p.key); 151 | sb.append("="); 152 | sb.append(p.value); 153 | sb.append(",").append(" "); 154 | } 155 | } 156 | sb.delete(sb.length() - 2, sb.length()); 157 | sb.append("}"); 158 | return sb.toString(); 159 | } 160 | 161 | public boolean containsKey(String key) { 162 | return getNode(key) != null; 163 | } 164 | 165 | public boolean containsValue(String value) { 166 | for (int i = 0; i < table.length; i++) { 167 | for (Node p = table[i]; p != null; p = p.next) { 168 | if (value.equals(p.value)) { 169 | return true; 170 | } 171 | } 172 | } 173 | return false; 174 | } 175 | 176 | public void clear() { 177 | size = 0; 178 | Arrays.fill(table, null); 179 | } 180 | 181 | public int size() { 182 | return size; 183 | } 184 | 185 | public boolean isEmpty() { 186 | return size == 0; 187 | } 188 | 189 | public int hash(Object key) { 190 | int h = key.hashCode(); 191 | return (h ^ (h >>> 16)) % table.length; 192 | } 193 | 194 | class Node { 195 | String key; 196 | String value; 197 | Node next; 198 | 199 | public Node(String key, String value, Node next) { 200 | this.key = key; 201 | this.value = value; 202 | this.next = next; 203 | } 204 | 205 | public String getKey() { 206 | return key; 207 | } 208 | 209 | public String getValue() { 210 | return value; 211 | } 212 | 213 | public String toString() { 214 | return key + "=" + value; 215 | } 216 | } 217 | 218 | } 219 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/tree/BinarySearchTree.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.tree; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | public class BinarySearchTree { 7 | private TreeNode root; 8 | 9 | public BinarySearchTree(TreeNode node) { 10 | root = node; 11 | } 12 | 13 | public TreeNode find(int data) { 14 | TreeNode p = root; 15 | while (p != null) { 16 | if (data < p.val) { 17 | p = p.left; 18 | } else if (data > p.val) { 19 | p = p.right; 20 | } else { 21 | return p; 22 | } 23 | } 24 | return null; 25 | } 26 | 27 | public void insert(int data) { 28 | if (root == null) { 29 | root = new TreeNode(data); 30 | return; 31 | } 32 | 33 | TreeNode p = root; 34 | while (p != null) { 35 | if (data < p.val) { 36 | if (p.left == null) { 37 | p.left = new TreeNode(data); 38 | return; 39 | } 40 | p = p.left; 41 | } else { 42 | if (p.right == null) { 43 | p.right = new TreeNode(data); 44 | return; 45 | } 46 | p = p.right; 47 | } 48 | } 49 | } 50 | 51 | public void delete(int data) { 52 | TreeNode p = root; 53 | TreeNode parent = null; 54 | 55 | while (p != null && p.val != data) { 56 | parent = p; 57 | if (data < p.val) { 58 | p = p.left; 59 | } else { 60 | p = p.right; 61 | } 62 | } 63 | 64 | if (p == null) { 65 | return; // 没有找到要删除的节点 66 | } 67 | 68 | // 要删除的节点有两个孩子节点 69 | if (p.left != null && p.right != null) { 70 | TreeNode minNode = p.right; 71 | TreeNode minNodeParent = p; 72 | // 找到右子树的最小节点,替换到要删除的节点上 73 | while (minNode.left != null) { 74 | minNodeParent = minNode; 75 | minNode = minNode.left; 76 | } 77 | p.val = minNode.val; 78 | // 要删除的节点变成了右子树的最小节点 79 | // 由于该节点肯定不会有左孩子,因此可以使用接下来的代码进行删除 80 | p = minNode; 81 | parent = minNodeParent; 82 | } 83 | 84 | // 删除叶子节点,或者只有一个孩子的节点 85 | TreeNode child; 86 | if (p.left != null) { 87 | child = p.left; 88 | } else if (p.right != null) { 89 | child = p.right; 90 | } else { 91 | child = null; 92 | } 93 | 94 | if (parent == null) { 95 | // 删除的是根节点 96 | root = child; 97 | } else if (parent.left == p) { 98 | parent.left = child; 99 | } else { 100 | parent.right = child; 101 | } 102 | } 103 | 104 | public TreeNode maximum() { 105 | return getMaxNode(root); 106 | } 107 | 108 | public TreeNode getMaxNode(TreeNode node) { 109 | if (node == null) { 110 | return null; 111 | } 112 | TreeNode p = node; 113 | while (p.right != null) { 114 | p = p.right; 115 | } 116 | return p; 117 | } 118 | 119 | public TreeNode minimum() { 120 | return getMinNode(root); 121 | } 122 | 123 | public TreeNode getMinNode(TreeNode node) { 124 | if (node == null) { 125 | return null; 126 | } 127 | TreeNode p = node; 128 | while (p.left != null) { 129 | p = p.left; 130 | } 131 | return p; 132 | } 133 | 134 | /** 135 | * 查找节点的前驱节点。 136 | * 中序遍历的前一个节点,小于该节点的所有节点中最大的那个节点。 137 | */ 138 | public TreeNode predecessor(int data) { 139 | if (root == null) { 140 | return null; 141 | } 142 | 143 | TreeNode parent = null; // 查找过程中当前节点的父亲节点 144 | TreeNode lastR = null; // 最后一次在查找路径中出现右拐的节点 145 | TreeNode p = root; 146 | while (p != null) { 147 | if (p.val == data) { 148 | break; // 查找到节点 149 | } 150 | parent = p; 151 | if (data < p.val) { 152 | p = p.left; 153 | } else { 154 | lastR = p; 155 | p = p.right; 156 | } 157 | } 158 | 159 | if (p == null) { 160 | return null; // 没有找到节点 161 | } 162 | 163 | // 如果节点有左子树,那么该节点的前驱节点是其左子树中值最大的节点 164 | if (p.left != null) { 165 | return getMaxNode(p.left); 166 | } 167 | 168 | // 如果是最小的节点,则没有前驱节点 169 | if (parent == null || lastR == null) { 170 | return null; 171 | } 172 | 173 | // 如果节点没有左子树,那么判断该节点和其父节点的关系 174 | if (p == parent.right) { 175 | // 如果节点是其父亲节点的右边节点,那么该节点的前驱结点即为其父亲节点 176 | return parent; 177 | } else { 178 | // 如果节点是其父亲节点的左边孩子,那么沿着其父亲节点一直向树的顶端寻找出现右拐的节点 179 | return lastR; 180 | } 181 | } 182 | 183 | /** 184 | * 查找节点的后继节点。 185 | * 中序遍历的后一个节点,大于该节点的所有节点中最小的那个节点。 186 | */ 187 | public TreeNode successor(int data) { 188 | if (root == null) { 189 | return null; 190 | } 191 | 192 | TreeNode parent = null; // 查找过程中当前节点的父亲节点 193 | TreeNode lastL = null; // 最后一次在查找路径中出现左拐的节点 194 | TreeNode p = root; 195 | while (p != null) { 196 | if (p.val == data) { 197 | break; // 查找到节点 198 | } 199 | parent = p; 200 | if (data < p.val) { 201 | lastL = p; 202 | p = p.left; 203 | } else { 204 | p = p.right; 205 | } 206 | } 207 | 208 | if (p == null) { 209 | return null; // 没有找到节点 210 | } 211 | 212 | // 如果节点有右子树,那么该节点的后继节点是其右子树中值最小的节点 213 | if (p.right != null) { 214 | return getMinNode(p.right); 215 | } 216 | 217 | // 如果是最大的节点,则没有后继节点 218 | if (parent == null || lastL == null) { 219 | return null; 220 | } 221 | 222 | // 如果节点没有右子树,那么判断该节点和其父节点的关系 223 | if (p == parent.left) { 224 | // 如果节点是其父亲节点的左边节点,那么该节点的后继结点即为其父亲节点 225 | return parent; 226 | } else { 227 | // 如果节点是其父亲节点的右边孩子,那么沿着其父亲节点一直向树的顶端寻找出现左拐的节点 228 | return lastL; 229 | } 230 | } 231 | 232 | // Encodes a tree to a single string. 233 | public String serialize(TreeNode root) { 234 | StringBuilder sb = new StringBuilder(); 235 | buildString(root, sb); 236 | return sb.toString(); 237 | } 238 | 239 | public void buildString(TreeNode root, StringBuilder sb) { 240 | if (root == null) { 241 | return; 242 | } 243 | sb.append(root.val + ","); 244 | buildString(root.left, sb); 245 | buildString(root.right, sb); 246 | } 247 | 248 | // Decodes your encoded data to tree. 249 | public TreeNode deserialize(String data) { 250 | if (data == null || data.equals("")) { 251 | return null; 252 | } 253 | String[] strs = data.split(","); 254 | Queue queue = new LinkedList<>(); 255 | for (String str : strs) { 256 | queue.offer(Integer.valueOf(str)); 257 | } 258 | return buildTree(queue); 259 | } 260 | 261 | public TreeNode buildTree(Queue queue) { 262 | if (queue.isEmpty()) { 263 | return null; 264 | } 265 | TreeNode root = new TreeNode(queue.poll()); 266 | Queue smallerQueue = new LinkedList<>(); 267 | while (!queue.isEmpty() && queue.peek() < root.val) { 268 | smallerQueue.offer(queue.poll()); 269 | } 270 | root.left = buildTree(smallerQueue); 271 | root.right = buildTree(queue); 272 | return root; 273 | } 274 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ds-algo-java 2 | 3 | 数据结构和算法必知必会的 50 个代码实现(Java) 4 | 5 | * https://github.com/andavid/ds-algo-java 6 | * https://github.com/wangzheng0822/algo 7 | * https://github.com/kkzfl22/datastruct 8 | 9 | ## 数组 10 | 11 | * 实现一个 [支持动态扩容的数组][dynamic-array] 12 | * 实现一个 [大小固定的有序数组][sorted-array],支持动态增删改操作 13 | * 实现 [两个有序数组合并为一个有序数组][merge-two-sorted-array] 14 | 15 | [dynamic-array]: ./src/main/java/com/github/andavid/ds/datastructure/array/DynamicArray.java 16 | [sorted-array]: ./src/main/java/com/github/andavid/ds/datastructure/array/SortedArray.java 17 | [merge-two-sorted-array]: ./src/main/java/com/github/andavid/ds/datastructure/array/MergeTwoSortedArray.java 18 | 19 | ## 链表 20 | 21 | * 实现 [单链表][singly-linked-list]、[循环链表][circular-linked-list]、[双向链表][doubly-linked-list],支持增删操作 22 | * 实现 [单链表反转][reverse-linked-list] 23 | * 实现 [两个有序的链表合并为一个有序链表][merge-two-linked-list] 24 | * 实现 [求链表的中间结点][find-middle-node] 25 | * 实现 [链表中环的检测][cycle-linked-list] 26 | * 实现 [删除链表倒数第 n 个结点][remove-nth-node] 27 | 28 | [singly-linked-list]: ./src/main/java/com/github/andavid/ds/datastructure/linkedlist/SinglyLinkedList.java 29 | [circular-linked-list]: ./src/main/java/com/github/andavid/ds/datastructure/linkedlist/CircularLinkedList.java 30 | [doubly-linked-list]: ./src/main/java/com/github/andavid/ds/datastructure/linkedlist/DoublyLinkedList.java 31 | [reverse-linked-list]: ./src/main/java/com/github/andavid/ds/datastructure/linkedlist/ReverseLinkedList.java 32 | [merge-two-linked-list]: ./src/main/java/com/github/andavid/ds/datastructure/linkedlist/MergeTwoLinkedList.java 33 | [find-middle-node]: ./src/main/java/com/github/andavid/ds/datastructure/linkedlist/FindMiddleNode.java 34 | [cycle-linked-list]: ./src/main/java/com/github/andavid/ds/datastructure/linkedlist/CycleLinkedList.java 35 | [remove-nth-node]: ./src/main/java/com/github/andavid/ds/datastructure/linkedlist/RemoveNthNode.java 36 | 37 | ## 栈 38 | 39 | * 用数组实现一个 [顺序栈][array-stack] 40 | * 用链表实现一个 [链式栈][linked-stack] 41 | * 编程模拟实现一个 [浏览器的前进、后退][sample-browser] 功能 42 | 43 | [array-stack]: ./src/main/java/com/github/andavid/ds/datastructure/stack/ArrayStack.java 44 | [linked-stack]: ./src/main/java/com/github/andavid/ds/datastructure/stack/LinkedStack.java 45 | [sample-browser]: ./src/main/java/com/github/andavid/ds/datastructure/stack/SampleBrowser.java 46 | 47 | ## 队列 48 | 49 | * 用数组实现一个 [顺序队列][array-queue] 50 | * 用链表实现一个 [链式队列][linked-queue] 51 | * 实现一个 [循环队列][circular-queue] 52 | 53 | [array-queue]: ./src/main/java/com/github/andavid/ds/datastructure/queue/ArrayQueue.java 54 | [linked-queue]: ./src/main/java/com/github/andavid/ds/datastructure/queue/LinkedQueue.java 55 | [circular-queue]: ./src/main/java/com/github/andavid/ds/datastructure/queue/CircularQueue.java 56 | 57 | ## 跳表 58 | 59 | * 实现一个 [跳表][skip-list] 60 | 61 | [skip-list]: ./src/main/java/com/github/andavid/ds/datastructure/skiplist/SkipList.java 62 | 63 | ## 散列表 64 | 65 | * 实现一个 [基于链表法解决冲突问题的散列表][my-hash-map] 66 | * 实现一个 [LRU缓存淘汰算法][lru-cache] 67 | * [一致性哈希算法][consistent-hash] 68 | 69 | [my-hash-map]: ./src/main/java/com/github/andavid/ds/datastructure/hash/MyHashMap.java 70 | [lru-cache]: ./src/main/java/com/github/andavid/ds/datastructure/hash/LruCache.java 71 | [consistent-hash]: ./src/main/java/com/github/andavid/ds/datastructure/hash/ConsistentHash.java 72 | 73 | ## 二叉树 74 | 75 | * 实现一个 [二叉查找树][BinarySearchTree],并且支持插入、删除、查找操作 76 | * 实现查找 [二叉查找树中某个节点的后继、前驱节点][BinarySearchTree] 77 | * 实现 [二叉树前、中、后序以及按层遍历][BinaryTree] 78 | 79 | [BinarySearchTree]: ./src/main/java/com/github/andavid/ds/datastructure/tree/BinarySearchTree.java 80 | [BinaryTree]: ./src/main/java/com/github/andavid/ds/datastructure/tree/BinaryTree.java 81 | 82 | ## 堆 83 | 84 | * 实现一个小顶堆、[大顶堆][MaxHeap]、[优先级队列][PriorityQueue] 85 | * 实现 [堆排序][HeapSort] 86 | * 利用优先级队列 [合并K个有序数组][MergeSortedArray] 87 | * 求一组动态数据集合的 [最大Top K][Topk] 88 | 89 | [MaxHeap]: ./src/main/java/com/github/andavid/ds/datastructure/heap/Heap.java 90 | [PriorityQueue]: ./src/main/java/com/github/andavid/ds/datastructure/heap/PriorityQueueUsage.java 91 | [HeapSort]: ./src/main/java/com/github/andavid/ds/datastructure/sort/HeapSort.java 92 | [MergeSortedArray]: ./src/main/java/com/github/andavid/ds/datastructure/heap/MergeSortedArray.java 93 | [Topk]: ./src/main/java/com/github/andavid/ds/datastructure/heap/Topk.java 94 | 95 | ## 图 96 | 97 | * 实现有向图、[无向图][graph]、有权图、无权图的邻接矩阵和邻接表表示方法 98 | * 实现 [图的深度优先搜索、广度优先搜索][graph] 99 | * 实现Dijkstra算法、A*算法 100 | * 实现拓扑排序的Kahn算法、DFS算法 101 | 102 | [graph]: ./src/main/java/com/github/andavid/ds/datastructure/graph/Graph.java 103 | 104 | ## 递归 105 | 106 | * 编程实现 [斐波那契数列求值][fibonacci] f(n)=f(n-1)+f(n-2) 107 | * 编程实现 [求阶乘n!][factorial] 108 | * 编程实现一组数据集合的 [全排列][permutation] 109 | 110 | [fibonacci]: ./src/main/java/com/github/andavid/ds/algorithm/recursion/Fibonacci.java 111 | [factorial]: ./src/main/java/com/github/andavid/ds/algorithm/recursion/Factorial.java 112 | [permutation]: ./src/main/java/com/github/andavid/ds/algorithm/recursion/Permutation.java 113 | 114 | ## 排序 115 | 116 | * [归并排序][MergeSort] 117 | * [快速排序][QuickSort] 118 | * [插入排序][InsertionSort] 119 | * [冒泡排序][BubbleSort] 120 | * [选择排序][SelectionSort] 121 | * [希尔排序][ShellSort] 122 | * [堆排序][HeapSort] 123 | * [桶排序][BucketSort] 124 | * [计数排序][CountingSort] 125 | * [基数排序][RadixSort] 126 | * 编程实现O(n)时间复杂度内 [找到一组数据的第K大元素][FindKthLargest] 127 | 128 | [MergeSort]: ./src/main/java/com/github/andavid/ds/algorithm/sort/MergeSort.java 129 | [QuickSort]: ./src/main/java/com/github/andavid/ds/algorithm/sort/QuickSort.java 130 | [BubbleSort]: ./src/main/java/com/github/andavid/ds/algorithm/sort/BubbleSort.java 131 | [InsertionSort]: ./src/main/java/com/github/andavid/ds/algorithm/sort/InsertionSort.java 132 | [SelectionSort]: ./src/main/java/com/github/andavid/ds/algorithm/sort/SelectionSort.java 133 | [ShellSort]: ./src/main/java/com/github/andavid/ds/algorithm/sort/ShellSort.java 134 | [HeapSort]: ./src/main/java/com/github/andavid/ds/algorithm/sort/HeapSort.java 135 | [BucketSort]: ./src/main/java/com/github/andavid/ds/algorithm/sort/BucketSort.java 136 | [CountingSort]: ./src/main/java/com/github/andavid/ds/algorithm/sort/CountingSort.java 137 | [RadixSort]: ./src/main/java/com/github/andavid/ds/algorithm/sort/RadixSort.java 138 | [FindKthLargest]: ./src/main/java/com/github/andavid/ds/algorithm/sort/FindKthLargest.java 139 | 140 | ## 二分查找 141 | 142 | * 实现一个有序数组的 [二分查找算法][binary-search] 143 | * 实现 [模糊二分查找算法][binary-search](比如大于等于给定值的第一个元素) 144 | 145 | [binary-search]: ./src/main/java/com/github/andavid/ds/algorithm/search/BinarySearch.java 146 | 147 | ## 字符串 148 | 149 | * 实现一个字符集,只包含a~z这26个英文字母的 [Trie 树][trie-tree] 150 | * 实现 [朴素的字符串匹配算法][brute-force] 151 | * 实现 [RK 字符串匹配算法][RK] 152 | * 实现 [KMP 字符串匹配算法][kmp] 153 | 154 | [trie-tree]: ./src/main/java/com/github/andavid/ds/algorithm/stringmatch/TrieTree.java 155 | [brute-force]: ./src/main/java/com/github/andavid/ds/algorithm/stringmatch/BruteForce.java 156 | [RK]: ./src/main/java/com/github/andavid/ds/algorithm/stringmatch/RabinKarp.java 157 | [kmp]: ./src/main/java/com/github/andavid/ds/algorithm/stringmatch/Kmp.java 158 | 159 | ## 贪心 160 | 161 | * [霍夫曼编码][huffman] 162 | 163 | [huffman]: ./src/main/java/com/github/andavid/ds/algorithm/greedy/Huffman.java 164 | 165 | ## 分治 166 | 167 | * 利用分治算法求一组数据的 [逆序对个数][CountInversePairs] 168 | 169 | [CountInversePairs]: ./src/main/java/com/github/andavid/ds/algorithm/divideandconquer/CountInversePairs.java 170 | 171 | ## 回溯 172 | 173 | * 利用回溯算法求解 [八皇后问题][EightQueen] 174 | * 利用回溯算法求解 [0-1 背包问题][Package] 175 | 176 | [EightQueen]: ./src/main/java/com/github/andavid/ds/algorithm/backtracking/EightQueen.java 177 | [Package]: ./src/main/java/com/github/andavid/ds/algorithm/backtracking/Package.java 178 | 179 | ## 动态规划 180 | 181 | * 0-1背包问题 182 | * 最小路径和 183 | * 编程实现莱文斯坦最短编辑距离 184 | * 编程实现查找两个字符串的最长公共子序列 185 | * 编程实现一个数据序列的最长递增子序列 186 | -------------------------------------------------------------------------------- /src/main/java/com/github/andavid/ds/datastructure/tree/BinaryTree.java: -------------------------------------------------------------------------------- 1 | package com.github.andavid.ds.datastructure.tree; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.Queue; 8 | import java.util.Stack; 9 | 10 | public class BinaryTree { 11 | 12 | public void preorder(TreeNode root) { 13 | if (root == null) { 14 | return; 15 | } 16 | 17 | System.out.print(root.val + " "); 18 | preorder(root.left); 19 | preorder(root.right); 20 | } 21 | 22 | public void inorder(TreeNode root) { 23 | if (root == null) { 24 | return; 25 | } 26 | 27 | inorder(root.left); 28 | System.out.print(root.val + " "); 29 | inorder(root.right); 30 | } 31 | 32 | public void postorder(TreeNode root) { 33 | if (root == null) { 34 | return; 35 | } 36 | 37 | postorder(root.left); 38 | postorder(root.right); 39 | System.out.print(root.val + " "); 40 | } 41 | 42 | public List preorderTraversal1(TreeNode root) { 43 | List list = new ArrayList<>(); 44 | if (root == null) { 45 | return list; 46 | } 47 | 48 | Stack stack = new Stack<>(); 49 | stack.push(root); 50 | 51 | while (!stack.empty()) { 52 | TreeNode p = stack.pop(); 53 | list.add(p.val); 54 | if (p.right != null) { 55 | stack.push(p.right); 56 | } 57 | if (p.left != null) { 58 | stack.push(p.left); 59 | } 60 | } 61 | 62 | return list; 63 | } 64 | 65 | public List preorderTraversal2(TreeNode root) { 66 | List list = new ArrayList<>(); 67 | Stack stack = new Stack<>(); 68 | TreeNode p = root; 69 | 70 | while (p != null || !stack.empty()) { 71 | while (p != null) { 72 | list.add(p.val); 73 | stack.push(p); 74 | p = p.left; 75 | } 76 | p = stack.pop(); 77 | p = p.right; 78 | } 79 | 80 | return list; 81 | } 82 | 83 | public List inorderTraversal(TreeNode root) { 84 | List list = new ArrayList<>(); 85 | Stack stack = new Stack<>(); 86 | TreeNode p = root; 87 | 88 | while (p != null || !stack.empty()) { 89 | while (p != null) { 90 | stack.push(p); 91 | p = p.left; 92 | } 93 | p = stack.pop(); 94 | list.add(p.val); 95 | p = p.right; 96 | } 97 | 98 | return list; 99 | } 100 | 101 | public List postorderTraversal1(TreeNode root) { 102 | List list = new ArrayList<>(); 103 | if (root == null) { 104 | return list; 105 | } 106 | 107 | Stack stack = new Stack<>(); 108 | stack.push(root); 109 | 110 | while (!stack.empty()) { 111 | TreeNode p = stack.pop(); 112 | if (p.left != null) { 113 | stack.push(p.left); 114 | } 115 | if (p.right != null) { 116 | stack.push(p.right); 117 | } 118 | // 逆序添加节点值 119 | list.add(0, p.val); 120 | } 121 | 122 | return list; 123 | } 124 | 125 | public List postorderTraversal2(TreeNode root) { 126 | List list = new ArrayList<>(); 127 | Stack stack = new Stack<>(); 128 | TreeNode cur = root; 129 | TreeNode last = null; // 记录上一次访问的节点 130 | 131 | while (cur != null || !stack.empty()) { 132 | // 从根节点开始, 将其所有左子节点入栈 133 | while (cur != null) { 134 | stack.push(cur); 135 | cur = cur.left; 136 | } 137 | cur = stack.peek(); 138 | if (cur.right == null || cur.right == last) { 139 | // 如果当前节点没有右孩子,或者当前节点的右孩子刚刚被访问过, 140 | // 这时应该访问当前节点 141 | list.add(cur.val); 142 | stack.pop(); 143 | last = cur; 144 | cur = null; 145 | } else { 146 | // 否则,将当前指针移到其右孩子节点上 147 | cur = cur.right; 148 | } 149 | } 150 | return list; 151 | } 152 | 153 | public List> levelOrder(TreeNode root) { 154 | List> result = new ArrayList<>(); 155 | if (root == null) { 156 | return result; 157 | } 158 | 159 | Queue queue = new LinkedList<>(); 160 | queue.offer(root); 161 | 162 | while (!queue.isEmpty()) { 163 | List level = new ArrayList<>(); 164 | int size = queue.size(); 165 | for (int i = 0; i < size; i++) { 166 | TreeNode node = queue.poll(); 167 | level.add(node.val); 168 | if (node.left != null) { 169 | queue.offer(node.left); 170 | } 171 | if (node.right != null) { 172 | queue.offer(node.right); 173 | } 174 | } 175 | result.add(level); 176 | } 177 | 178 | return result; 179 | } 180 | 181 | /** 182 | * 树的最大深度 183 | */ 184 | public int maxDepth(TreeNode root) { 185 | if (root == null) { 186 | return 0; 187 | } 188 | return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1; 189 | } 190 | 191 | private boolean isBalanced = true; 192 | 193 | /** 194 | * 是否是高度平衡的二叉树 195 | */ 196 | public boolean isBalanced(TreeNode root) { 197 | getDepth(root); 198 | return isBalanced; 199 | } 200 | 201 | public int getDepth(TreeNode root) { 202 | if (root == null) { 203 | return 0; 204 | } 205 | int left = getDepth(root.left); 206 | int right = getDepth(root.right); 207 | if (Math.abs(left - right) > 1) { 208 | isBalanced = false; 209 | } 210 | return left > right ? left + 1 : right + 1; 211 | } 212 | 213 | /** 214 | * 是否是镜像对称的二叉树 215 | */ 216 | public boolean isSymmetric(TreeNode root) { 217 | if (root == null) { 218 | return true; 219 | } 220 | return isSym(root.left, root.right); 221 | } 222 | 223 | public boolean isSym(TreeNode r1, TreeNode r2) { 224 | if (r1 == null && r2 == null) { 225 | return true; 226 | } 227 | if (r1 == null || r2 == null) { 228 | return false; 229 | } 230 | return r1.val == r2.val && isSym(r1.left, r2.right) && isSym(r1.right, r2.left); 231 | } 232 | 233 | // Encodes a tree to a single string. 234 | public String serialize(TreeNode root) { 235 | if (root == null) { 236 | return "[]"; 237 | } 238 | 239 | List list = new ArrayList<>(); 240 | Queue queue = new LinkedList<>(); 241 | queue.offer(root); 242 | 243 | while (!queue.isEmpty()) { 244 | TreeNode node = queue.poll(); 245 | 246 | if (node == null) { 247 | list.add("null"); 248 | continue; 249 | } else { 250 | list.add("" + node.val); 251 | } 252 | 253 | if (node.left != null) { 254 | queue.offer(node.left); 255 | } else { 256 | queue.offer(null); 257 | } 258 | 259 | if (node.right != null) { 260 | queue.offer(node.right); 261 | } else { 262 | queue.offer(null); 263 | } 264 | } 265 | 266 | // 移除末尾的 null 267 | for (int i = list.size() - 1; i >= 0; i--) { 268 | if (list.get(i).equals("null")) { 269 | list.remove(i); 270 | } else { 271 | break; 272 | } 273 | } 274 | 275 | StringBuilder sb = new StringBuilder(); 276 | sb.append('['); 277 | for (int i = 0; i < list.size(); i++) { 278 | sb.append(list.get(i)); 279 | if (i == list.size() - 1) { 280 | sb.append("]"); 281 | } else { 282 | sb.append(","); 283 | } 284 | } 285 | 286 | return sb.toString(); 287 | } 288 | 289 | // Decodes your encoded data to tree. 290 | public TreeNode deserialize(String data) { 291 | if (data == null || data.equals("[]") || data.length() <= 2) { 292 | return null; 293 | } 294 | 295 | String[] strArray = data.substring(1, data.length() - 1).split(","); 296 | Queue list = new LinkedList<>(); 297 | list.addAll(Arrays.asList(strArray)); 298 | 299 | Queue queue = new LinkedList<>(); 300 | TreeNode root = new TreeNode(Integer.valueOf(list.poll())); 301 | queue.offer(root); 302 | 303 | while (!queue.isEmpty()) { 304 | TreeNode node = queue.poll(); 305 | 306 | String leftVal = list.poll(); 307 | if (leftVal == null || leftVal.equals("null")) { 308 | node.left = null; 309 | } else { 310 | TreeNode leftNode = new TreeNode(Integer.valueOf(leftVal)); 311 | node.left = leftNode; 312 | queue.offer(leftNode); 313 | } 314 | 315 | String rightVal = list.poll(); 316 | if (rightVal == null || rightVal.equals("null")) { 317 | node.right = null; 318 | } else { 319 | TreeNode rightNode = new TreeNode(Integer.valueOf(rightVal)); 320 | node.right = rightNode; 321 | queue.offer(rightNode); 322 | } 323 | } 324 | 325 | return root; 326 | } 327 | 328 | } --------------------------------------------------------------------------------