├── .gitattributes ├── README.md ├── pom.xml └── src ├── main └── java │ └── org │ └── buptdavid │ └── datastructure │ ├── Node.java │ ├── array │ ├── CompressStr.java │ └── SetZeroMatrix.java │ ├── designPatterns │ └── singleton │ │ ├── Singleton.java │ │ ├── classic │ │ └── Singleton.java │ │ ├── staticInnerClass │ │ └── Singleton.java │ │ ├── statics │ │ └── Singleton.java │ │ ├── threadSafety │ │ └── Singleton.java │ │ └── threadSafetyVolatile │ │ └── Singleton.java │ ├── graph │ ├── DirectedGraphPathCheck.java │ ├── GraphNode.java │ └── GraphSearch.java │ ├── io │ ├── aio │ │ ├── AcceptCompletionHandler.java │ │ ├── AsyncTimeClientHandler.java │ │ ├── AsyncTimeServerHandler.java │ │ ├── ReadCompletionHandler.java │ │ ├── TimeClient.java │ │ └── TimeServer.java │ ├── bio │ │ ├── TimeClient.java │ │ ├── TimeClientHandler.java │ │ ├── TimeServer.java │ │ └── TimeServerHandler.java │ ├── fakenio │ │ ├── TimeServer.java │ │ └── TimeServerHandlerExecutePool.java │ ├── netty │ │ ├── serializable │ │ │ ├── SubReqClient.java │ │ │ ├── SubReqClientHandler.java │ │ │ ├── SubReqServer.java │ │ │ ├── SubReqServerHandler.java │ │ │ ├── SubscribeReq.java │ │ │ └── SubscribeResp.java │ │ └── tcpacketsplicing │ │ │ ├── TimeClient.java │ │ │ ├── TimeClientHandler.java │ │ │ ├── TimeServer.java │ │ │ └── TimeServerHandler.java │ └── nio │ │ ├── MultiplexerTimeServer.java │ │ ├── TimeClient.java │ │ ├── TimeClientHandle.java │ │ └── TimeServer.java │ ├── linkedlist │ ├── DeleteDups.java │ ├── LinkedListLoop.java │ └── SortWithValue.java │ ├── queue │ ├── IQueue.java │ ├── Queue.java │ └── QueueWith2Stack.java │ ├── search │ └── BinarySearch.java │ ├── sort │ ├── BubbleSort.java │ ├── ISort.java │ ├── InsertOptimizeSort.java │ ├── InsertSort.java │ ├── MergeSort.java │ ├── QuickSort.java │ └── SelectionSort.java │ ├── stack │ ├── Hannotower.java │ ├── IStack.java │ ├── SetOfStacks.java │ ├── Stack.java │ ├── StackCapacity.java │ └── StackWithMin.java │ ├── string │ └── StringEqual.java │ ├── thread │ ├── ChopStickLocked.java │ ├── ChopStickUnLocked.java │ ├── ExtendThread.java │ ├── ExtendThreadRun.java │ ├── LockedATM.java │ ├── LockedATMThread.java │ ├── PhilosopherLocked.java │ ├── PhilosopherLockedEat.java │ ├── PhilosopherUnLocked.java │ ├── PhilosopherUnLockedEat.java │ ├── RunableThread.java │ ├── SynchronizedObject.java │ ├── SynchronizedThread.java │ ├── lockcondition │ │ ├── Bank.java │ │ ├── SynchBankTest.java │ │ └── TransferRunnable.java │ ├── threadpool │ │ └── ThreadPoolTest.java │ └── usesynchronized │ │ ├── Bank.java │ │ ├── SynchBankTest2.java │ │ └── TransferRunnable.java │ └── tree │ ├── BinarySearchTree.java │ ├── CheckBalanceTree.java │ ├── CommonAncestorSearch.java │ ├── MinBinaryTree.java │ ├── TreeNode.java │ └── TreeSearch.java └── test └── java └── org └── buptdavid └── datastructure ├── graph ├── DirectedGraphPathCheckTest.java └── GraphSearchTest.java ├── linkedlist └── LinkedListLoopTest.java ├── queue └── QueueTest.java ├── search └── BinarySearchTest.java ├── sort └── SortTest.java ├── stack └── StackTest.java └── tree ├── BinarySearchTreeTest.java ├── CheckBalanceTreeTest.java ├── CommonAncestorSearchTest.java └── TreeSearchTest.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # datastructure 2 | 用Java实现的数据结构暨算法,同时对其进行了测试 3 | 4 | 准备工作 5 | ------ 6 | 1 为你的系统安装Maven 7 | 2 Setup环境 请在终端命令行上运行 “mvn clean install -DskipTests”, 然后再运行 “mvn eclipse:eclipse”,将项目Import到你的Eclipse中 8 | 9 | 目录 10 | ------ 11 | 1. 字符串 [字符串压缩](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/array/CompressStr.java) [矩阵](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/array/SetZeroMatrix.java) [String的秘密](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/string/StringEqual.java) 12 | 2. 链表 [删除重复元素](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/linkedlist/DeleteDups.java) [链表排序](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/linkedlist/SortWithValue.java) [链表环儿](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/linkedlist/LinkedListLoop.java) [链表环儿测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/linkedlist/LinkedListLoopTest.java) 13 | 3. 查找 [二分查找](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/search/BinarySearch.java) [二分查找测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/search/BinarySearchTest.java) 14 | 4. 排序 [冒泡排序](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/sort/BubbleSort.java) [归并排序](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/sort/MergeSort.java) [快速排序](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/sort/QuickSort.java) [选择排序](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/sort/SelectionSort.java) [插入排序](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/sort/InsertSort.java) [插入优化排序](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/sort/InsertOptimizeSort.java) [排序全测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/sort/SortTest.java) 15 | 5. 栈 [栈的实现](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/stack/Stack.java) [记录存储容量和索引的栈](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/stack/StackCapacity.java) [能获取最小值的栈](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/stack/StackWithMin.java) [汉诺塔](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/stack/Hannotower.java) [栈全测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/stack/StackTest.java) 16 | 6. 队列 [队列实现](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/queue/Queue.java) [两栈实现队列](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/queue/QueueWith2Stack.java) [队列全测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/queue/QueueTest.java) 17 | 7. 树 [树的前序,中序,后续遍历搜索](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/tree/TreeSearch.java) [遍历搜索测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/tree/TreeSearchTest.java) [二叉树判断](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/tree/BinarySearchTree.java) [二叉树判断测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/tree/BinarySearchTreeTest.java) [平衡树判断](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/tree/CheckBalanceTree.java) [平衡树判断测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/tree/CheckBalanceTreeTest.java) [查找两节点共同祖先](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/tree/CommonAncestorSearch.java) [共同祖先测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/tree/CommonAncestorSearchTest.java) [数组变二叉查找树](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/tree/MinBinaryTree.java) 18 | 8. 图 [图的广度优先和深度优先搜索](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/graph/GraphSearch.java) [广度优先和深度优先搜索测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/graph/GraphSearchTest.java) [有向图路径判断](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/graph/DirectedGraphPathCheck.java) [有向图路径判断测试](https://github.com/buptdavid/datastructure/blob/master/src/test/java/org/buptdavid/datastructure/graph/DirectedGraphPathCheckTest.java) 19 | 9. 多线程 [线程实现之继承Thread](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/ExtendThread.java) [线程实现之实现Runnable](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/RunableThread.java) [实现锁的ATM取款与存款](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/LockedATM.java) [哲学家就餐问题之会死锁的哲学家](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/PhilosopherLocked.java) [死锁哲学家测试](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/PhilosopherLockedEat.java) [哲学家就餐问题之不会死锁的哲学家](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/PhilosopherUnLocked.java) [不死锁哲学家测试](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/PhilosopherUnLockedEat.java) [同步对象](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/SynchronizedObject.java) [同步线程](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/SynchronizedThread.java) [Lock Condition转账](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/lockcondition/SynchBankTest.java) [synchronized wait转账](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/usesynchronized/SynchBankTest2.java) [线程池](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/thread/threadpool/ThreadPoolTest.java) 20 | 10. IO [BIO服务端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/bio/TimeServer.java) [BIO客户端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/bio/TimeClient.java) [伪NIO服务端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/fakenio/TimeServer.java) [NIO服务端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/nio/TimeServer.java) [NIO客户端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/nio/TimeClient.java) [AIO服务端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/aio/TimeServer.java) [AIO客户端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/aio/TimeClient.java) 21 | 11. Netty [Netty粘包拆包服务端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/netty/tcpacketsplicing/TimeServer.java) [Netty粘包拆包客户端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/netty/tcpacketsplicing/TimeClient.java) [Netty序列化服务端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/netty/serializable/SubReqServer.java) [Netty序列化客户端](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/io/netty/serializable/SubReqClient.java) 22 | 12. 设计模式 [五种单例模式](https://github.com/buptdavid/datastructure/blob/master/src/main/java/org/buptdavid/datastructure/designPatterns/singleton/Singleton.java) 23 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.buptdavid 6 | datastructure 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | datastructure 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | junit 20 | junit 21 | 4.11 22 | 23 | 24 | io.netty 25 | netty-all 26 | 5.0.0.Alpha2 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/Node.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure; 2 | 3 | /** 4 | * 链表的节点 5 | * @author weijielu 6 | */ 7 | public class Node { 8 | public Node next; 9 | public T data; 10 | 11 | public Node(T _data){ 12 | data = _data; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/array/CompressStr.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.array; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * 压缩字符串,如果压缩后的字符串长度大于等于原字符串长度,则返回原字符串 9 | * @author weijielu 10 | * 11 | */ 12 | public class CompressStr { 13 | public static String compress(String s){ 14 | StringBuffer sb = new StringBuffer(); 15 | 16 | int i,j; 17 | for(i = 0; i < s.length(); i++){ 18 | j = i + 1; 19 | while(j < s.length() && s.charAt(j) == s.charAt(i)){ 20 | j++; 21 | } 22 | 23 | sb.append(s.charAt(i)); 24 | sb.append(j - i); 25 | 26 | i = j - 1; 27 | } 28 | 29 | String sbString = sb.toString(); 30 | return sbString.length() <= s.length()? sbString.toString() : s; 31 | } 32 | 33 | @Test 34 | public void test(){ 35 | String s1 = "aabcccaaaa"; 36 | String expectedS1 = "a2b1c3a4"; 37 | 38 | String s2 = "aaaaaaaaaaaa"; 39 | String expectedS2 = "a12"; 40 | 41 | String s3 = "abcdefg"; 42 | String expectedS3 = "abcdefg"; 43 | 44 | String s4 = "aabbccdd"; 45 | String expectedS4 = "aabbccdd"; 46 | 47 | Assert.assertEquals(expectedS1, compress(s1)); 48 | Assert.assertEquals(expectedS2, compress(s2)); 49 | Assert.assertEquals(expectedS3, compress(s3)); 50 | Assert.assertEquals(expectedS4, s4); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/array/SetZeroMatrix.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.array; 2 | 3 | 4 | /** 5 | * 在矩阵中,如果某个位置为0,怎将其所在的行和列都置为0 6 | * @author weijielu 7 | * 8 | */ 9 | public class SetZeroMatrix { 10 | 11 | public static void zeroGood(int[][] matrix){ 12 | boolean row[] = new boolean[matrix.length]; 13 | boolean column[] = new boolean[matrix[0].length]; 14 | 15 | int i, j; 16 | for(i = 0 ; i < matrix.length; i++){ 17 | for(j = 0; j < matrix[i].length; j++){ 18 | if(matrix[i][j] == 0){ 19 | row[i] = true; 20 | column[j] = true; 21 | } 22 | } 23 | } 24 | 25 | for(i = 0; i < matrix.length; i++){ 26 | for(j = 0; j < matrix[i].length; j++){ 27 | if(row[i] || column[j]){ 28 | matrix[i][j] = 0; 29 | } 30 | } 31 | } 32 | } 33 | 34 | /** 35 | * @param args 36 | */ 37 | public static void main(String[] args) { 38 | int[][] matrix = { { 1, 2, 3, 4 }, { 2, 3, 4, 5 }, { 6, 5, 3, 4 }, 39 | { 8, 6, 9, 0 }, { 4, 7, 0, 1 } }; 40 | 41 | for (int i = 0; i < matrix.length; i++) { 42 | String matrixStr = ""; 43 | for (int j = 0; j < matrix[i].length; j++) { 44 | matrixStr += matrix[i][j] + " "; 45 | } 46 | System.out.println(matrixStr); 47 | } 48 | 49 | System.out.println("Set Zero"); 50 | zeroGood(matrix); 51 | 52 | for (int i = 0; i < matrix.length; i++) { 53 | String matrixStr = ""; 54 | for (int j = 0; j < matrix[i].length; j++) { 55 | matrixStr += matrix[i][j] + " "; 56 | } 57 | System.out.println(matrixStr); 58 | } 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/designPatterns/singleton/Singleton.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.designPatterns.singleton; 2 | 3 | /** 4 | * 五种单例模式的实现 5 | * @author weijielu 6 | * 7 | */ 8 | public class Singleton { 9 | 10 | /** 11 | * @param args 12 | */ 13 | public static void main(String[] args) { 14 | // 静态变量初始化实现线程安全的单例模式 15 | org.buptdavid.datastructure.designPatterns.singleton.statics.Singleton instance1 = 16 | org.buptdavid.datastructure.designPatterns.singleton.statics.Singleton.getInstance(); 17 | 18 | // 静态内部类实现的线程安全的单例模式 19 | org.buptdavid.datastructure.designPatterns.singleton.staticInnerClass.Singleton instance2 = 20 | org.buptdavid.datastructure.designPatterns.singleton.staticInnerClass.Singleton.getInstance(); 21 | 22 | // 经典的非线程安全单例模式实现类 23 | org.buptdavid.datastructure.designPatterns.singleton.classic.Singleton instance3 = 24 | org.buptdavid.datastructure.designPatterns.singleton.classic.Singleton.getInstance(); 25 | 26 | // 线程安全的单例模式实现类 27 | org.buptdavid.datastructure.designPatterns.singleton.threadSafety.Singleton instance4 = 28 | org.buptdavid.datastructure.designPatterns.singleton.threadSafety.Singleton.getInstance(); 29 | 30 | // 高效的线程安全的单例模式实现类 31 | org.buptdavid.datastructure.designPatterns.singleton.threadSafetyVolatile.Singleton instance5 = 32 | org.buptdavid.datastructure.designPatterns.singleton.threadSafetyVolatile.Singleton.getInstance(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/designPatterns/singleton/classic/Singleton.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.designPatterns.singleton.classic; 2 | 3 | /** 4 | * 经典的非线程安全单例模式实现类 5 | * @author weijielu 6 | * 7 | */ 8 | public class Singleton { 9 | private static Singleton instance; 10 | 11 | private Singleton(){ } 12 | 13 | public static Singleton getInstance(){ 14 | if(instance == null){ 15 | instance = new Singleton(); 16 | } 17 | return instance; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/designPatterns/singleton/staticInnerClass/Singleton.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.designPatterns.singleton.staticInnerClass; 2 | 3 | /** 4 | * 静态内部类实现的线程安全的单例模式
5 | * 由于内部静态类只会被加载一次,故是线程安全的 6 | * @author weijielu 7 | * 8 | */ 9 | public class Singleton { 10 | 11 | private Singleton(){} 12 | 13 | private static class SingleHolder{ 14 | static Singleton instance = new Singleton(); 15 | } 16 | 17 | public static Singleton getInstance(){ 18 | return SingleHolder.instance; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/designPatterns/singleton/statics/Singleton.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.designPatterns.singleton.statics; 2 | 3 | /** 4 | * 静态变量初始化实现线程安全的单例模式
5 | * static变量 instance 是在类被加载时初始化并仅被初始化一次,这样就可以保证只有一个instance被初始化 6 | * @author weijielu 7 | * 8 | */ 9 | public class Singleton { 10 | private static Singleton instance = new Singleton(); 11 | 12 | private Singleton(){} 13 | 14 | public static Singleton getInstance(){ 15 | return instance; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/designPatterns/singleton/threadSafety/Singleton.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.designPatterns.singleton.threadSafety; 2 | 3 | /** 4 | * 线程安全的单例模式实现类 5 | * @author weijielu 6 | * 7 | */ 8 | public class Singleton { 9 | private static Singleton instance; 10 | 11 | private Singleton(){} 12 | 13 | public static synchronized Singleton getInstance(){ 14 | if(instance == null){ 15 | instance = new Singleton(); 16 | } 17 | 18 | return instance; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/designPatterns/singleton/threadSafetyVolatile/Singleton.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.designPatterns.singleton.threadSafetyVolatile; 2 | 3 | /** 4 | * 高效的线程安全的单例模式实现类 5 | * @author weijielu 6 | * 7 | */ 8 | public class Singleton { 9 | private static volatile Singleton instance; 10 | 11 | private Singleton(){} 12 | 13 | public static Singleton getInstance(){ 14 | if(instance == null){ 15 | synchronized(Singleton.class){ 16 | if(instance == null){ 17 | instance = new Singleton(); 18 | } 19 | } 20 | } 21 | 22 | return instance; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/graph/DirectedGraphPathCheck.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.graph; 2 | 3 | import java.util.List; 4 | 5 | import org.buptdavid.datastructure.queue.IQueue; 6 | import org.buptdavid.datastructure.queue.Queue; 7 | 8 | /** 9 | * 给出有向图的两个节点判断两者之间是否有一路径 10 | * @author weijielu 11 | * @see GraphNode 12 | * @see DirectedGraphPathCheck 13 | */ 14 | public class DirectedGraphPathCheck { 15 | 16 | /** 17 | * 利用深度优先搜索进行路径判断p - q 之间是否有路径 18 | * @param p 19 | * @param q 20 | * @return 21 | */ 22 | public static boolean pathCheckDFS(GraphNode p, GraphNode q){ 23 | boolean isFound =false; 24 | 25 | p.restoreVisited(); 26 | isFound |= pathOrderCheckDFS(p, q); 27 | 28 | q.restoreVisited(); 29 | isFound |= pathOrderCheckDFS(q, p); 30 | 31 | return isFound; 32 | } 33 | 34 | /** 35 | * 利用深度优先搜索进行路径判断 p -> q 是否有路径 36 | * @return 37 | */ 38 | private static boolean pathOrderCheckDFS(GraphNode p, GraphNode q){ 39 | if(p.equals(q)){ 40 | return true; 41 | } 42 | 43 | boolean isFound = false; 44 | List> pNeighborList = p.neighborList; 45 | for(int i = 0; i < pNeighborList.size(); i++){ 46 | GraphNode neighbor = pNeighborList.get(i); 47 | if(!neighbor.visited){ 48 | neighbor.visited = true; 49 | if(neighbor.equals(q)){ 50 | return true; 51 | } 52 | 53 | isFound = isFound || pathOrderCheckDFS(neighbor, q); 54 | } 55 | } 56 | 57 | return isFound; 58 | } 59 | 60 | /** 61 | * 利用广度优先搜索进行路径判断 p - q 之间是否有路径 62 | * @param p 63 | * @param q 64 | * @return 65 | */ 66 | public static boolean pathCheckBFS(GraphNode p, GraphNode q){ 67 | boolean isFound =false; 68 | 69 | p.restoreVisited(); 70 | isFound |= pathOrderCheckBFS(p, q); 71 | 72 | q.restoreVisited(); 73 | isFound |= pathOrderCheckBFS(q, p); 74 | 75 | return isFound; 76 | } 77 | 78 | /** 79 | * 利用广度优先搜索进行路径判断 p -> q 是否有路径 80 | * @return 81 | */ 82 | private static boolean pathOrderCheckBFS(GraphNode p, GraphNode q){ 83 | IQueue> queue = new Queue> (); 84 | 85 | if(!p.visited && p.equals(q)){ 86 | return true; 87 | } 88 | 89 | p.visited = true; 90 | queue.enqueue(p); 91 | 92 | while(!queue.isEmpty()){ 93 | List> neighbors = queue.dequeue().neighborList; 94 | for(int i = 0; i < neighbors.size(); i++){ 95 | GraphNode neighbor = neighbors.get(i); 96 | 97 | if(!neighbor.visited && neighbor.equals(q)){ 98 | return true; 99 | } 100 | neighbor.visited = true; 101 | queue.enqueue(neighbor); 102 | } 103 | } 104 | 105 | return false; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/graph/GraphNode.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.graph; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 图的节点 8 | * @author weijielu 9 | */ 10 | public class GraphNode { 11 | T data; 12 | List> neighborList; 13 | boolean visited; 14 | 15 | public GraphNode(T data){ 16 | this.data = data; 17 | neighborList = new ArrayList>(); 18 | visited = false; 19 | } 20 | 21 | public boolean equals(GraphNode node){ 22 | return this.data.equals(node.data); 23 | } 24 | 25 | /** 26 | * 还原图中所有节点为未访问 27 | */ 28 | public void restoreVisited(){ 29 | restoreVisited(this); 30 | } 31 | 32 | /** 33 | * 还原node的图所有节点为未访问 34 | * @param node 35 | */ 36 | private void restoreVisited(GraphNode node){ 37 | if(node.visited){ 38 | node.visited = false; 39 | } 40 | 41 | List> neighbors = node.neighborList; 42 | for(int i = 0; i < neighbors.size(); i++){ 43 | restoreVisited(neighbors.get(i)); 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/graph/GraphSearch.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.graph; 2 | 3 | import org.buptdavid.datastructure.queue.IQueue; 4 | import org.buptdavid.datastructure.queue.Queue; 5 | 6 | /** 7 | * 图的广度优先搜索和深度优先搜索实现 8 | * 9 | * @author weijielu 10 | * @see GraphNode 11 | * @see GraphSearchTest 12 | */ 13 | public class GraphSearch { 14 | 15 | public StringBuffer searchPathDFS = new StringBuffer(); 16 | public StringBuffer searchPathBFS = new StringBuffer(); 17 | 18 | /** 19 | * 深度优先搜索实现 20 | * 21 | * @param root 22 | */ 23 | public void searchDFS(GraphNode root) { 24 | if (root == null) { 25 | return; 26 | } 27 | 28 | // visited root 29 | if (searchPathDFS.length() > 0) { 30 | searchPathDFS.append("->"); 31 | } 32 | searchPathDFS.append(root.data.toString()); 33 | root.visited = true; 34 | 35 | for (GraphNode node : root.neighborList) { 36 | if (!node.visited) { 37 | searchDFS(node); 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * 广度优先搜索实现,使用队列 44 | * 45 | * @param root 46 | */ 47 | public void searchBFS(GraphNode root) { 48 | IQueue> queue = new Queue>(); 49 | 50 | // visited root 51 | if (searchPathBFS.length() > 0) { 52 | searchPathBFS.append("->"); 53 | } 54 | searchPathBFS.append(root.data.toString()); 55 | root.visited = true; 56 | 57 | // 加到队列队尾 58 | queue.enqueue(root); 59 | 60 | while(!queue.isEmpty()){ 61 | GraphNode r = queue.dequeue(); 62 | for (GraphNode node : r.neighborList) { 63 | if (!node.visited) { 64 | searchPathBFS.append("->"); 65 | searchPathBFS.append(node.data.toString()); 66 | node.visited = true; 67 | 68 | queue.enqueue(node); 69 | } 70 | } 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/aio/AcceptCompletionHandler.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.aio; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.channels.AsynchronousSocketChannel; 5 | import java.nio.channels.CompletionHandler; 6 | 7 | /** 8 | * AIO时间服务器服务端 AcceptCompletionHandler 9 | * @author weijielu 10 | * 11 | * @param 12 | * @param 13 | */ 14 | public class AcceptCompletionHandler implements CompletionHandler { 15 | 16 | @Override 17 | public void completed(AsynchronousSocketChannel result, AsyncTimeServerHandler attachment) { 18 | /** 19 | * 再次调用AsyncTimeServerHandler.asynchronousServerSocketChannel的accept方法 20 | * 当我们调用AsynchronousServerSocketChannel的accept方法后,如果有新的客户端连接接入,系统将回调我们传入的CompletionHandler 21 | * 实例的completed方法,表示新的客户端已经接入成功,因为一个AsynchronousServerSocketChannel可以接受成千上万个客户端, 22 | * 所以我们需要继续调用它的accept方法,接受其他的客户端连接,最终形成一个循环。每当接受一个客户读取成功之后, 23 | * 再异步接受新的客户端连接 24 | */ 25 | attachment.asynchronousServerSocketChannel.accept(attachment, this); 26 | 27 | ByteBuffer buffer = ByteBuffer.allocate(1024); 28 | /** 29 | * 异步读取操作 30 | * @param buffer 接受缓冲区,用于从异步Channel中读取数据包 31 | * @para buffer 异步Channel携带的附件,通知回调的时候作为入参使用 32 | * @para ReadCompletionHandler 接受通知回调的业务handler 33 | */ 34 | result.read(buffer, buffer, new ReadCompletionHandler(result)); 35 | } 36 | 37 | @Override 38 | public void failed(Throwable exc, AsyncTimeServerHandler attachment) { 39 | exc.printStackTrace(); 40 | attachment.latch.countDown(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/aio/AsyncTimeClientHandler.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.aio; 2 | 3 | import java.io.IOException; 4 | import java.io.UnsupportedEncodingException; 5 | import java.net.InetSocketAddress; 6 | import java.nio.ByteBuffer; 7 | import java.nio.channels.AsynchronousSocketChannel; 8 | import java.nio.channels.CompletionHandler; 9 | import java.util.concurrent.CountDownLatch; 10 | 11 | /** 12 | * AIO时间服务器客户端 AsyncTimeClientHandler 13 | * @author weijielu 14 | * 15 | */ 16 | public class AsyncTimeClientHandler implements CompletionHandler, Runnable { 17 | 18 | private AsynchronousSocketChannel client; 19 | private String host; 20 | private int port; 21 | private CountDownLatch latch; 22 | 23 | public AsyncTimeClientHandler(String host, int port){ 24 | this.host = host; 25 | this.port = port; 26 | try{ 27 | client = AsynchronousSocketChannel.open(); 28 | }catch(IOException e){ 29 | e.printStackTrace(); 30 | } 31 | } 32 | 33 | @Override 34 | public void run() { 35 | latch = new CountDownLatch(1); 36 | 37 | /** 38 | * 发起异步操作 39 | * @param attachment AsynchronousSocketChannel的附件,用于回调通知时作为入参被传递,调用者可以自定义 40 | * @param handler 异步操作回调通知接口,由调用者实现 41 | */ 42 | client.connect(new InetSocketAddress(host, port), this, this); 43 | 44 | try{ 45 | latch.await(); 46 | }catch(InterruptedException e1){ 47 | e1.printStackTrace(); 48 | } 49 | 50 | try{ 51 | client.close(); 52 | }catch(IOException e){ 53 | e.printStackTrace(); 54 | } 55 | } 56 | 57 | @Override 58 | public void completed(Void result, AsyncTimeClientHandler attachment) { 59 | byte[] req = "QUERY TIME ORDER".getBytes(); 60 | ByteBuffer writeBuffer = ByteBuffer.allocate(req.length); 61 | writeBuffer.put(req); 62 | writeBuffer.flip(); 63 | client.write(writeBuffer, writeBuffer, new CompletionHandler(){ 64 | 65 | @Override 66 | public void completed(Integer result, ByteBuffer buffer) { 67 | if(buffer.hasRemaining()){ 68 | // 如果发送缓冲区仍有尚未发送的字节,将继续异步发送 69 | client.write(buffer, buffer, this); 70 | }else{ 71 | // 如果已经发送完成,则执行异步读取操作 72 | ByteBuffer readBuffer = ByteBuffer.allocate(1024); 73 | client.read(readBuffer, readBuffer, new CompletionHandler(){ 74 | 75 | @Override 76 | public void completed(Integer result, ByteBuffer buffer) { 77 | buffer.flip(); 78 | byte[] bytes = new byte[buffer.remaining()]; 79 | buffer.get(bytes); 80 | 81 | String body; 82 | try{ 83 | body = new String(bytes, "UTF-8"); 84 | System.out.println("NOW is : " + body); 85 | }catch(UnsupportedEncodingException e){ 86 | e.printStackTrace(); 87 | } 88 | } 89 | 90 | @Override 91 | public void failed(Throwable exc, ByteBuffer buffer) { 92 | try{ 93 | client.close(); 94 | latch.countDown(); 95 | }catch(IOException e){ 96 | // ingnore 97 | } 98 | } 99 | 100 | }); 101 | } 102 | } 103 | 104 | @Override 105 | public void failed(Throwable exc, ByteBuffer attachment) { 106 | try{ 107 | client.close(); 108 | latch.countDown(); 109 | }catch(IOException e){ 110 | // ingnore 111 | } 112 | } 113 | 114 | }); 115 | } 116 | 117 | @Override 118 | public void failed(Throwable exc, AsyncTimeClientHandler attachment) { 119 | exc.printStackTrace(); 120 | 121 | try{ 122 | client.close(); 123 | latch.countDown(); 124 | }catch(IOException e){ 125 | // ingnore 126 | } 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/aio/AsyncTimeServerHandler.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.aio; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.nio.channels.AsynchronousServerSocketChannel; 6 | import java.util.concurrent.CountDownLatch; 7 | 8 | /** 9 | * AIO时间服务器服务端 AsyncTimeServerHandler 10 | * @author weijielu 11 | * 12 | */ 13 | public class AsyncTimeServerHandler implements Runnable { 14 | 15 | private int port; 16 | 17 | CountDownLatch latch; 18 | AsynchronousServerSocketChannel asynchronousServerSocketChannel; 19 | 20 | public AsyncTimeServerHandler(int port){ 21 | this.port = port; 22 | try { 23 | // 创建异步服务器通道,绑定监听端口 24 | asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open(); 25 | asynchronousServerSocketChannel.bind(new InetSocketAddress(port)); 26 | System.out.println("The time server is start in port : " + port); 27 | } catch (IOException e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | 32 | @Override 33 | public void run() { 34 | // 初始化CountDownLatch对象,作用是在完成一组正在执行的操作之前,允许当前的线程一直阻塞 35 | latch = new CountDownLatch(1); 36 | doAccept(); 37 | 38 | try { 39 | latch.await(); 40 | } catch (InterruptedException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | 45 | public void doAccept(){ 46 | // 接受客户端的连接,由于是异步操作,可以传递一个CompletionHandler类型的实例 47 | // 来接受accept操作成功的通知消息 48 | asynchronousServerSocketChannel.accept(this, new AcceptCompletionHandler()); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/aio/ReadCompletionHandler.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.aio; 2 | 3 | import java.io.IOException; 4 | import java.io.UnsupportedEncodingException; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.AsynchronousSocketChannel; 7 | import java.nio.channels.CompletionHandler; 8 | 9 | /** 10 | * AIO时间服务器服务端 ReadCompletionHandler 11 | * @author weijielu 12 | * 13 | */ 14 | public class ReadCompletionHandler implements CompletionHandler { 15 | 16 | private AsynchronousSocketChannel channel; 17 | 18 | public ReadCompletionHandler(AsynchronousSocketChannel channel){ 19 | if(this.channel == null){ 20 | this.channel = channel; 21 | } 22 | } 23 | 24 | @Override 25 | public void completed(Integer result, ByteBuffer attachment) { 26 | attachment.flip(); 27 | byte[] body = new byte[attachment.remaining()]; 28 | attachment.get(body); 29 | 30 | try{ 31 | String req = new String(body, "UTF-8"); 32 | System.out.println("The time server receive order ; " + req); 33 | String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(req) ? new java.util.Date(System.currentTimeMillis()).toString() : "BAD ORDER"; 34 | doWrite(currentTime); 35 | } catch (UnsupportedEncodingException e){ 36 | e.printStackTrace(); 37 | } 38 | } 39 | 40 | private void doWrite(String currentTime){ 41 | if(currentTime != null && currentTime.trim().length() > 0){ 42 | byte[] bytes = currentTime.getBytes(); 43 | ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length); 44 | writeBuffer.put(bytes); 45 | writeBuffer.flip(); 46 | 47 | channel.write(writeBuffer, writeBuffer, new CompletionHandler(){ 48 | 49 | @Override 50 | public void completed(Integer result, ByteBuffer buffer) { 51 | // 如果没有发送完成,继续发送 52 | if(buffer.hasRemaining()){ 53 | channel.write(buffer, buffer, this); 54 | } 55 | } 56 | 57 | @Override 58 | public void failed(Throwable exc, ByteBuffer attachment) { 59 | try{ 60 | channel.close(); 61 | } catch (IOException e){ 62 | // ingnore 63 | } 64 | } 65 | 66 | }); 67 | } 68 | } 69 | 70 | @Override 71 | public void failed(Throwable exc, ByteBuffer attachment) { 72 | try{ 73 | this.channel.close(); 74 | } catch (IOException e){ 75 | e.printStackTrace(); 76 | 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/aio/TimeClient.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.aio; 2 | 3 | /** 4 | * AIO时间服务器客户端 TimeClient 5 | * @author weijielu 6 | * 7 | */ 8 | public class TimeClient { 9 | 10 | /** 11 | * @param args 12 | */ 13 | public static void main(String[] args) { 14 | int port = 8080; 15 | if(args != null && args.length > 0){ 16 | try{ 17 | port = Integer.valueOf(args[0]); 18 | }catch (NumberFormatException e){ 19 | 20 | } 21 | } 22 | 23 | int i = 0; 24 | while(++i < 1000){ 25 | new Thread(new AsyncTimeClientHandler("127.0.0.1", port), "AIO-AsyncTimeClientHandler-" + i).start(); 26 | } 27 | 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/aio/TimeServer.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.aio; 2 | 3 | /** 4 | * AIO时间服务器服务端 TimeServer 5 | * @author weijielu 6 | * 7 | */ 8 | public class TimeServer { 9 | 10 | /** 11 | * @param args 12 | */ 13 | public static void main(String[] args) { 14 | int port = 8080; 15 | if(args != null && args.length > 0){ 16 | try{ 17 | port = Integer.valueOf(args[0]); 18 | } catch(NumberFormatException e){ 19 | 20 | } 21 | } 22 | 23 | AsyncTimeServerHandler timeServer = new AsyncTimeServerHandler(port); 24 | new Thread(timeServer, "AIO-AsyncTimeServerHandler-001").start(); 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/bio/TimeClient.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.bio; 2 | 3 | 4 | /** 5 | * BIO的TimeClient 6 | * @author weijielu 7 | */ 8 | public class TimeClient { 9 | 10 | /** 11 | * @param args 12 | */ 13 | public static void main(String[] args) { 14 | int port = 8080; 15 | if(args != null && args.length > 0){ 16 | try{ 17 | port = Integer.valueOf(args[0]); 18 | } catch (NumberFormatException e){ 19 | // Do nothing 20 | } 21 | } 22 | 23 | int i = 0; 24 | while(i++ < 1000){ 25 | new Thread(new TimeClientHandler(port), "TimeClient-" + i).start(); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/bio/TimeClientHandler.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.bio; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.io.PrintWriter; 7 | import java.net.Socket; 8 | 9 | /** 10 | * BIO的TimeClientHandler 11 | * @author weijielu 12 | */ 13 | public class TimeClientHandler implements Runnable { 14 | 15 | private int port; 16 | 17 | public TimeClientHandler(int port){ 18 | this.port = port; 19 | } 20 | 21 | @Override 22 | public void run() { 23 | Socket socket = null; 24 | BufferedReader in = null; 25 | PrintWriter out = null; 26 | 27 | try { 28 | socket = new Socket("127.0.0.1", port); 29 | in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 30 | out = new PrintWriter(socket.getOutputStream(), true); 31 | // Sleep 0-10 s中的随机时间 32 | Thread.sleep((long) (1000 * Math.random() * 10)); 33 | out.println("QUERY TIME ORDER"); 34 | System.out.println("Send order to server succeed."); 35 | 36 | String resp = in.readLine(); 37 | System.out.println("Now is : " + resp); 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } finally{ 41 | if(out != null){ 42 | out.close(); 43 | out = null; 44 | } 45 | 46 | if(in != null){ 47 | try { 48 | in.close(); 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | } 52 | in = null; 53 | } 54 | 55 | if(socket != null){ 56 | try { 57 | socket.close(); 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } 61 | socket = null; 62 | } 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/bio/TimeServer.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.bio; 2 | 3 | import java.io.IOException; 4 | import java.net.ServerSocket; 5 | import java.net.Socket; 6 | 7 | /** 8 | * BIO的TimeServer 9 | * @author weijielu 10 | */ 11 | public class TimeServer { 12 | 13 | /** 14 | * @param args 15 | * @throws IOException 16 | */ 17 | public static void main(String[] args) throws IOException { 18 | int port = 8080; 19 | if(args != null && args.length > 0){ 20 | try{ 21 | port = Integer.valueOf(args[0]); 22 | }catch(NumberFormatException e){ 23 | 24 | } 25 | } 26 | 27 | ServerSocket server = null; 28 | try { 29 | server = new ServerSocket(port); 30 | System.out.println("The time server is start in port : " + port); 31 | Socket socket = null; 32 | while(true){ 33 | socket = server.accept(); 34 | new Thread(new TimeServerHandler(socket)).start(); 35 | } 36 | } catch (IOException e) { 37 | e.printStackTrace(); 38 | } finally { 39 | if(server != null){ 40 | System.out.println("The time server close"); 41 | server.close(); 42 | server = null; 43 | } 44 | } 45 | 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/bio/TimeServerHandler.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.bio; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.io.PrintWriter; 7 | import java.net.Socket; 8 | 9 | /** 10 | * BIO的TimeServerhandler 11 | * @author weijielu 12 | */ 13 | public class TimeServerHandler implements Runnable { 14 | 15 | private Socket socket; 16 | 17 | public TimeServerHandler(Socket socket){ 18 | this.socket = socket; 19 | } 20 | 21 | @Override 22 | public void run() { 23 | BufferedReader in = null; 24 | PrintWriter out = null; 25 | 26 | try { 27 | in = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); 28 | out = new PrintWriter(this.socket.getOutputStream(), true); 29 | 30 | String currentTime = null; 31 | String body = null; 32 | while(true){ 33 | // 此处如果无数据,则会被阻塞,直到: 1. 有数据可读; 2. 可用数据读取完毕(客户端输出流关闭); 3.发生空指针或IO异常 34 | body = in.readLine(); 35 | if(body == null){ 36 | break; 37 | } 38 | System.out.println("The time server receive order : " + body); 39 | currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new java.util.Date(System.currentTimeMillis()).toString() : "BAD ORDER"; 40 | out.println(currentTime); 41 | } 42 | } catch (Exception e) { 43 | if(in != null){ 44 | try { 45 | in.close(); 46 | } catch (IOException e1){ 47 | e1.printStackTrace(); 48 | } 49 | in = null; 50 | } 51 | 52 | if(out != null){ 53 | out.close(); 54 | out = null; 55 | } 56 | 57 | if(this.socket != null){ 58 | try { 59 | this.socket.close(); 60 | } catch (IOException e1){ 61 | e1.printStackTrace(); 62 | } 63 | this.socket = null; 64 | } 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/fakenio/TimeServer.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.fakenio; 2 | 3 | import java.io.IOException; 4 | import java.net.ServerSocket; 5 | import java.net.Socket; 6 | 7 | import org.buptdavid.datastructure.io.bio.TimeServerHandler; 8 | 9 | /** 10 | * 伪异步IO的TimeServer
11 | * 伪异步IO采用了线程池实现,因此避免了为每个请求都创建一个独立线程造成的线程资源消耗问题
12 | * 但是由于它底层的通信依然采用同步阻塞模型,因此无法从根本上解决问题
13 | * 由于同步阻塞IO的InputStream的read方法和OutputStream的write方法都是自动阻塞方法,所以如果通信双方放回应答时间过长会引起一下级联故障:
14 | * (1) 服务器端处理缓慢,返回应答消息耗费60s,平时只需要10ms
15 | * (2) 读取故障服务节点的响应会被同步阻塞20s
16 | * (3) 假如所有的可用线程都被故障服务器阻塞,那么后续所有的IO消息都将在队列中排队
17 | * (4) 由于线程池采用阻塞队列实现,当队列积满之后,后续入队列的操作将被阻塞
18 | * (5) 由于前段只有一个线程接受客户端接入,它被阻塞在线程池的同步阻塞队列之后,新的客户端请求消息将被拒绝,客户端会发生大量的链接超时
19 | * (6) 由于几乎所有的链接都超时,调用者会认为系统已经崩溃,无法接受新的请求消息
20 | * SOOOOOOOOOOOO,我们不得不使用NIO 21 | * @author weijielu 22 | */ 23 | public class TimeServer { 24 | 25 | /** 26 | * @param args 27 | * @throws IOException 28 | */ 29 | public static void main(String[] args) throws IOException { 30 | int port = 8080; 31 | if(args != null && args.length > 0){ 32 | try{ 33 | port = Integer.valueOf(args[0]); 34 | }catch(NumberFormatException e){ 35 | // Do nothing 36 | } 37 | } 38 | 39 | ServerSocket server = null; 40 | try { 41 | server = new ServerSocket(port); 42 | System.out.println("The time server is start in port : " + port); 43 | Socket socket = null; 44 | TimeServerHandlerExecutePool singleExecutor = new TimeServerHandlerExecutePool(50, 10000); 45 | while(true){ 46 | socket = server.accept(); 47 | singleExecutor.execute(new TimeServerHandler(socket)); 48 | } 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | } finally { 52 | if(server != null){ 53 | System.out.println("The time server close"); 54 | server.close(); 55 | server = null; 56 | } 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/fakenio/TimeServerHandlerExecutePool.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.fakenio; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.ThreadPoolExecutor; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * 伪异步IO的线程池 10 | * @author weijielu 11 | */ 12 | public class TimeServerHandlerExecutePool { 13 | 14 | private ExecutorService executor; 15 | 16 | public TimeServerHandlerExecutePool(int maxPoolSize, int queueSize){ 17 | executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), 18 | maxPoolSize, 120L, TimeUnit.SECONDS, new ArrayBlockingQueue(queueSize)); 19 | } 20 | 21 | public void execute(java.lang.Runnable task){ 22 | executor.execute(task); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/netty/serializable/SubReqClient.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.netty.serializable; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioSocketChannel; 11 | import io.netty.handler.codec.serialization.ClassResolvers; 12 | import io.netty.handler.codec.serialization.ObjectDecoder; 13 | import io.netty.handler.codec.serialization.ObjectEncoder; 14 | 15 | /** 16 | * Netty Java序列化 产品订购客户端 17 | * @author weijielu 18 | * 19 | */ 20 | public class SubReqClient { 21 | 22 | public void connect(int port, String host) throws InterruptedException{ 23 | // 配置客户端NIO线程组 24 | EventLoopGroup group = new NioEventLoopGroup(); 25 | 26 | try{ 27 | Bootstrap b = new Bootstrap(); 28 | b.group(group).channel(NioSocketChannel.class) 29 | .option(ChannelOption.TCP_NODELAY, true) 30 | .handler(new ChannelInitializer(){ 31 | @Override 32 | protected void initChannel(SocketChannel arg0) throws Exception { 33 | // 禁止对类加载器进行缓存 34 | arg0.pipeline().addLast(new ObjectDecoder(1024, ClassResolvers.cacheDisabled(this.getClass().getClassLoader()))); 35 | arg0.pipeline().addLast(new ObjectEncoder()); 36 | arg0.pipeline().addLast(new SubReqClientHandler()); 37 | } 38 | }); 39 | 40 | // 发起异步连接操作 41 | ChannelFuture f = b.connect(host, port).sync(); 42 | 43 | // 等待客户端链路关闭 44 | f.channel().closeFuture().sync(); 45 | } finally { 46 | group.shutdownGracefully(); 47 | } 48 | 49 | } 50 | 51 | /** 52 | * @param args 53 | * @throws InterruptedException 54 | */ 55 | public static void main(String[] args) throws InterruptedException { 56 | int port = 8080; 57 | if(args != null && args.length > 0){ 58 | try{ 59 | port = Integer.valueOf(args[0]); 60 | }catch (NumberFormatException e){ 61 | 62 | } 63 | } 64 | 65 | new SubReqClient().connect(port, "127.0.0.1"); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/netty/serializable/SubReqClientHandler.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.netty.serializable; 2 | 3 | import io.netty.channel.ChannelHandlerAdapter; 4 | import io.netty.channel.ChannelHandlerContext; 5 | 6 | /** 7 | * Netty Java序列化 产品订购客户端 SubReqClientHandler 8 | * @author weijielu 9 | * 10 | */ 11 | public class SubReqClientHandler extends ChannelHandlerAdapter { 12 | 13 | public SubReqClientHandler(){ 14 | } 15 | 16 | @Override 17 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 18 | for(int i = 0; i < 10; i++){ 19 | ctx.write(subReq(i)); 20 | } 21 | ctx.flush(); 22 | } 23 | 24 | private SubscribeReq subReq(int i){ 25 | SubscribeReq req = new SubscribeReq(); 26 | req.setAddress("北京市海淀区中关村软件园"); 27 | req.setPhoneNumber("1342222222"); 28 | req.setProductName("Netty 权威指南"); 29 | req.setSubReqID(i); 30 | req.setUserName("Luweijie"); 31 | return req; 32 | } 33 | 34 | @Override 35 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 36 | System.out.println("Receive server response : [" + msg + "]"); 37 | } 38 | 39 | @Override 40 | public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 41 | ctx.flush(); 42 | } 43 | 44 | @Override 45 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 46 | cause.printStackTrace(); 47 | ctx.close(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/netty/serializable/SubReqServer.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.netty.serializable; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import io.netty.handler.codec.serialization.ClassResolvers; 12 | import io.netty.handler.codec.serialization.ObjectDecoder; 13 | import io.netty.handler.codec.serialization.ObjectEncoder; 14 | import io.netty.handler.logging.LogLevel; 15 | import io.netty.handler.logging.LoggingHandler; 16 | 17 | /** 18 | * Netty JAVA序列化 订购服务端主函数 SubReqServer 19 | * @author weijielu 20 | * 21 | */ 22 | public class SubReqServer { 23 | 24 | public void bind(int port) throws Exception{ 25 | // 配置服务端的NIO线程组 26 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 27 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 28 | 29 | try{ 30 | ServerBootstrap b = new ServerBootstrap(); 31 | b.group(bossGroup, workerGroup) 32 | .channel(NioServerSocketChannel.class) 33 | .option(ChannelOption.SO_BACKLOG, 100) 34 | .handler(new LoggingHandler(LogLevel.INFO)) 35 | .childHandler(new ChannelInitializer(){ 36 | @Override 37 | protected void initChannel(SocketChannel arg0) throws Exception { 38 | // 创建一个新的ObjectDecoder,它负责对实现Serializable的POJO对象进行解码,它有多个构造函数,支持不同的ClassResolver, 39 | // 在此我们使用weakCachingConcurrentResolver创建线程安全的WeakReferenceMap对类加载器进行缓存, 40 | // 它支持多线程并发访问,当虚拟机内存不足时,会释放缓存中的内存,防止内存泄露,为了防止异常码流和解码错位导致的内存溢出 41 | // 这里将单个对象最大序列化后的字节数组长度设置为1M, 42 | arg0.pipeline().addLast(new ObjectDecoder(1024*1024, ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader()))); 43 | // 新增一个ObjectEncoder,它可以在消息发送的时候自动将实现Serializable的POJO对象进行编码,因此用户无需亲自对对象进行手工序列化, 44 | // 只需要关注自己的业务逻辑处理即可,对象序列化和反序列化都由Netty的对象编码器搞定 45 | arg0.pipeline().addLast(new ObjectEncoder()); 46 | arg0.pipeline().addLast(new SubReqServerHandler()); 47 | } 48 | }); 49 | 50 | // 绑定端口,同步等待成功 51 | ChannelFuture f = b.bind(port).sync(); 52 | 53 | // 等待服务端监听端口关闭 54 | f.channel().closeFuture().sync(); 55 | } finally { 56 | // 优雅退出,释放线程池资源 57 | bossGroup.shutdownGracefully(); 58 | workerGroup.shutdownGracefully(); 59 | } 60 | } 61 | 62 | /** 63 | * @param args 64 | * @throws Exception 65 | */ 66 | public static void main(String[] args) throws Exception { 67 | int port = 8080; 68 | if(args != null && args.length > 0){ 69 | try{ 70 | port = Integer.valueOf(args[0]); 71 | }catch (NumberFormatException e){ 72 | 73 | } 74 | } 75 | 76 | new SubReqServer().bind(port); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/netty/serializable/SubReqServerHandler.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.netty.serializable; 2 | 3 | import io.netty.channel.ChannelHandlerAdapter; 4 | import io.netty.channel.ChannelHandlerContext; 5 | 6 | /** 7 | * Netty JAVA序列化 订购服务处理类 SubReqServerhandler 8 | * @author weijielu 9 | * 10 | */ 11 | public class SubReqServerHandler extends ChannelHandlerAdapter { 12 | 13 | @Override 14 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 15 | SubscribeReq req = (SubscribeReq)msg; 16 | if("Luweijie".equalsIgnoreCase(req.getUserName())){ 17 | System.out.println("Service accept client subscribe req : [" + req.toString() + "]"); 18 | ctx.writeAndFlush(resp(req.getSubReqID())); 19 | } 20 | } 21 | 22 | private SubscribeResp resp(int subReqID){ 23 | SubscribeResp resp = new SubscribeResp(); 24 | resp.setSubReqID(subReqID); 25 | resp.setRespCode(0); 26 | resp.setDesc("Netty book order succeed, 3 days later, sent to the designated address"); 27 | return resp; 28 | } 29 | 30 | @Override 31 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 32 | cause.printStackTrace(); 33 | ctx.close();//发生异常,关闭链路 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/netty/serializable/SubscribeReq.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.netty.serializable; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Netty Java序列化 订购请求POJO类定义 7 | * @author weijielu 8 | * 9 | */ 10 | public class SubscribeReq implements Serializable { 11 | 12 | /** 13 | * 默认的序列号ID 14 | */ 15 | private static final long serialVersionUID = 1L; 16 | 17 | private int subReqID; 18 | 19 | private String userName; 20 | 21 | private String productName; 22 | 23 | private String phoneNumber; 24 | 25 | private String address; 26 | 27 | 28 | /* (non-Javadoc) 29 | * @see java.lang.Object#toString() 30 | */ 31 | @Override 32 | public String toString() { 33 | return "SubscribeReq [subReqId=" + subReqID + ", userName=" + userName + ", productName=" + productName + ", phoneNumber=" +phoneNumber + ", address=" + address + "]"; 34 | } 35 | 36 | /** 37 | * @return the subReqID 38 | */ 39 | public int getSubReqID() { 40 | return subReqID; 41 | } 42 | 43 | /** 44 | * @param subReqID the subReqID to set 45 | */ 46 | public void setSubReqID(int subReqID) { 47 | this.subReqID = subReqID; 48 | } 49 | 50 | /** 51 | * @return the userName 52 | */ 53 | public String getUserName() { 54 | return userName; 55 | } 56 | 57 | /** 58 | * @param userName the userName to set 59 | */ 60 | public void setUserName(String userName) { 61 | this.userName = userName; 62 | } 63 | 64 | /** 65 | * @return the productName 66 | */ 67 | public String getProductName() { 68 | return productName; 69 | } 70 | 71 | /** 72 | * @param productName the productName to set 73 | */ 74 | public void setProductName(String productName) { 75 | this.productName = productName; 76 | } 77 | 78 | /** 79 | * @return the phoneNumber 80 | */ 81 | public String getPhoneNumber() { 82 | return phoneNumber; 83 | } 84 | 85 | /** 86 | * @param phoneNumber the phoneNumber to set 87 | */ 88 | public void setPhoneNumber(String phoneNumber) { 89 | this.phoneNumber = phoneNumber; 90 | } 91 | 92 | /** 93 | * @return the address 94 | */ 95 | public String getAddress() { 96 | return address; 97 | } 98 | 99 | /** 100 | * @param address the address to set 101 | */ 102 | public void setAddress(String address) { 103 | this.address = address; 104 | } 105 | 106 | 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/netty/serializable/SubscribeResp.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.netty.serializable; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Netty Java序列化 订购应答POJO类定义 7 | * @author weijielu 8 | * 9 | */ 10 | public class SubscribeResp implements Serializable { 11 | 12 | /** 13 | * 默认序列ID 14 | */ 15 | private static final long serialVersionUID = 1L; 16 | 17 | private int subReqID; 18 | 19 | private int respCode; 20 | 21 | private String desc; 22 | 23 | 24 | 25 | /* (non-Javadoc) 26 | * @see java.lang.Object#toString() 27 | */ 28 | @Override 29 | public String toString() { 30 | return "SubscribeResp [subReqID=" + subReqID + ", respCode=" + respCode + ", desc=" + desc + "]"; 31 | } 32 | 33 | /** 34 | * @return the subReqID 35 | */ 36 | public int getSubReqID() { 37 | return subReqID; 38 | } 39 | 40 | /** 41 | * @param subReqID the subReqID to set 42 | */ 43 | public void setSubReqID(int subReqID) { 44 | this.subReqID = subReqID; 45 | } 46 | 47 | /** 48 | * @return the respCode 49 | */ 50 | public int getRespCode() { 51 | return respCode; 52 | } 53 | 54 | /** 55 | * @param respCode the respCode to set 56 | */ 57 | public void setRespCode(int respCode) { 58 | this.respCode = respCode; 59 | } 60 | 61 | /** 62 | * @return the desc 63 | */ 64 | public String getDesc() { 65 | return desc; 66 | } 67 | 68 | /** 69 | * @param desc the desc to set 70 | */ 71 | public void setDesc(String desc) { 72 | this.desc = desc; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/netty/tcpacketsplicing/TimeClient.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.netty.tcpacketsplicing; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioSocketChannel; 11 | import io.netty.handler.codec.LineBasedFrameDecoder; 12 | import io.netty.handler.codec.string.StringDecoder; 13 | 14 | /** 15 | * Netty时间服务器客户端 TimeClient 16 | * @author weijielu 17 | * 18 | */ 19 | public class TimeClient { 20 | 21 | public void connect(int port, String host) throws Exception{ 22 | // 配置客户端NIO线程组 23 | EventLoopGroup group = new NioEventLoopGroup(); 24 | try{ 25 | Bootstrap b = new Bootstrap(); 26 | b.group(group).channel(NioSocketChannel.class) 27 | .option(ChannelOption.TCP_NODELAY, true) 28 | .handler(new ChannelInitializer(){ 29 | // 作用是当创建NioSocketChannel成功之后,在初始化它的时候将它的ChannelHandler设置到ChannelPipeline中 30 | // 用于处理网络IO事件 31 | @Override 32 | protected void initChannel(SocketChannel arg0) throws Exception { 33 | arg0.pipeline().addLast(new LineBasedFrameDecoder(1024)); 34 | arg0.pipeline().addLast(new StringDecoder()); 35 | arg0.pipeline().addLast(new TimeClientHandler()); 36 | } 37 | }); 38 | 39 | // 发起异步连接操作 40 | ChannelFuture f = b.connect(host, port).sync(); 41 | 42 | // 等待客户端链路关闭 43 | f.channel().closeFuture().sync(); 44 | 45 | } finally { 46 | // 优雅退出,释放NIO线程组 47 | group.shutdownGracefully(); 48 | } 49 | } 50 | 51 | /** 52 | * @param args 53 | * @throws Exception 54 | */ 55 | public static void main(String[] args) throws Exception { 56 | int port = 8080; 57 | if(args != null && args.length > 0){ 58 | try{ 59 | port = Integer.valueOf(args[0]); 60 | }catch (NumberFormatException e){ 61 | 62 | } 63 | } 64 | 65 | new TimeClient().connect(port, "127.0.0.1"); 66 | 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/netty/tcpacketsplicing/TimeClientHandler.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.netty.tcpacketsplicing; 2 | 3 | 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.buffer.Unpooled; 6 | import io.netty.channel.ChannelHandlerAdapter; 7 | import io.netty.channel.ChannelHandlerContext; 8 | 9 | import java.util.logging.Logger; 10 | 11 | /** 12 | * Netty时间服务器客户端 TimeClientHandler 13 | * @author weijielu 14 | * 15 | */ 16 | public class TimeClientHandler extends ChannelHandlerAdapter { 17 | 18 | private static final Logger logger = Logger.getLogger(TimeClientHandler.class.getName()); 19 | 20 | private int counter; 21 | private byte[] req; 22 | 23 | /** 24 | * Creates a client-side handler 25 | */ 26 | public TimeClientHandler(){ 27 | req = (("QUERY TIME ORDER") + System.getProperty("line.separator")).getBytes(); 28 | } 29 | 30 | /** 31 | * 当客户端和服务器端TCP链路建立成功之后,Netty的NIO线程会调用channelActive方法
32 | * 发送查询时间的指令给服务端,调用ChannelHandlerContext的writeAndFlush方法将请求消息发送给服务端
33 | */ 34 | @Override 35 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 36 | // ctx.writeAndFlush(firstMessage); 37 | ByteBuf message = null; 38 | for(int i = 0; i < 100; i++){ 39 | message = Unpooled.buffer(req.length); 40 | message.writeBytes(req); 41 | ctx.writeAndFlush(message); 42 | } 43 | } 44 | 45 | /** 46 | * 当服务端返回应答消息时,channelRead方法被调用 47 | */ 48 | @Override 49 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 50 | // ByteBuf buf = (ByteBuf)msg; 51 | // byte[] req = new byte[buf.readableBytes()]; 52 | // buf.readBytes(req); 53 | // String body = new String(req, "UTF-8"); 54 | 55 | String body = (String) msg; 56 | System.out.println("Now is : " + body + " ; the counter is : " + ++counter); 57 | } 58 | 59 | /** 60 | * 当发生异常时,打印异常日志,释放客户端资源 61 | */ 62 | @Override 63 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 64 | // 释放资源 65 | logger.warning("Unexpected exception from downstream : " + cause.getMessage()); 66 | ctx.close(); 67 | } 68 | 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/netty/tcpacketsplicing/TimeServer.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.netty.tcpacketsplicing; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import io.netty.handler.codec.LineBasedFrameDecoder; 12 | import io.netty.handler.codec.string.StringDecoder; 13 | 14 | /** 15 | * Netty时间服务器服务端 TimeServer 16 | * @author weijielu 17 | * 18 | */ 19 | public class TimeServer { 20 | 21 | public void bind(int port) throws Exception{ 22 | // 配置服务端的NIO线程组 23 | // 用于服务端接受客户端的连接 24 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 25 | // 用于进行SocketChannel的网络读写 26 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 27 | 28 | try{ 29 | // Netty用于启动NIO服务端的辅助启动类,目的是降低服务端的开发复杂度 30 | ServerBootstrap b = new ServerBootstrap(); 31 | b.group(bossGroup, workerGroup) 32 | .channel(NioServerSocketChannel.class) 33 | .option(ChannelOption.SO_BACKLOG, 1024) 34 | .childHandler(new ChildChannelHandler()); 35 | 36 | // 绑定端口,同步等待成功 37 | // 类似java.util.concurrrent.Future,主要用于异步操作的通知回调 38 | ChannelFuture f = b.bind(port).sync(); 39 | System.out.println("The time server is start in port : " + port); 40 | 41 | // 等待服务端监听端口关闭 42 | // 进行阻塞,等待服务端链路关闭后main函数才退出 43 | f.channel().closeFuture().sync(); 44 | 45 | } finally { 46 | // 优雅退出,释放线程池资源 47 | bossGroup.shutdownGracefully(); 48 | workerGroup.shutdownGracefully(); 49 | } 50 | } 51 | 52 | /** 53 | * 类似于Reactor模式中的handler,主要用于处理网络IO事件,例如日志记录,对消息进行编解码等 54 | * 55 | */ 56 | private class ChildChannelHandler extends ChannelInitializer{ 57 | 58 | @Override 59 | protected void initChannel(SocketChannel arg0) throws Exception { 60 | // LineBasedFrameDecoder的工作原理是它依次遍历ByteBuf中的可读字节,判断看是否有"\n"或者"\r\n", 61 | // 如果有,就以此位置为结束位置,从可读索引到结束位置区间的字节就组成了一行 62 | // 如果连续读取到最大长度后仍然没有发现换行符,就不抛出异常,同时忽略掉之前读到的异常码流 63 | arg0.pipeline().addLast(new LineBasedFrameDecoder(1024)); 64 | // StringDecoder的功能就是将接受到的对象转换成字符串,然后继续调用后面的handler 65 | // LineBaseFrameDecoder+StringDecoder组合就是按行切换的文本编码器,用来支持TCP的粘包和拆包 66 | arg0.pipeline().addLast(new StringDecoder()); 67 | arg0.pipeline().addLast(new TimeServerHandler()); 68 | 69 | // 除此之外,还有两种解码器,他们都能解决TCP粘包拆包导致的读半包问题 70 | // 1. DelimiterBasedFrameDecoder 自动完成以分隔符做结束标志的消息的解码 71 | // 2. FixedLengthFrameDecoder 自动完成对定长消息的解码 72 | } 73 | 74 | } 75 | 76 | /** 77 | * @param args 78 | * @throws Exception 79 | */ 80 | public static void main(String[] args) throws Exception { 81 | int port = 8080; 82 | if(args != null && args.length > 0){ 83 | try{ 84 | port = Integer.valueOf(args[0]); 85 | }catch (NumberFormatException e){ 86 | 87 | } 88 | } 89 | 90 | new TimeServer().bind(port); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/netty/tcpacketsplicing/TimeServerHandler.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.netty.tcpacketsplicing; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.ChannelHandlerAdapter; 6 | import io.netty.channel.ChannelHandlerContext; 7 | 8 | /** 9 | * Netty时间服务器服务端 TimeServerhandler 10 | * @author weijielu 11 | * 12 | */ 13 | public class TimeServerHandler extends ChannelHandlerAdapter { 14 | 15 | private int counter; 16 | 17 | @Override 18 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 19 | // ByteBuf buf = (ByteBuf)msg; 20 | // byte[] req = new byte[buf.readableBytes()]; 21 | // buf.readBytes(req); 22 | // 23 | // String body = new String(req, "UTF-8").substring(0, req.length - System.getProperty("line.separator").length()); 24 | 25 | String body = (String) msg; 26 | 27 | System.out.println("The time server receive order : " + body + " ; the counter is : " + ++counter); 28 | String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new java.util.Date(System.currentTimeMillis()).toString() : "BAD ORDER"; 29 | currentTime = currentTime + System.getProperty("line.separator"); 30 | ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes()); 31 | ctx.writeAndFlush(resp); 32 | } 33 | 34 | @Override 35 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 36 | ctx.close(); 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/nio/MultiplexerTimeServer.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.nio; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.SelectionKey; 7 | import java.nio.channels.Selector; 8 | import java.nio.channels.ServerSocketChannel; 9 | import java.nio.channels.SocketChannel; 10 | import java.util.Iterator; 11 | import java.util.Set; 12 | 13 | /** 14 | * NIO时间服务器 MultiplexerTimeServer 15 | * NIO编程的优点如下:
16 | * (1)客户端发起的连接操作是异步的,可以通过在多路复用器注册OP_CONNECT等待后续结果,不需要像之前的客户端那样被同步阻塞。
17 | * (2)SocketChannel的读写操作都是异步的,如果没有可读写的数据它不会同步等待,直接返回,这样IO通信线程就可以处理其他的
18 | * 链路,不需要同步等待这个链路可用
19 | * (3)线程模型的优化:由于JDK的Selector在Linux等主流操作系统上通过epoll实现,它没有连接句柄数的限制(只受限于操作系统的最大
20 | * 句柄数或者对单个进程的句柄限制),这意味着一个Selector线程可以同时处理成千上万个客户端连接,而且性能不会随着客户端
21 | * 的增加而线性下降,因此,它非常适合做高性能、高负载的网络服务器
22 | * @author weijielu 23 | * 24 | */ 25 | public class MultiplexerTimeServer implements Runnable { 26 | 27 | private Selector selector; 28 | 29 | private ServerSocketChannel servChannel; 30 | 31 | private volatile boolean stop; 32 | 33 | /** 34 | * 初始化多路复用器,绑定监听端口 35 | * @param port 36 | */ 37 | public MultiplexerTimeServer(int port){ 38 | try{ 39 | selector = Selector.open(); 40 | 41 | servChannel = ServerSocketChannel.open(); 42 | servChannel.configureBlocking(false); 43 | 44 | servChannel.socket().bind(new InetSocketAddress(port), 1024); 45 | servChannel.register(selector, SelectionKey.OP_ACCEPT); 46 | 47 | System.out.println("The time server is tart in port : " + port); 48 | } catch (IOException e){ 49 | e.printStackTrace(); 50 | System.exit(1); 51 | } 52 | } 53 | 54 | public void stop(){ 55 | this.stop = true; 56 | } 57 | 58 | @Override 59 | public void run() { 60 | // 循环遍历selector,休眠时间 1s 61 | while(!stop){ 62 | try{ 63 | selector.select(1000); 64 | Set selectedKeys = selector.selectedKeys(); 65 | Iterator it = selectedKeys.iterator(); 66 | SelectionKey key = null; 67 | while(it.hasNext()){ 68 | key = it.next(); 69 | it.remove(); 70 | try{ 71 | handleInput(key); 72 | } catch (Exception e){ 73 | if(key != null){ 74 | key.cancel(); 75 | if(key.channel() != null){ 76 | key.channel().close(); 77 | } 78 | } 79 | } 80 | } 81 | 82 | } catch (Throwable t){ 83 | t.printStackTrace(); 84 | } 85 | } 86 | 87 | // 多路复用器关闭后,所有注册在上面的Channel和Pipe等资源都会被自动去注册并关闭,所以不需要重复释放资源 88 | if(selector != null){ 89 | try{ 90 | selector.close(); 91 | } catch (IOException e){ 92 | e.printStackTrace(); 93 | } 94 | } 95 | } 96 | 97 | private void handleInput(SelectionKey key) throws IOException{ 98 | if(key.isValid()){ 99 | // 处理新接入的请求消息 100 | if(key.isAcceptable()){ 101 | //接受新connection 102 | ServerSocketChannel ssc = (ServerSocketChannel)key.channel(); 103 | // 完成TCP的三次握手 104 | SocketChannel sc = ssc.accept(); 105 | sc.configureBlocking(false); 106 | // 添加新connection到selector 107 | sc.register(selector, SelectionKey.OP_READ); 108 | } 109 | 110 | if(key.isReadable()){ 111 | // 读数据 112 | SocketChannel sc = (SocketChannel) key.channel(); 113 | ByteBuffer readBuffer = ByteBuffer.allocate(1024); 114 | // 非阻塞读取 115 | int readBytes = sc.read(readBuffer); 116 | if(readBytes > 0){ 117 | // 大于0,对字节进行解编码 118 | readBuffer.flip(); // 将缓冲区当前的limit设置为position,position设置为0,用于后续对缓冲区的读取操作 119 | byte[] bytes = new byte[readBuffer.remaining()]; 120 | readBuffer.get(bytes); 121 | 122 | String body = new String(bytes, "UTF-8"); 123 | System.out.println("The time server receive order : " + body); 124 | String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new java.util.Date(System.currentTimeMillis()).toString() : "BAD ORDER"; 125 | 126 | doWrite(sc, currentTime); 127 | }else if(readBytes < 0){ 128 | // 小于0(-1),链路已经关闭,关闭SocketChannel释放资源 129 | key.cancel(); 130 | sc.close(); 131 | }else { 132 | // 读到0字节,忽略 133 | } 134 | } 135 | } 136 | } 137 | 138 | /** 139 | * 将应答消息异步发送给客户端 140 | * @param channel 141 | * @param response 142 | * @throws IOException 143 | */ 144 | private void doWrite(SocketChannel channel, String response) throws IOException{ 145 | if(response != null && response.trim().length() > 0){ 146 | byte[] bytes = response.getBytes(); 147 | ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length); 148 | writeBuffer.put(bytes); 149 | writeBuffer.flip(); 150 | // 异步非阻塞写 151 | channel.write(writeBuffer); 152 | } 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/nio/TimeClient.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.nio; 2 | 3 | /** 4 | * NIO时间服务器客户端 TimeClient 5 | * @author weijielu 6 | * 7 | */ 8 | public class TimeClient { 9 | 10 | /** 11 | * @param args 12 | */ 13 | public static void main(String[] args) { 14 | int port = 8080; 15 | if(args != null && args.length > 0){ 16 | try{ 17 | port = Integer.valueOf(args[0]); 18 | }catch (NumberFormatException e){ 19 | 20 | } 21 | } 22 | 23 | int i = 0; 24 | while(i++ < 1000){ 25 | new Thread(new TimeClientHandle("127.0.0.1", port), "TimeClient-" + i).start(); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/nio/TimeClientHandle.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.nio; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.SelectionKey; 7 | import java.nio.channels.Selector; 8 | import java.nio.channels.SocketChannel; 9 | import java.util.Iterator; 10 | import java.util.Set; 11 | 12 | /** 13 | * NIO时间服务器客户端 TimeClientHandle 14 | * @author weijielu 15 | * 16 | */ 17 | public class TimeClientHandle implements Runnable { 18 | 19 | private String host; 20 | private int port; 21 | private Selector selector; 22 | private SocketChannel socketChannel; 23 | private volatile boolean stop; 24 | 25 | public TimeClientHandle(String host, int port){ 26 | this.host = host == null ? "127.0.0.1" : host; 27 | this.port = port; 28 | try{ 29 | selector = Selector.open(); 30 | socketChannel = SocketChannel.open(); 31 | socketChannel.configureBlocking(false); 32 | } catch (IOException e){ 33 | e.printStackTrace(); 34 | System.exit(1); 35 | } 36 | } 37 | 38 | @Override 39 | public void run() { 40 | try{ 41 | doConnect(); 42 | } catch (IOException e){ 43 | e.printStackTrace(); 44 | System.exit(1); 45 | } 46 | 47 | while(!stop){ 48 | try{ 49 | selector.select(1000); 50 | Set selectedKeys = selector.selectedKeys(); 51 | Iterator it = selectedKeys.iterator(); 52 | SelectionKey key = null; 53 | 54 | while(it.hasNext()){ 55 | key = it.next(); 56 | it.remove(); 57 | try{ 58 | handleInput(key); 59 | } catch (Exception e){ 60 | if(key != null){ 61 | key.cancel(); 62 | if(key.channel() != null){ 63 | key.channel().close(); 64 | } 65 | } 66 | } 67 | } 68 | 69 | } catch (Exception e){ 70 | e.printStackTrace(); 71 | System.exit(1); 72 | } 73 | } 74 | 75 | // 多路复用器关闭后,所有注册在上面的Channel和Pipe等资源都会被自动去注册并关闭,所以不需要重复释放资源 76 | if(selector != null){ 77 | try{ 78 | selector.close(); 79 | } catch (IOException e){ 80 | e.printStackTrace(); 81 | } 82 | } 83 | } 84 | 85 | 86 | private void handleInput(SelectionKey key) throws IOException{ 87 | if(key.isValid()){ 88 | // 判断是否连接成功 89 | SocketChannel sc = (SocketChannel)key.channel(); 90 | if(key.isConnectable()){ 91 | if(sc.finishConnect()){ 92 | sc.register(selector, SelectionKey.OP_READ); 93 | doWrite(sc); 94 | }else{ 95 | System.exit(1); 96 | } 97 | } 98 | 99 | if(key.isReadable()){ 100 | ByteBuffer readBuffer = ByteBuffer.allocate(1024); 101 | int readBytes = sc.read(readBuffer); 102 | 103 | if(readBytes > 0){ 104 | // 大于0,对字节进行解编码 105 | readBuffer.flip(); // 将缓冲区当前的limit设置为position,position设置为0,用于后续对缓冲区的读取操作 106 | byte[] bytes = new byte[readBuffer.remaining()]; 107 | readBuffer.get(bytes); 108 | 109 | String body = new String(bytes, "UTF-8"); 110 | System.out.println("Now is : " + body); 111 | this.stop = true; 112 | }else if(readBytes < 0){ 113 | // 小于0(-1),链路已经关闭,关闭SocketChannel释放资源 114 | key.cancel(); 115 | sc.close(); 116 | }else { 117 | // 读到0字节,忽略 118 | } 119 | } 120 | } 121 | } 122 | 123 | private void doConnect() throws IOException{ 124 | // 如果直接连接成功,则注册到多路复用器上,发送请求消息,读应答 125 | if(socketChannel.connect(new InetSocketAddress(host, port))){ 126 | socketChannel.register(selector, SelectionKey.OP_READ); 127 | doWrite(socketChannel); 128 | }else{ 129 | socketChannel.register(selector, SelectionKey.OP_CONNECT); 130 | } 131 | } 132 | 133 | private void doWrite(SocketChannel sc) throws IOException{ 134 | byte[] req = "QUERY TIME ORDER".getBytes(); 135 | ByteBuffer writeBuffer = ByteBuffer.allocate(req.length); 136 | writeBuffer.put(req); 137 | writeBuffer.flip(); 138 | sc.write(writeBuffer); 139 | if(!writeBuffer.hasRemaining()){ 140 | System.out.println("Send order to server succeed."); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/io/nio/TimeServer.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.io.nio; 2 | 3 | /** 4 | * NIO时间服务器 TimeServer 5 | * @author weijielu 6 | * 7 | */ 8 | public class TimeServer { 9 | 10 | /** 11 | * @param args 12 | */ 13 | public static void main(String[] args) { 14 | int port = 8080; 15 | if(args != null && args.length > 0){ 16 | try{ 17 | port = Integer.valueOf(args[0]); 18 | } catch(NumberFormatException e){ 19 | 20 | } 21 | } 22 | 23 | MultiplexerTimeServer timeServer = new MultiplexerTimeServer(port); 24 | new Thread(timeServer, "NIO-MultiplexerTimeServer-001").start(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/linkedlist/DeleteDups.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.linkedlist; 2 | 3 | import org.buptdavid.datastructure.Node; 4 | 5 | /** 6 | * 删除链表中重复的元素 7 | * 8 | * @author weijielu 9 | * 10 | */ 11 | public class DeleteDups { 12 | 13 | public static void delete(Node head) { 14 | if (head == null) 15 | return; 16 | 17 | Node current = head; 18 | while (current != null) { 19 | Node runner = current; 20 | while (runner.next != null) { 21 | if (runner.next.data == current.data) { 22 | runner.next = runner.next.next; 23 | } else { 24 | runner = runner.next; 25 | } 26 | } 27 | 28 | current = current.next; 29 | } 30 | } 31 | 32 | /** 33 | * @param args 34 | */ 35 | public static void main(String[] args) { 36 | Node node1 = new Node(2); 37 | Node node2 = new Node(2); 38 | Node node3 = new Node(3); 39 | Node node4 = new Node(4); 40 | Node node5 = new Node(4); 41 | 42 | node1.next = node2; 43 | node2.next = node3; 44 | node3.next = node4; 45 | node4.next = node5; 46 | 47 | Node head = node1; 48 | while (node1 != null) { 49 | System.out.print(node1.data + " "); 50 | node1 = node1.next; 51 | } 52 | 53 | System.out.println("\r\nDelete dups"); 54 | delete(head); 55 | 56 | node1 = head; 57 | while (node1 != null) { 58 | System.out.print(node1.data + " "); 59 | node1 = node1.next; 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/linkedlist/LinkedListLoop.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.linkedlist; 2 | 3 | import org.buptdavid.datastructure.Node; 4 | 5 | /** 6 | * 1. 判断一个链表是否存在环儿
7 | * 2. 如果有环儿计算环儿的长度
8 | * 3. 找出环儿的连接点
9 | * @author weijielu 10 | * @see LinkedListLoopTest 11 | */ 12 | public class LinkedListLoop { 13 | 14 | /** 15 | * 判断一个链表是否存在环儿 16 | * @param header 17 | * @return 是否存在环儿 18 | */ 19 | public static boolean isExistLoop(Node header){ 20 | // 定义两个指针fast和slow,fast移动步长为2,slow移动步长为1 21 | Node fast = header; 22 | Node slow = header; 23 | 24 | while(fast != null && fast.next != null){ 25 | fast = fast.next.next; 26 | slow = slow.next; 27 | 28 | //如果相遇则存在环儿,跳出 29 | if(fast == slow){ 30 | break; 31 | } 32 | } 33 | 34 | // 根据跳出循环的条件return 35 | if(fast == null || fast.next == null){ 36 | return false; 37 | }else{ 38 | return true; 39 | } 40 | } 41 | 42 | /** 43 | * 计算有环儿链表的环儿长度
44 | * fast, slow从碰撞点出发再次碰撞就是环儿的长度 45 | * @param header 46 | * @return 返回环儿的长度 47 | */ 48 | public static int loopLength(Node header){ 49 | // 如果不存在环儿,返回0 50 | if(!isExistLoop(header)){ 51 | return 0; 52 | } 53 | 54 | Node fast = header; 55 | Node slow = header; 56 | int length = 0; 57 | boolean begin = false; 58 | boolean again = false; 59 | 60 | while(fast != null && fast.next != null){ 61 | fast = fast.next.next; 62 | slow = slow.next; 63 | 64 | // 超过两圈后停止计数,跳出循环 65 | if(fast == slow && again == true){ 66 | break; 67 | } 68 | 69 | // 超过一圈后开始计数 70 | if(fast == slow && again == false){ 71 | begin = true; 72 | again = true; 73 | } 74 | 75 | if(begin == true){ 76 | ++length; 77 | } 78 | } 79 | 80 | return length; 81 | } 82 | 83 | /** 84 | * 找出环儿的连接点
85 | * 碰撞点到连接点的距离=头指针到连接点的距离
86 | * 因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点
87 | * @param header 88 | * @return 环儿连接点 89 | */ 90 | public static Node findLoopEntrance(Node header){ 91 | Node fast = header; 92 | Node slow = header; 93 | while(fast != null && fast.next != null){ 94 | fast = fast.next.next; 95 | slow = slow.next; 96 | if(fast == slow){ 97 | break; 98 | } 99 | } 100 | 101 | if(fast == null || fast.next == null){ 102 | return null; 103 | } 104 | 105 | slow = header; 106 | while(slow != fast){ 107 | slow = slow.next; 108 | fast = fast.next; 109 | } 110 | 111 | return slow; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/linkedlist/SortWithValue.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.linkedlist; 2 | 3 | import org.buptdavid.datastructure.Node; 4 | 5 | /** 6 | * 给出一个值,将链表中左边数据都小于此值,右边的值都大于等于此值 7 | * 8 | * @author weijielu 9 | * 10 | */ 11 | public class SortWithValue { 12 | 13 | /** 14 | * 较差的方法 15 | * @param head 16 | * @param x 17 | * @return 18 | */ 19 | public static Node sort(Node head, int x) { 20 | if (head == null) { 21 | return null; 22 | } 23 | 24 | Node beforeStart = null; 25 | Node beforeEnd = null; 26 | Node afterStart = null; 27 | Node afterEnd = null; 28 | 29 | while (head != null) { 30 | Node next = head.next; 31 | head.next = null; 32 | if (head.data < x) { 33 | if (beforeStart == null) { 34 | beforeStart = head; 35 | beforeEnd = beforeStart; 36 | } else { 37 | beforeEnd.next = head; 38 | beforeEnd = head; 39 | } 40 | } else { 41 | if (afterStart == null) { 42 | afterStart = head; 43 | afterEnd = afterStart; 44 | } else { 45 | afterEnd.next = head; 46 | afterEnd = head; 47 | } 48 | } 49 | 50 | head = next; 51 | } 52 | 53 | if (beforeStart != null) { 54 | beforeEnd.next = afterStart; 55 | head = beforeStart; 56 | } else { 57 | head = afterStart; 58 | } 59 | 60 | return head; 61 | } 62 | 63 | /** 64 | * 较优的方法 65 | * @param node 66 | * @param x 67 | * @return 68 | */ 69 | public static Node sortGood(Node node, int x) { 70 | if (node == null) { 71 | return node; 72 | } 73 | 74 | Node beforeStart = null; 75 | Node afterStart = null; 76 | 77 | while (node != null) { 78 | Node next = node.next; 79 | 80 | if (node.data < x) { 81 | node.next = beforeStart; 82 | beforeStart = node; 83 | } else { 84 | node.next = afterStart; 85 | afterStart = node; 86 | } 87 | node = next; 88 | } 89 | 90 | Node head = null; 91 | if (beforeStart == null) { 92 | head = afterStart; 93 | } else { 94 | head = beforeStart; 95 | while (beforeStart.next != null) { 96 | beforeStart = beforeStart.next; 97 | } 98 | beforeStart.next = afterStart; 99 | } 100 | 101 | return head; 102 | } 103 | 104 | /** 105 | * @param args 106 | */ 107 | public static void main(String[] args) { 108 | Node node1 = new Node(2); 109 | Node node2 = new Node(8); 110 | Node node3 = new Node(6); 111 | Node node4 = new Node(10); 112 | Node node5 = new Node(7); 113 | 114 | node1.next = node2; 115 | node2.next = node3; 116 | node3.next = node4; 117 | node4.next = node5; 118 | 119 | Node head = node1; 120 | while (node1 != null) { 121 | System.out.print(node1.data + " "); 122 | node1 = node1.next; 123 | } 124 | 125 | System.out.println("\r\nSort...."); 126 | node1 = sortGood(head, 6); 127 | 128 | while (node1 != null) { 129 | System.out.print(node1.data + " "); 130 | node1 = node1.next; 131 | } 132 | 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/queue/IQueue.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.queue; 2 | 3 | /** 4 | * 队列的接口 5 | * @author weijielu 6 | */ 7 | public interface IQueue { 8 | 9 | /** 10 | * 入队列操作 11 | * @param item 12 | */ 13 | void enqueue(T item); 14 | 15 | /** 16 | * 出队列操作 17 | * @return 18 | */ 19 | T dequeue(); 20 | 21 | /** 22 | * 返回队列头,但不出退咧 23 | * @return 24 | */ 25 | T peek(); 26 | 27 | /** 28 | * 队列是否为空 29 | * @return 30 | */ 31 | boolean isEmpty(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/queue/Queue.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.queue; 2 | 3 | import org.buptdavid.datastructure.Node; 4 | 5 | /** 6 | * 队列的实现 7 | * 8 | * @author weijielu 9 | * @see QueueTest 10 | * @see IQueue 11 | * @see Node 12 | */ 13 | public class Queue implements IQueue { 14 | Node first, last; 15 | 16 | public void enqueue(T item) { 17 | if(first == null){ 18 | last = new Node(item); 19 | first = last; 20 | }else{ 21 | last.next = new Node(item); 22 | last = last.next; 23 | } 24 | } 25 | 26 | public T dequeue() { 27 | if(first != null){ 28 | T item = first.data; 29 | first = first.next; 30 | return item; 31 | } 32 | 33 | return null; 34 | } 35 | 36 | public T peek() { 37 | if(first != null){ 38 | return first.data; 39 | } 40 | return null; 41 | } 42 | 43 | public boolean isEmpty() { 44 | return first == null; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/queue/QueueWith2Stack.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.queue; 2 | 3 | import org.buptdavid.datastructure.stack.IStack; 4 | import org.buptdavid.datastructure.stack.Stack; 5 | 6 | 7 | /** 8 | * 使用两个栈实现队列 9 | * @author weijielu 10 | * 11 | */ 12 | public class QueueWith2Stack implements IQueue { 13 | IStack stackOldest, stackNewest; 14 | 15 | public QueueWith2Stack(){ 16 | stackOldest = new Stack(); 17 | stackNewest = new Stack(); 18 | } 19 | 20 | public void enqueue(T item) { 21 | stackNewest.push(item); 22 | } 23 | 24 | public T dequeue() { 25 | shiftStacks(); 26 | return stackOldest.pop(); 27 | } 28 | 29 | public T peek() { 30 | shiftStacks(); 31 | return stackOldest.peek(); 32 | } 33 | 34 | /** 35 | * 如果旧栈已空,将新栈所有数据压入旧栈 36 | */ 37 | private void shiftStacks(){ 38 | if(stackOldest.isEmpty()){ 39 | while(!stackNewest.isEmpty()){ 40 | stackOldest.push(stackNewest.pop()); 41 | } 42 | } 43 | } 44 | 45 | public boolean isEmpty() { 46 | return stackOldest.isEmpty(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/search/BinarySearch.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.search; 2 | 3 | /** 4 | * 二分查找的实现: 在一个有序数组中查找某个值 5 | * @author weijielu 6 | * @see BinarySearchTest 7 | */ 8 | public class BinarySearch { 9 | 10 | /** 11 | * 使用循环的方式实现二分查找 12 | * @param array 13 | * @param value 14 | * @return 15 | */ 16 | public static Integer searchCirculation(int[] array, int value){ 17 | int low = 0; 18 | int high = array.length - 1; 19 | int middle; 20 | 21 | while(low <= high){ 22 | middle = (low + high) / 2; 23 | if(value < array[middle]){ 24 | high = middle - 1; 25 | }else if(value > array[middle]){ 26 | low = middle + 1; 27 | }else{ 28 | return array[middle]; 29 | } 30 | } 31 | 32 | return null; 33 | } 34 | 35 | /** 36 | * 使用递归的方式实现二分查找 37 | * @param array 38 | * @param value 39 | * @return 40 | */ 41 | public static Integer searchRecursive(int[] array, int value){ 42 | return searchRecursive(array, value, 0, array.length - 1); 43 | } 44 | 45 | private static Integer searchRecursive(int[] array, int value, int low, int high){ 46 | if(high < low){ 47 | return null; 48 | } 49 | 50 | int middle = (low + high) / 2; 51 | 52 | if(value < array[middle]){ 53 | return searchRecursive(array, value, low, middle - 1); 54 | }else if(value > array[middle]){ 55 | return searchRecursive(array, value, middle + 1, high); 56 | }else { 57 | return array[middle]; 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/sort/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.sort; 2 | 3 | /** 4 | * 冒泡排序
5 | * 时间复杂度: 平均情况与最差情况都是O(n^2)
6 | * 空间复杂度: O(1) 7 | * @author weijielu 8 | * @see ISort 9 | * @see SortTest 10 | */ 11 | public class BubbleSort implements ISort { 12 | 13 | public void sort(int[] array) { 14 | int temp = 0; 15 | for(int i = 0; i < array.length; i++){ 16 | for(int j = 0; j < array.length - 1; j++){ 17 | if(array[j] > array[j + 1]){ 18 | temp = array[j]; 19 | array[j] = array[j + 1]; 20 | array[j + 1] = temp; 21 | } 22 | } 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/sort/ISort.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.sort; 2 | 3 | /** 4 | * 排序算法的接口 5 | * @author weijielu 6 | */ 7 | public interface ISort { 8 | 9 | /** 10 | * 对数组array进行升序排序 11 | * @param array 12 | */ 13 | public void sort(int[] array); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/sort/InsertOptimizeSort.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.buptdavid.datastructure.sort; 5 | 6 | /** 7 | * 插入排序优化实现 8 | * @author weijielu 9 | * 10 | */ 11 | public class InsertOptimizeSort implements ISort { 12 | 13 | @Override 14 | public void sort(int[] array) { 15 | for(int i = 1; i < array.length; i++){ 16 | int index = getInsertIndex(array, i, array[i]); 17 | 18 | if(i != index){ 19 | int j = i; 20 | int temp = array[i]; 21 | while(j > index){ 22 | array[j] = array[j - 1]; 23 | j--; 24 | } 25 | 26 | array[j] = temp; 27 | } 28 | } 29 | } 30 | 31 | /** 32 | * 使用二分查找法返回插入的位置 33 | * @param array 34 | * @param value 35 | * @return 36 | */ 37 | private int getInsertIndex(int[] array, int length, int value){ 38 | int low = 0; 39 | int high = length - 1; 40 | int middle = -1; 41 | 42 | while(low <= high){ 43 | middle = (low + high) / 2; 44 | 45 | if(array[middle] > value){ 46 | high = middle - 1; 47 | }else if(array[middle] < value){ 48 | low = middle + 1; 49 | }else{ 50 | return middle; 51 | } 52 | } 53 | 54 | if(array[middle] <= value){ 55 | middle++; 56 | } 57 | 58 | return middle; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/sort/InsertSort.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.buptdavid.datastructure.sort; 5 | 6 | /** 7 | * 插入排序实现 8 | * @author weijielu 9 | * 10 | */ 11 | public class InsertSort implements ISort { 12 | 13 | @Override 14 | public void sort(int[] array) { 15 | 16 | for(int i = 1; i < array.length; i++){ 17 | int temp = array[i]; 18 | int j = i - 1; 19 | while(j >= 0 && array[j] > temp){ 20 | array[j + 1] = array[j]; 21 | j--; 22 | } 23 | 24 | if(j != i - 1){ 25 | array[j + 1] = temp; 26 | } 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/sort/MergeSort.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.sort; 2 | 3 | /** 4 | * 归并排序
5 | * 时间复杂度: 平均情况与最差情况都是O(nlog(n))
6 | * 空间复杂度: It Depends 7 | * @author weijielu 8 | * @see ISort 9 | * @see SortTest 10 | */ 11 | public class MergeSort implements ISort { 12 | 13 | public void sort(int[] array) { 14 | mergeSort(array, 0, array.length - 1); 15 | } 16 | 17 | /** 18 | * 从索引low到high归并排序数组array 19 | * @param array 20 | * @param low 21 | * @param high 22 | */ 23 | private void mergeSort(int[] array, int low, int high){ 24 | if(low < high){ 25 | int middle = (low + high)/2; 26 | mergeSort(array, low, middle); 27 | mergeSort(array, middle + 1, high); 28 | 29 | merge(array, low, middle, high); 30 | } 31 | } 32 | 33 | /** 34 | * 归并array 35 | * @param array 36 | * @param low 37 | * @param middle 38 | * @param high 39 | */ 40 | private void merge(int[] array, int low, int middle, int high){ 41 | // 辅助数组 42 | int[] helper = new int[array.length]; 43 | for(int i = 0; i <= high; i++){ 44 | helper[i] = array[i]; 45 | } 46 | 47 | int helperLeft = low; 48 | int helperRight = middle + 1; 49 | int current = low; 50 | 51 | /** 52 | * 迭代访问helper数组,比较左右两半元素 53 | * 并将较小的元素复制到原先的数组中 54 | */ 55 | while(helperLeft <= middle && helperRight <= high){ 56 | if(helper[helperLeft] <= helper[helperRight]){ 57 | array[current] = helper[helperLeft]; 58 | helperLeft++; 59 | } else{ 60 | array[current] = helper[helperRight]; 61 | helperRight++; 62 | } 63 | current++; 64 | } 65 | 66 | /** 67 | * 将数组左半剩余元素复制到原先的数组中 68 | */ 69 | int remaining = middle - helperLeft; 70 | for(int i = 0; i <= remaining; i++){ 71 | array[current + i] = helper[helperLeft + i]; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/sort/QuickSort.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.sort; 2 | 3 | /** 4 | * 快速排序
5 | * 时间复杂度: 平均情况是O(nlog(n)),最差情况是O(n^2)
6 | * 空间复杂度: O(nlog(n)) 7 | * @author weijielu 8 | * @see ISort 9 | * @see SortTest 10 | */ 11 | public class QuickSort implements ISort { 12 | 13 | public void sort(int[] array) { 14 | quickSort(array, 0, array.length - 1); 15 | } 16 | 17 | /** 18 | * 从left到right排序数组array 19 | * @param array 20 | * @param left 21 | * @param right 22 | */ 23 | private void quickSort(int[] array, int left, int right){ 24 | int index = partition(array, left, right); 25 | if(left < index - 1){ 26 | quickSort(array, left, index - 1); 27 | } 28 | if(index + 1 < right){ 29 | quickSort(array, index, right); 30 | } 31 | } 32 | 33 | /** 34 | * 找出一个基准点,排列数组array左边的都小于它,右边的都大于它 35 | * @param array 36 | * @param left 37 | * @param right 38 | * @return 基准值数组索引 39 | */ 40 | private int partition(int[] array, int left, int right){ 41 | int pivot = array[(left + right) / 2]; 42 | int temp; 43 | 44 | while(left < right){ 45 | while(array[left] < pivot) left++; 46 | while(array[right] > pivot) right--; 47 | 48 | if(left < right){ 49 | temp = array[left]; 50 | array[left] = array[right]; 51 | array[right] = temp; 52 | left++; 53 | right--; 54 | } 55 | } 56 | 57 | return left; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/sort/SelectionSort.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.sort; 2 | 3 | /** 4 | * 选择排序
5 | * 时间复杂度: 平均情况与最差情况都是O(n^2)
6 | * 空间复杂度: O(1) 7 | * @author weijielu 8 | * @see ISort 9 | * @see SortTest 10 | */ 11 | public class SelectionSort implements ISort { 12 | 13 | public void sort(int[] array) { 14 | int temp = 0; 15 | 16 | for(int i = 0; i < array.length; i++){ 17 | temp = array[i]; 18 | for(int j = i; j < array.length; j++){ 19 | if(temp > array[j]){ 20 | temp = array[j]; 21 | } 22 | } 23 | 24 | if(temp != array[i]){ 25 | array[i] = temp; 26 | } 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/stack/Hannotower.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.stack; 2 | 3 | /** 4 | * 经典的汉诺塔问题,3根柱子,N个大小不同的盘子开始由下到上依次变小摞在第一个柱子上
5 | * 实现汉诺算法,将N个盘子以相同的顺序搁到第三根柱子上 6 | * @author weijielu 7 | * 8 | */ 9 | public class Hannotower { 10 | 11 | /** 12 | * 封装柱子为一个内部类 13 | */ 14 | public static class Tower{ 15 | private Stack disks; 16 | private char name; 17 | 18 | public Tower(char name){ 19 | disks = new Stack(); 20 | this.name = name; 21 | } 22 | 23 | public char name(){ 24 | return this.name; 25 | } 26 | 27 | /** 28 | * 向此柱子上添加盘子d 29 | * @param d 30 | */ 31 | public void add(int d){ 32 | if(!disks.isEmpty() && disks.peek() <= d){ 33 | System.out.println("不能将盘子 " + d + " 放入此柱子上"); 34 | }else{ 35 | disks.push(d); 36 | } 37 | } 38 | 39 | /** 40 | * 将此柱子顶部的盘子移到柱子t上 41 | * @param t 42 | */ 43 | public void moveTopTo(Tower t){ 44 | int top = disks.pop(); 45 | t.add(top); 46 | System.out.println("将盘子 " + top + "从柱子 " + name() +" 移动 到柱子 " + t.name()); 47 | } 48 | 49 | /** 50 | * 将n个盘子从此柱子依靠缓冲柱子buffer移到柱子destination 51 | * 52 | * @param n 53 | * @param destination 54 | * @param buffer 55 | */ 56 | public void moveDisks(int n, Tower destination, Tower buffer){ 57 | if(n > 0){ 58 | // 先将n-1个盘子从此柱子依靠缓冲柱子destination移到柱子buffer 59 | moveDisks(n - 1, buffer, destination); 60 | // 然后将剩下的盘子n移到柱子destination上 61 | moveTopTo(destination); 62 | // 最后将n-1个盘子从buffer依靠本身缓冲移到柱子destination 63 | buffer.moveDisks(n - 1, destination, this); 64 | } 65 | } 66 | } 67 | 68 | 69 | 70 | /** 71 | * @param args 72 | */ 73 | public static void main(String[] args) { 74 | // 三根柱子 75 | int n = 3; 76 | Tower[] towers = new Tower[n]; 77 | towers[0] = new Tower('A'); 78 | towers[1] = new Tower('B'); 79 | towers[2] = new Tower('C'); 80 | 81 | // 10个盘子 82 | int diskCount = 10; 83 | for(int i = diskCount; i > 0; i--){ 84 | towers[0].add(i); 85 | } 86 | towers[0].moveDisks(diskCount, towers[2], towers[1]); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/stack/IStack.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.stack; 2 | 3 | /** 4 | * 栈的接口 5 | * @author weijielu 6 | * @see Stack 7 | * @see SetOfStacks 8 | * @see StackWithMin 9 | * @see StackTest 10 | */ 11 | public interface IStack { 12 | 13 | /** 14 | * 入栈操作 15 | * @param item 16 | */ 17 | void push(T item); 18 | 19 | /** 20 | * 出栈操作 21 | * @return 22 | */ 23 | T pop(); 24 | 25 | /** 26 | * 返回栈顶元素,但不出栈 27 | * @return 28 | */ 29 | T peek(); 30 | 31 | /** 32 | * 栈是否为空 33 | * @return boolean 34 | */ 35 | boolean isEmpty(); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/stack/SetOfStacks.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.stack; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.buptdavid.datastructure.Node; 7 | 8 | 9 | /** 10 | * 此类用来表示若干具有一定容量的栈的集合
11 | * 当第一个栈push满后,push第二个栈,以此类推
12 | * 当最后一个栈pop空后,pop倒数第二个栈,依次类推
13 | * 14 | * @author weijielu 15 | * @see StackTest 16 | * @see IStack 17 | * @see Node 18 | */ 19 | public class SetOfStacks implements IStack { 20 | List> stacks = new ArrayList>(); 21 | 22 | public static int index = -1; 23 | private int capacity; 24 | 25 | public SetOfStacks(int capacity) { 26 | this.capacity = capacity; 27 | } 28 | 29 | public void push(T item) { 30 | StackCapacity last = getLastStack(); 31 | if (last != null && !last.isFull()) { 32 | last.push(item); 33 | } else { 34 | StackCapacity stack = new StackCapacity(capacity); 35 | stack.push(item); 36 | stacks.add(stack); 37 | index++; 38 | } 39 | } 40 | 41 | public T pop() { 42 | StackCapacity last = getLastStack(); 43 | T value = null; 44 | if (last != null) { 45 | value = last.pop(); 46 | if (last.getIndex() == 0) { 47 | stacks.remove(index--); 48 | } 49 | } 50 | return value; 51 | } 52 | 53 | public T peek() { 54 | StackCapacity last = getLastStack(); 55 | T value = null; 56 | if (last != null) { 57 | value = last.peek(); 58 | } 59 | return value; 60 | } 61 | 62 | public boolean isEmpty() { 63 | StackCapacity last = getLastStack(); 64 | return (last == null); 65 | } 66 | 67 | /** 68 | * 返回最后的栈 69 | * 70 | * @return 71 | */ 72 | private StackCapacity getLastStack() { 73 | if (stacks.size() == 0) { 74 | return null; 75 | } else { 76 | return stacks.get(index); 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/stack/Stack.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.stack; 2 | 3 | import org.buptdavid.datastructure.Node; 4 | 5 | /** 6 | * 栈的实现 7 | * @author weijielu 8 | * @see StackTest 9 | * @see IStack 10 | * @see Node 11 | */ 12 | public class Stack implements IStack{ 13 | Node top; 14 | 15 | public T pop(){ 16 | if(top != null){ 17 | T item = top.data; 18 | top = top.next; 19 | return item; 20 | } 21 | 22 | return null; 23 | } 24 | 25 | public void push(T item){ 26 | Node t = new Node(item); 27 | t.next = top; 28 | top = t; 29 | } 30 | 31 | public T peek(){ 32 | if(top != null){ 33 | return top.data; 34 | } 35 | return null; 36 | } 37 | 38 | 39 | public boolean isEmpty(){ 40 | return (top == null); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/stack/StackCapacity.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.stack; 2 | 3 | /** 4 | * 记录栈的最大存储容量和栈中内容实际索引值 5 | * 6 | * @author weijielu 7 | * 8 | */ 9 | public class StackCapacity extends Stack { 10 | private int capacity; 11 | private int index = 0; 12 | 13 | public int getIndex() { 14 | return index; 15 | } 16 | 17 | public void setIndex(int index) { 18 | this.index = index; 19 | } 20 | 21 | public StackCapacity(int capacity) { 22 | this.capacity = capacity; 23 | } 24 | 25 | public void push(T data) { 26 | super.push(data); 27 | index++; 28 | } 29 | 30 | public T pop() { 31 | index--; 32 | return super.pop(); 33 | } 34 | 35 | public boolean isFull() { 36 | return (index == capacity); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/stack/StackWithMin.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.stack; 2 | 3 | import org.buptdavid.datastructure.Node; 4 | 5 | 6 | /** 7 | * 一个能随时获取栈中最小值的栈的实现 8 | * 9 | * @author weijielu 10 | * @see StackTest 11 | * @see IStack 12 | * @see Node 13 | */ 14 | public class StackWithMin extends Stack { 15 | Stack stackMin; 16 | 17 | public StackWithMin(){ 18 | stackMin = new Stack(); 19 | } 20 | 21 | public void push(Integer item){ 22 | if(item <= min()){ 23 | stackMin.push(item); 24 | } 25 | super.push(item); 26 | } 27 | 28 | public Integer pop(){ 29 | int value = super.pop(); 30 | if(value == min()){ 31 | stackMin.pop(); 32 | } 33 | return value; 34 | } 35 | 36 | /** 37 | * 取得栈中的最小值 38 | * @return 39 | */ 40 | public Integer min(){ 41 | if(stackMin.isEmpty()){ 42 | return Integer.MAX_VALUE; 43 | }else{ 44 | return stackMin.peek(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/string/StringEqual.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.string; 2 | 3 | public class StringEqual { 4 | 5 | /** 6 | * 字符串比较 7 | * @author weijielu 8 | */ 9 | public static void main(String[] args) { 10 | // s1和s2被分配到永久区(方法区)的运行时常量池的相同的内存 11 | String s1 = "abc"; 12 | String s2 = "abc"; 13 | 14 | // s3和s4被分配到堆中的两个不同对象 15 | String s3 = new String("abc"); 16 | String s4 = new String("abc"); 17 | 18 | System.out.println(s1 == s2); 19 | System.out.println(s1.equals(s2)); 20 | 21 | System.out.println(s3 == s4); 22 | System.out.println(s3.equals(s4)); 23 | 24 | System.out.println(s1 == s3); 25 | System.out.println(s1.equals(s3)); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/ChopStickLocked.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | /** 7 | * 哲学家就餐问题的筷子 8 | * @author weijielu 9 | * @see PhilosopherLocked 10 | * @see PhilosopherLockedEat 11 | */ 12 | public class ChopStickLocked { 13 | /* 锁 */ 14 | protected Lock lock; 15 | 16 | public ChopStickLocked(){ 17 | lock = new ReentrantLock(); 18 | } 19 | 20 | /** 21 | * 拿起筷子 22 | * @return 23 | */ 24 | public boolean pickUp(){ 25 | lock.lock(); 26 | // try { 27 | // int sleepTime = (int)(Math.random() * 500 + 10); 28 | // Thread.sleep(sleepTime); 29 | // } catch (InterruptedException e) { 30 | // e.printStackTrace(); 31 | // } 32 | return true; 33 | } 34 | 35 | /** 36 | * 放下筷子 37 | */ 38 | public boolean putDown(){ 39 | lock.unlock(); 40 | // try { 41 | // int sleepTime = (int)(Math.random() * 500 + 10); 42 | // Thread.sleep(sleepTime); 43 | // } catch (InterruptedException e) { 44 | // e.printStackTrace(); 45 | // } 46 | 47 | return true; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/ChopStickUnLocked.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * 5 | * @author weijielu 6 | */ 7 | public class ChopStickUnLocked extends ChopStickLocked { 8 | public ChopStickUnLocked(){ 9 | super(); 10 | } 11 | 12 | public boolean pickUp(){ 13 | return lock.tryLock(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/ExtendThread.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * 继承Thread实现线程类 5 | * @author weijielu 6 | * @see ExtendThreadRun 7 | */ 8 | public class ExtendThread extends Thread { 9 | int count = 0; 10 | 11 | public void run(){ 12 | try{ 13 | while(count < 5){ 14 | Thread.sleep(250); 15 | System.out.println("In Thread, count is " + count); 16 | count++; 17 | } 18 | } catch (InterruptedException e) { 19 | System.out.println("Thread interrupted."); 20 | } 21 | System.out.println("Thread terminating."); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/ExtendThreadRun.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * RunExtendThread 5 | * @author weijielu 6 | * @see ExtendThread 7 | */ 8 | public class ExtendThreadRun { 9 | 10 | public static void main(String args[]){ 11 | ExtendThread instance = new ExtendThread(); 12 | instance.start(); 13 | 14 | while(instance.count != 5){ 15 | try{ 16 | Thread.sleep(250); 17 | } catch(InterruptedException e){ 18 | e.printStackTrace(); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/LockedATM.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | import java.util.concurrent.locks.Lock; 4 | import java.util.concurrent.locks.ReentrantLock; 5 | 6 | /** 7 | * 实现锁的ATM的取款与存款 8 | * @author weijielu 9 | * @see LockedATMThread 10 | */ 11 | public class LockedATM { 12 | private Lock lock; 13 | private int balance = 10000; 14 | 15 | public LockedATM(){ 16 | lock = new ReentrantLock(); 17 | } 18 | 19 | /** 20 | * 取款value 21 | * @param value 22 | * @return 取款后的余额 23 | */ 24 | public Integer withDraw(int value){ 25 | System.out.println("准备取款: " + value); 26 | 27 | lock.lock(); 28 | 29 | Integer temp = null; 30 | if(value > balance){ 31 | System.out.println("余额不足"); 32 | temp = null; 33 | }else{ 34 | temp = balance; 35 | try{ 36 | Thread.sleep(300); 37 | temp = temp - value; 38 | Thread.sleep(200); 39 | balance = temp; 40 | } catch (InterruptedException e){ 41 | e.printStackTrace(); 42 | } 43 | } 44 | 45 | lock.unlock(); 46 | 47 | return temp; 48 | } 49 | 50 | /** 51 | * 存款value 52 | * @param value 存款后的余额 53 | * @return 54 | */ 55 | public Integer deposit(int value){ 56 | System.out.println("准备存款: " + value); 57 | 58 | lock.lock(); 59 | 60 | Integer temp = balance; 61 | try{ 62 | Thread.sleep(300); 63 | temp = temp + value; 64 | Thread.sleep(200); 65 | balance = temp; 66 | } catch (InterruptedException e){ 67 | e.printStackTrace(); 68 | } 69 | 70 | lock.unlock(); 71 | 72 | return temp; 73 | } 74 | 75 | /** 76 | * @param args 77 | */ 78 | public static void main(String[] args) { 79 | LockedATM atm = new LockedATM(); 80 | LockedATMThread thread1 = new LockedATMThread(atm); 81 | LockedATMThread thread2 = new LockedATMThread(atm); 82 | LockedATMThread thread3 = new LockedATMThread(atm); 83 | LockedATMThread thread4 = new LockedATMThread(atm); 84 | 85 | thread1.start(); 86 | thread2.start(); 87 | thread3.start(); 88 | thread4.start(); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/LockedATMThread.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * LockedATM线程 5 | * @author weijielu 6 | * @see LockedATM 7 | */ 8 | public class LockedATMThread extends Thread{ 9 | private LockedATM atm; 10 | 11 | public LockedATMThread(LockedATM atm){ 12 | this.atm = atm; 13 | } 14 | 15 | public void run(){ 16 | atm.deposit(200); 17 | atm.withDraw(700); 18 | atm.deposit(500); 19 | atm.withDraw(600); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/PhilosopherLocked.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * 哲学家就餐问题的 会死锁的 哲学家 5 | * @author weijielu 6 | * @see ChopStickLocked 7 | * @see PhilosopherLockedEat 8 | */ 9 | public class PhilosopherLocked extends Thread { 10 | private int bites = 100; 11 | protected ChopStickLocked left; 12 | protected ChopStickLocked right; 13 | public String name; 14 | 15 | public PhilosopherLocked(String name, ChopStickLocked left, ChopStickLocked right){ 16 | this.name = name; 17 | this.left = left; 18 | this.right = right; 19 | } 20 | 21 | public void eat(){ 22 | pickUp(); 23 | chew(); 24 | putDown(); 25 | } 26 | 27 | /** 28 | * 哲学家分别拿起左右手的筷子 29 | * @return 30 | */ 31 | public boolean pickUp(){ 32 | System.out.println("哲学家 " + name + " 准备拿左筷子..."); 33 | left.pickUp(); 34 | System.out.println("哲学家 " + name + " 拿起了左筷子"); 35 | System.out.println("哲学家 " + name + " 准备拿右筷子..."); 36 | right.pickUp(); 37 | System.out.println("哲学家 " + name + " 拿起了右筷子"); 38 | return true; 39 | } 40 | 41 | /** 42 | * 哲学家开始就餐 43 | */ 44 | public void chew(){ 45 | System.out.println("哲学家 " + name + " 准备吃一口..."); 46 | int sleepTime = 0; 47 | try { 48 | sleepTime = (int)(Math.random() * 1000); 49 | Thread.sleep(sleepTime); 50 | } catch (InterruptedException e) { 51 | e.printStackTrace(); 52 | } 53 | System.out.println("哲学家 " + name + " 吃完这一口, 用时 " + sleepTime + " ms"); 54 | } 55 | 56 | /** 57 | * 哲学家分别放下右左手的筷子 58 | */ 59 | public void putDown(){ 60 | System.out.println("哲学家 " + name + " 准备放下左筷子..."); 61 | left.putDown(); 62 | System.out.println("哲学家 " + name + " 放下了左筷子"); 63 | System.out.println("哲学家 " + name + " 准备放下右筷子..."); 64 | right.putDown(); 65 | System.out.println("哲学家 " + name + " 放下了右筷子"); 66 | } 67 | 68 | public void run(){ 69 | for(int i = 0; i < bites; i++){ 70 | // try { 71 | // int sleepTime = (int)(Math.random() * 1000); 72 | // Thread.sleep(sleepTime); 73 | // } catch (InterruptedException e) { 74 | // e.printStackTrace(); 75 | // } 76 | eat(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/PhilosopherLockedEat.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * 十个死锁哲学家就餐 5 | * @author weijielu 6 | * @see ChopStickLocked 7 | * @see PhilosopherLocked 8 | */ 9 | public class PhilosopherLockedEat { 10 | 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | ChopStickLocked chopStick1 = new ChopStickLocked(); 16 | ChopStickLocked chopStick2 = new ChopStickLocked(); 17 | PhilosopherLocked philosopherA = new PhilosopherLocked("A", chopStick1, chopStick2); 18 | ChopStickLocked chopStick3 = new ChopStickLocked(); 19 | PhilosopherLocked philosopherB = new PhilosopherLocked("B", chopStick2, chopStick3); 20 | ChopStickLocked chopStick4 = new ChopStickLocked(); 21 | PhilosopherLocked philosopherC = new PhilosopherLocked("C", chopStick3, chopStick4); 22 | ChopStickLocked chopStick5 = new ChopStickLocked(); 23 | PhilosopherLocked philosopherD = new PhilosopherLocked("D", chopStick4, chopStick5); 24 | ChopStickLocked chopStick6 = new ChopStickLocked(); 25 | PhilosopherLocked philosopherE = new PhilosopherLocked("E", chopStick5, chopStick6); 26 | ChopStickLocked chopStick7 = new ChopStickLocked(); 27 | PhilosopherLocked philosopherF = new PhilosopherLocked("F", chopStick6, chopStick7); 28 | ChopStickLocked chopStick8 = new ChopStickLocked(); 29 | PhilosopherLocked philosopherG = new PhilosopherLocked("G", chopStick7, chopStick8); 30 | ChopStickLocked chopStick9 = new ChopStickLocked(); 31 | PhilosopherLocked philosopherH = new PhilosopherLocked("H", chopStick8, chopStick9); 32 | ChopStickLocked chopStick10 = new ChopStickLocked(); 33 | PhilosopherLocked philosopherI = new PhilosopherLocked("I", chopStick9, chopStick10); 34 | 35 | PhilosopherLocked philosopherJ = new PhilosopherLocked("J", chopStick10, chopStick1); 36 | 37 | philosopherA.start(); 38 | philosopherB.start(); 39 | philosopherC.start(); 40 | philosopherD.start(); 41 | philosopherE.start(); 42 | philosopherF.start(); 43 | philosopherG.start(); 44 | philosopherH.start(); 45 | philosopherI.start(); 46 | philosopherJ.start(); 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/PhilosopherUnLocked.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * 哲学家就餐问题的 不会死锁的 哲学家 5 | * @author weijielu 6 | * @see ChopStickUnLocked 7 | * @see PhilosopherUnLockedEat 8 | */ 9 | public class PhilosopherUnLocked extends PhilosopherLocked { 10 | 11 | public PhilosopherUnLocked(String name, ChopStickUnLocked left, ChopStickUnLocked right) { 12 | super(name, left, right); 13 | } 14 | 15 | public void eat(){ 16 | if(pickUp()){ 17 | chew(); 18 | putDown(); 19 | } 20 | } 21 | 22 | public boolean pickUp(){ 23 | System.out.println("哲学家 " + name + " 准备拿左筷子..."); 24 | if(!left.pickUp()){ 25 | System.out.println("哲学家 " + name + " 放弃拿左筷子"); 26 | return false; 27 | } 28 | 29 | System.out.println("哲学家 " + name + " 准备拿右筷子..."); 30 | if(!right.pickUp()){ 31 | System.out.println("哲学家 " + name + " 放弃拿右筷子..."); 32 | System.out.println("哲学家 " + name + " 放下左筷子..."); 33 | left.putDown(); 34 | return false; 35 | } 36 | return true; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/PhilosopherUnLockedEat.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * 十个不会死锁哲学家就餐 5 | * @author weijielu 6 | * @see ChopStickUnLocked 7 | * @see PhilosopherUnLocked 8 | */ 9 | public class PhilosopherUnLockedEat { 10 | 11 | /** 12 | * @param args 13 | */ 14 | public static void main(String[] args) { 15 | ChopStickUnLocked chopStick1 = new ChopStickUnLocked(); 16 | ChopStickUnLocked chopStick2 = new ChopStickUnLocked(); 17 | PhilosopherUnLocked philosopherA = new PhilosopherUnLocked("A", chopStick1, chopStick2); 18 | ChopStickUnLocked chopStick3 = new ChopStickUnLocked(); 19 | PhilosopherUnLocked philosopherB = new PhilosopherUnLocked("B", chopStick2, chopStick3); 20 | ChopStickUnLocked chopStick4 = new ChopStickUnLocked(); 21 | PhilosopherUnLocked philosopherC = new PhilosopherUnLocked("C", chopStick3, chopStick4); 22 | ChopStickUnLocked chopStick5 = new ChopStickUnLocked(); 23 | PhilosopherUnLocked philosopherD = new PhilosopherUnLocked("D", chopStick4, chopStick5); 24 | ChopStickUnLocked chopStick6 = new ChopStickUnLocked(); 25 | PhilosopherUnLocked philosopherE = new PhilosopherUnLocked("E", chopStick5, chopStick6); 26 | ChopStickUnLocked chopStick7 = new ChopStickUnLocked(); 27 | PhilosopherUnLocked philosopherF = new PhilosopherUnLocked("F", chopStick6, chopStick7); 28 | ChopStickUnLocked chopStick8 = new ChopStickUnLocked(); 29 | PhilosopherUnLocked philosopherG = new PhilosopherUnLocked("G", chopStick7, chopStick8); 30 | ChopStickUnLocked chopStick9 = new ChopStickUnLocked(); 31 | PhilosopherUnLocked philosopherH = new PhilosopherUnLocked("H", chopStick8, chopStick9); 32 | ChopStickUnLocked chopStick10 = new ChopStickUnLocked(); 33 | PhilosopherUnLocked philosopherI = new PhilosopherUnLocked("I", chopStick9, chopStick10); 34 | 35 | PhilosopherUnLocked philosopherJ = new PhilosopherUnLocked("J", chopStick10, chopStick1); 36 | 37 | philosopherA.start(); 38 | philosopherB.start(); 39 | philosopherC.start(); 40 | philosopherD.start(); 41 | philosopherE.start(); 42 | philosopherF.start(); 43 | philosopherG.start(); 44 | philosopherH.start(); 45 | philosopherI.start(); 46 | philosopherJ.start(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/RunableThread.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * 实现接口Runnable来实现线程类 5 | * @author weijielu 6 | */ 7 | public class RunableThread implements Runnable{ 8 | public int count = 0; 9 | 10 | public void run() { 11 | System.out.println("RunnableThread starting....."); 12 | try{ 13 | while(count < 5){ 14 | Thread.sleep(500); 15 | System.out.println("In Thread, count is " + count); 16 | count++; 17 | } 18 | } catch (InterruptedException e){ 19 | System.out.println("RunnableThread interrupted."); 20 | } 21 | 22 | System.out.println("RunnableThread terminating."); 23 | } 24 | 25 | /** 26 | * @param args 27 | */ 28 | public static void main(String[] args) { 29 | RunableThread instance = new RunableThread(); 30 | Thread thread = new Thread(instance); 31 | thread.start(); 32 | 33 | while(instance.count != 5){ 34 | try{ 35 | Thread.sleep(250); 36 | } catch(InterruptedException e){ 37 | e.printStackTrace(); 38 | } 39 | } 40 | 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/SynchronizedObject.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * 同步对象 5 | * @author weijielu 6 | * @see SynchronizedThread 7 | */ 8 | public class SynchronizedObject { 9 | public synchronized void syn(String name){ 10 | try{ 11 | System.out.println("Thread " + name + ".syn(): starting."); 12 | Thread.sleep(3000); 13 | System.out.println("Thread " + name + ".syn(): ending."); 14 | } catch (InterruptedException e){ 15 | System.out.println("Thread " + name + ": interrupted."); 16 | } 17 | } 18 | 19 | public static void main(String[] args) throws InterruptedException{ 20 | System.out.println("Different SynchronizedObject"); 21 | SynchronizedObject sObject1 = new SynchronizedObject(); 22 | SynchronizedObject sObject2 = new SynchronizedObject(); 23 | SynchronizedThread sThread1 = new SynchronizedThread(sObject1, "1"); 24 | SynchronizedThread sThread2 = new SynchronizedThread(sObject2, "2"); 25 | 26 | Thread thread1 = new Thread(sThread1); 27 | thread1.start(); 28 | Thread thread2 = new Thread(sThread2); 29 | thread2.start(); 30 | 31 | Thread.sleep(7000); 32 | 33 | System.out.println(); 34 | System.out.println("Same SynchronizedObject"); 35 | SynchronizedObject sObject3 = new SynchronizedObject(); 36 | SynchronizedThread sThread3 = new SynchronizedThread(sObject3, "3"); 37 | SynchronizedThread sThread4 = new SynchronizedThread(sObject3, "4"); 38 | Thread thread3 = new Thread(sThread3); 39 | thread3.start(); 40 | Thread thread4 = new Thread(sThread4); 41 | thread4.start(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/SynchronizedThread.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread; 2 | 3 | /** 4 | * Synichronized线程 5 | * @author weijielu 6 | * @see SynchronizedObject 7 | */ 8 | public class SynchronizedThread implements Runnable{ 9 | private String name; 10 | private SynchronizedObject sObject; 11 | 12 | public SynchronizedThread(SynchronizedObject sObject, String name){ 13 | this.sObject = sObject; 14 | this.name = name; 15 | } 16 | 17 | public void run() { 18 | sObject.syn(name); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/lockcondition/Bank.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread.lockcondition; 2 | import java.util.concurrent.locks.*; 3 | 4 | /** 5 | * A bank with a number of bank accounts that uses locks for serializing access. 6 | * @version 1.30 2004-08-01 7 | * @author Cay Horstmann 8 | */ 9 | public class Bank 10 | { 11 | /** 12 | * Constructs the bank. 13 | * @param n the number of accounts 14 | * @param initialBalance the initial balance for each account 15 | */ 16 | public Bank(int n, double initialBalance) 17 | { 18 | accounts = new double[n]; 19 | for (int i = 0; i < accounts.length; i++) 20 | accounts[i] = initialBalance; 21 | bankLock = new ReentrantLock(); 22 | sufficientFunds = bankLock.newCondition(); 23 | } 24 | 25 | /** 26 | * Transfers money from one account to another. 27 | * @param from the account to transfer from 28 | * @param to the account to transfer to 29 | * @param amount the amount to transfer 30 | */ 31 | public void transfer(int from, int to, double amount) throws InterruptedException 32 | { 33 | bankLock.lock(); 34 | try 35 | { 36 | while (accounts[from] < amount) 37 | sufficientFunds.await(); 38 | System.out.print(Thread.currentThread()); 39 | accounts[from] -= amount; 40 | System.out.printf(" %10.2f from %d to %d", amount, from, to); 41 | accounts[to] += amount; 42 | System.out.printf(" Total Balance: %10.2f%n", getTotalBalance()); 43 | sufficientFunds.signalAll(); 44 | } 45 | finally 46 | { 47 | bankLock.unlock(); 48 | } 49 | } 50 | 51 | /** 52 | * Gets the sum of all account balances. 53 | * @return the total balance 54 | */ 55 | public double getTotalBalance() 56 | { 57 | // bankLock.lock(); 58 | try 59 | { 60 | double sum = 0; 61 | 62 | for (double a : accounts) 63 | sum += a; 64 | 65 | return sum; 66 | } 67 | finally 68 | { 69 | // bankLock.unlock(); 70 | } 71 | } 72 | 73 | /** 74 | * Gets the number of accounts in the bank. 75 | * @return the number of accounts 76 | */ 77 | public int size() 78 | { 79 | return accounts.length; 80 | } 81 | 82 | private final double[] accounts; 83 | private Lock bankLock; 84 | private Condition sufficientFunds; 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/lockcondition/SynchBankTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread.lockcondition; 2 | /** 3 | * This program shows how multiple threads can safely access a data structure. 4 | * @version 1.30 2004-08-01 5 | * @author Cay Horstmann 6 | */ 7 | public class SynchBankTest 8 | { 9 | public static void main(String[] args) 10 | { 11 | Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE); 12 | int i; 13 | for (i = 0; i < NACCOUNTS; i++) 14 | { 15 | TransferRunnable r = new TransferRunnable(b, i, INITIAL_BALANCE); 16 | Thread t = new Thread(r); 17 | t.start(); 18 | } 19 | } 20 | 21 | public static final int NACCOUNTS = 100; 22 | public static final double INITIAL_BALANCE = 1000; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/lockcondition/TransferRunnable.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread.lockcondition; 2 | /** 3 | * A runnable that transfers money from an account to other accounts in a bank. 4 | * @version 1.30 2004-08-01 5 | * @author Cay Horstmann 6 | */ 7 | public class TransferRunnable implements Runnable 8 | { 9 | /** 10 | * Constructs a transfer runnable. 11 | * @param b the bank between whose account money is transferred 12 | * @param from the account to transfer money from 13 | * @param max the maximum amount of money in each transfer 14 | */ 15 | public TransferRunnable(Bank b, int from, double max) 16 | { 17 | bank = b; 18 | fromAccount = from; 19 | maxAmount = max; 20 | } 21 | 22 | public void run() 23 | { 24 | try 25 | { 26 | while (true) 27 | { 28 | int toAccount = (int) (bank.size() * Math.random()); 29 | double amount = maxAmount * Math.random(); 30 | bank.transfer(fromAccount, toAccount, amount); 31 | Thread.sleep((int) (DELAY * Math.random())); 32 | } 33 | } 34 | catch (InterruptedException e) 35 | { 36 | } 37 | } 38 | 39 | private Bank bank; 40 | private int fromAccount; 41 | private double maxAmount; 42 | private int DELAY = 10; 43 | } -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/threadpool/ThreadPoolTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread.threadpool; 2 | import java.io.*; 3 | import java.util.*; 4 | import java.util.concurrent.*; 5 | 6 | /** 7 | * @version 1.0 2004-08-01 8 | * @author Cay Horstmann 9 | */ 10 | public class ThreadPoolTest 11 | { 12 | public static void main(String[] args) throws Exception 13 | { 14 | Scanner in = new Scanner(System.in); 15 | System.out.print("Enter base directory (e.g. /usr/local/jdk5.0/src): "); 16 | String directory = in.nextLine(); 17 | System.out.print("Enter keyword (e.g. volatile): "); 18 | String keyword = in.nextLine(); 19 | 20 | ExecutorService pool = Executors.newCachedThreadPool(); 21 | 22 | MatchCounter counter = new MatchCounter(new File(directory), keyword, pool); 23 | Future result = pool.submit(counter); 24 | 25 | try 26 | { 27 | System.out.println(result.get() + " matching files."); 28 | } 29 | catch (ExecutionException e) 30 | { 31 | e.printStackTrace(); 32 | } 33 | catch (InterruptedException e) 34 | { 35 | } 36 | pool.shutdown(); 37 | 38 | int largestPoolSize = ((ThreadPoolExecutor) pool).getLargestPoolSize(); 39 | System.out.println("largest pool size=" + largestPoolSize); 40 | } 41 | } 42 | 43 | /** 44 | * This task counts the files in a directory and its subdirectories that contain a given keyword. 45 | */ 46 | class MatchCounter implements Callable 47 | { 48 | /** 49 | * Constructs a MatchCounter. 50 | * @param directory the directory in which to start the search 51 | * @param keyword the keyword to look for 52 | * @param pool the thread pool for submitting subtasks 53 | */ 54 | public MatchCounter(File directory, String keyword, ExecutorService pool) 55 | { 56 | this.directory = directory; 57 | this.keyword = keyword; 58 | this.pool = pool; 59 | } 60 | 61 | public Integer call() 62 | { 63 | count = 0; 64 | try 65 | { 66 | File[] files = directory.listFiles(); 67 | ArrayList> results = new ArrayList>(); 68 | 69 | for (File file : files) 70 | if (file.isDirectory()) 71 | { 72 | MatchCounter counter = new MatchCounter(file, keyword, pool); 73 | Future result = pool.submit(counter); 74 | results.add(result); 75 | } 76 | else 77 | { 78 | if (search(file)) count++; 79 | } 80 | 81 | for (Future result : results) 82 | try 83 | { 84 | count += result.get(); 85 | } 86 | catch (ExecutionException e) 87 | { 88 | e.printStackTrace(); 89 | } 90 | } 91 | catch (InterruptedException e) 92 | { 93 | } 94 | return count; 95 | } 96 | 97 | /** 98 | * Searches a file for a given keyword. 99 | * @param file the file to search 100 | * @return true if the keyword is contained in the file 101 | */ 102 | public boolean search(File file) 103 | { 104 | try 105 | { 106 | Scanner in = new Scanner(new FileInputStream(file)); 107 | boolean found = false; 108 | while (!found && in.hasNextLine()) 109 | { 110 | String line = in.nextLine(); 111 | if (line.contains(keyword)) found = true; 112 | } 113 | in.close(); 114 | return found; 115 | } 116 | catch (IOException e) 117 | { 118 | return false; 119 | } 120 | } 121 | 122 | private File directory; 123 | private String keyword; 124 | private ExecutorService pool; 125 | private int count; 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/usesynchronized/Bank.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread.usesynchronized; 2 | 3 | /** 4 | * A bank with a number of bank accounts that uses synchronization primitives. 5 | * @version 1.30 2004-08-01 6 | * @author Cay Horstmann 7 | */ 8 | public class Bank 9 | { 10 | /** 11 | * Constructs the bank. 12 | * @param n the number of accounts 13 | * @param initialBalance the initial balance for each account 14 | */ 15 | public Bank(int n, double initialBalance) 16 | { 17 | accounts = new double[n]; 18 | for (int i = 0; i < accounts.length; i++) 19 | accounts[i] = initialBalance; 20 | } 21 | 22 | /** 23 | * Transfers money from one account to another. 24 | * @param from the account to transfer from 25 | * @param to the account to transfer to 26 | * @param amount the amount to transfer 27 | */ 28 | public synchronized void transfer(int from, int to, double amount) throws InterruptedException 29 | { 30 | while (accounts[from] < amount) 31 | wait(); 32 | System.out.print(Thread.currentThread()); 33 | accounts[from] -= amount; 34 | System.out.printf(" %10.2f from %d to %d", amount, from, to); 35 | accounts[to] += amount; 36 | System.out.printf(" Total Balance: %10.2f%n", getTotalBalance()); 37 | notifyAll(); 38 | } 39 | 40 | /** 41 | * Gets the sum of all account balances. 42 | * @return the total balance 43 | */ 44 | public synchronized double getTotalBalance() 45 | { 46 | double sum = 0; 47 | 48 | for (double a : accounts) 49 | sum += a; 50 | 51 | return sum; 52 | } 53 | 54 | /** 55 | * Gets the number of accounts in the bank. 56 | * @return the number of accounts 57 | */ 58 | public int size() 59 | { 60 | return accounts.length; 61 | } 62 | 63 | private final double[] accounts; 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/usesynchronized/SynchBankTest2.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread.usesynchronized; 2 | 3 | import java.util.Vector; 4 | 5 | /** 6 | * This program shows how multiple threads can safely access a data structure, using synchronized 7 | * methods. 8 | * @version 1.30 2004-08-01 9 | * @author Cay Horstmann 10 | */ 11 | public class SynchBankTest2 12 | { 13 | public static void main(String[] args) 14 | { 15 | Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE); 16 | int i; 17 | for (i = 0; i < NACCOUNTS; i++) 18 | { 19 | TransferRunnable r = new TransferRunnable(b, i, INITIAL_BALANCE); 20 | Thread t = new Thread(r); 21 | t.start(); 22 | } 23 | } 24 | 25 | public static final int NACCOUNTS = 100; 26 | public static final double INITIAL_BALANCE = 1000; 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/thread/usesynchronized/TransferRunnable.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.thread.usesynchronized; 2 | /** 3 | * A runnable that transfers money from an account to other accounts in a bank. 4 | * @version 1.30 2004-08-01 5 | * @author Cay Horstmann 6 | */ 7 | public class TransferRunnable implements Runnable 8 | { 9 | /** 10 | * Constructs a transfer runnable. 11 | * @param b the bank between whose account money is transferred 12 | * @param from the account to transfer money from 13 | * @param max the maximum amount of money in each transfer 14 | */ 15 | public TransferRunnable(Bank b, int from, double max) 16 | { 17 | bank = b; 18 | fromAccount = from; 19 | maxAmount = max; 20 | } 21 | 22 | public void run() 23 | { 24 | try 25 | { 26 | while (true) 27 | { 28 | int toAccount = (int) (bank.size() * Math.random()); 29 | double amount = maxAmount * Math.random(); 30 | bank.transfer(fromAccount, toAccount, amount); 31 | Thread.sleep((int) (DELAY * Math.random())); 32 | } 33 | } 34 | catch (InterruptedException e) 35 | { 36 | } 37 | } 38 | 39 | private Bank bank; 40 | private int fromAccount; 41 | private double maxAmount; 42 | private int DELAY = 10; 43 | } -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/tree/BinarySearchTree.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.tree; 2 | 3 | /** 4 | * 二叉查找树的判断
5 | * 二叉查找树:对所有节点来说:所有左子树节点都小于等于其根节点;所有右子树节点都大于其根节点 6 | * @author weijielu 7 | * @see BinarySearchTreeTest 8 | * @see TreeNode 9 | */ 10 | public class BinarySearchTree { 11 | 12 | /** 13 | * Check root左子树所有节点小于等于max,root右子树所有节点大于min 14 | * 15 | * @param root 16 | * @param min 17 | * @param max 18 | * @return 19 | */ 20 | private static boolean checkBSTMinMax(TreeNode root, Integer min, Integer max){ 21 | if(root == null){ 22 | return true; 23 | } 24 | 25 | if(root.data > max || root.data <= min){ 26 | return false; 27 | } 28 | 29 | if(!checkBSTMinMax(root.left, min, root.data) || !checkBSTMinMax(root.right, root.data, max)){ 30 | return false; 31 | } 32 | 33 | return true; 34 | } 35 | 36 | /** 37 | * Check root是否二叉查找树 38 | * @param root 39 | * @return 40 | */ 41 | public static boolean checkBST(TreeNode root){ 42 | return checkBSTMinMax(root, Integer.MIN_VALUE, Integer.MAX_VALUE); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/tree/CheckBalanceTree.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.tree; 2 | 3 | /** 4 | * 检查是否平衡树,此处平衡树的定义是两棵子树的高度差不超过1 5 | * @author weijielu 6 | * @see CheckBalanceTreeTest 7 | * @see TreeNode 8 | */ 9 | public class CheckBalanceTree { 10 | 11 | /** 12 | * 返回树的高度 13 | * @param root 14 | * @return 15 | */ 16 | private static int getHeight(TreeNode root){ 17 | if(root == null){ 18 | return 0; 19 | } 20 | 21 | return Math.max(getHeight(root.left), getHeight(root.right)) + 1; 22 | } 23 | 24 | /** 25 | * 判断树是否平衡
26 | * 此方法时间复杂度为O(NlogN),效率不高 27 | * @param root 28 | * @return 29 | */ 30 | public static boolean isBalanced(TreeNode root){ 31 | if(root == null){ 32 | return true; 33 | } 34 | 35 | int heightDiff = getHeight(root.left) - getHeight(root.right); 36 | if(Math.abs(heightDiff) > 1){ 37 | return false; 38 | }else{ 39 | return isBalanced(root.left) && isBalanced(root.right); 40 | } 41 | } 42 | 43 | /** 44 | * 检查树的高度,若子树不平衡直接返回-1 45 | * @return 46 | */ 47 | private static int checkHeight(TreeNode root){ 48 | if(root == null){ 49 | return 0; 50 | } 51 | 52 | int leftHeight = checkHeight(root.left); 53 | if(leftHeight == -1){ 54 | return -1; 55 | } 56 | 57 | int rightHeight = checkHeight(root.right); 58 | if(rightHeight == -1){ 59 | return -1; 60 | } 61 | 62 | int heightDiff = leftHeight - rightHeight; 63 | if(Math.abs(heightDiff) > 1){ 64 | return -1; 65 | }else{ 66 | return Math.max(leftHeight, rightHeight) + 1; 67 | } 68 | } 69 | 70 | public static boolean isBalancedGood(TreeNode root){ 71 | if(checkHeight(root) == -1){ 72 | return false; 73 | }else{ 74 | return true; 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/tree/CommonAncestorSearch.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.tree; 2 | 3 | /** 4 | * 查找两个节点的共通祖先 5 | * @author weijielu 6 | * @see CommonAncestorSearchTest 7 | * @see TreeNode 8 | */ 9 | public class CommonAncestorSearch { 10 | 11 | /** 12 | * 判断p节点是否是root节点的子孙节点 13 | * @param root 14 | * @param p 15 | * @return 16 | */ 17 | private static boolean isDescendant(TreeNode root, TreeNode p){ 18 | if(root == null){ 19 | return false; 20 | } 21 | if(root == p){ 22 | return true; 23 | } 24 | 25 | return isDescendant(root.left, p) || isDescendant(root.right, p); 26 | } 27 | 28 | /** 29 | * 返回节点p和节点q的第一个祖先节点
30 | * 时间复杂度为O(n) 31 | * @param root 32 | * @param p 33 | * @param q 34 | * @return 35 | */ 36 | public static TreeNode searchCommonAncestor(TreeNode root, TreeNode p, TreeNode q){ 37 | // 确保p和q都是root的子孙节点 38 | if(!isDescendant(root, p) || !isDescendant(root, q)){ 39 | return null; 40 | } 41 | 42 | if(root == q || root== q){ 43 | return root; 44 | } 45 | 46 | boolean is_p_on_left = isDescendant(root.left, p); 47 | boolean is_q_on_left = isDescendant(root.left, q); 48 | 49 | // 如果p和q在root的两边,则返回root 50 | if(is_p_on_left != is_q_on_left){ 51 | return root; 52 | } 53 | 54 | // 如果p和q在root的同一边,则遍历访问那一边 55 | TreeNode treeSide = is_p_on_left?root.left:root.right; 56 | return searchCommonAncestor(treeSide, p, q); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/tree/MinBinaryTree.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.tree; 2 | 3 | /** 4 | * 将一个有序的数组变成一个最小高度的二叉查找树 5 | * @author weijielu 6 | */ 7 | public class MinBinaryTree { 8 | 9 | public static TreeNode insertNodeFromArray(int[] array, int start, int end){ 10 | if(end < start){ 11 | return null; 12 | } 13 | 14 | int middle = (start + end) / 2; 15 | 16 | TreeNode treeNode = new TreeNode(array[middle]); 17 | 18 | treeNode.left = insertNodeFromArray(array, start, middle - 1); 19 | treeNode.right = insertNodeFromArray(array, middle + 1, end); 20 | 21 | return treeNode; 22 | } 23 | 24 | /** 25 | * @param args 26 | */ 27 | public static void main(String[] args) { 28 | int[] array = {1,2,3,4,5,6,7,8,9,10}; 29 | MinBinaryTree.insertNodeFromArray(array, 0, array.length - 1); 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/tree/TreeNode.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.tree; 2 | 3 | /** 4 | * 树的节点 5 | * @author weijielu 6 | * 7 | */ 8 | public class TreeNode { 9 | T data; 10 | TreeNode left; 11 | TreeNode right; 12 | 13 | public TreeNode(T data){ 14 | this.data = data; 15 | } 16 | 17 | /** 18 | * 输出树 19 | */ 20 | // public void printTree(){ 21 | // int height = getHeight(this); 22 | // String[][] array = new String[height][height*2]; 23 | // 24 | // TreeNode left = this.left; 25 | // TreeNode right = this.right; 26 | // 27 | // } 28 | 29 | /** 30 | * 返回树root的高度 31 | * @param root 32 | * @return 33 | */ 34 | // private int getHeight(TreeNode root){ 35 | // if(root == null){ 36 | // return 0; 37 | // } 38 | // 39 | // return Math.max(getHeight(root.left), getHeight(root.right)) + 1; 40 | // } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/buptdavid/datastructure/tree/TreeSearch.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.tree; 2 | 3 | /** 4 | * 实现树的前序,中序,后续遍历搜索 5 | * @author weijielu 6 | * @see TreeSearchTest 7 | * @see TreeNode 8 | */ 9 | public class TreeSearch { 10 | StringBuffer searchPath = new StringBuffer(); 11 | private boolean isSearched = false; 12 | 13 | /** 14 | * 前序遍历root查询item 15 | * @param item 16 | * @return 17 | */ 18 | public void preorderTraversal(TreeNode root, T data){ 19 | if(root == null){ 20 | return; 21 | } 22 | 23 | if(!isSearched){ 24 | if(!searchPath.toString().equals("")){ 25 | searchPath.append("->"); 26 | } 27 | searchPath.append(root.data); 28 | if(root.data.equals(data)) 29 | isSearched = true; 30 | } 31 | 32 | if(!isSearched) 33 | preorderTraversal(root.left, data); 34 | if(!isSearched) 35 | preorderTraversal(root.right, data); 36 | } 37 | 38 | /** 39 | * 中序遍历root查询item 40 | * @param root 41 | * @param item 42 | * @return 43 | */ 44 | public void inorderTraversal(TreeNode root, T data){ 45 | if(root == null){ 46 | return; 47 | } 48 | 49 | if(!isSearched) 50 | inorderTraversal(root.left, data); 51 | 52 | if(!isSearched){ 53 | if(!searchPath.toString().equals("")){ 54 | searchPath.append("->"); 55 | } 56 | searchPath.append(root.data); 57 | if(root.data.equals(data)) 58 | isSearched = true; 59 | } 60 | 61 | if(!isSearched) 62 | inorderTraversal(root.right, data); 63 | } 64 | 65 | /** 66 | * 后续遍历root查询item 67 | * @param item 68 | * @return 69 | */ 70 | public void postorderTraversal(TreeNode root, T data){ 71 | if(root == null){ 72 | return; 73 | } 74 | 75 | if(!isSearched) 76 | postorderTraversal(root.left, data); 77 | 78 | if(!isSearched) 79 | postorderTraversal(root.right, data); 80 | 81 | if(!isSearched){ 82 | if(!searchPath.toString().equals("")){ 83 | searchPath.append("->"); 84 | } 85 | searchPath.append(root.data); 86 | if(root.data.equals(data)) 87 | isSearched = true; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/graph/DirectedGraphPathCheckTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.graph; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.BeforeClass; 6 | import org.junit.Test; 7 | 8 | /** 9 | * DirectedGraphPach测试 10 | * @author weijielu 11 | * @see GraphNode 12 | * @see DirectedGraphPathCheck 13 | */ 14 | public class DirectedGraphPathCheckTest { 15 | static GraphNode node1; 16 | static GraphNode node2; 17 | static GraphNode node3; 18 | static GraphNode node4; 19 | static GraphNode node5; 20 | static GraphNode node6; 21 | static GraphNode node7; 22 | static GraphNode node8; 23 | static GraphNode node9; 24 | static GraphNode node10; 25 | 26 | @BeforeClass 27 | public static void beforeClass(){ 28 | node1 = new GraphNode(1); 29 | node2 = new GraphNode(2); 30 | node3 = new GraphNode(3); 31 | node4 = new GraphNode(4); 32 | node5 = new GraphNode(5); 33 | node6 = new GraphNode(6); 34 | node7 = new GraphNode(7); 35 | node8 = new GraphNode(8); 36 | node9 = new GraphNode(9); 37 | node10 = new GraphNode(10); 38 | 39 | node1.neighborList.add(node2); 40 | node1.neighborList.add(node3); 41 | node1.neighborList.add(node4); 42 | 43 | node2.neighborList.add(node5); 44 | node2.neighborList.add(node6); 45 | 46 | node3.neighborList.add(node8); 47 | 48 | node4.neighborList.add(node5); 49 | node4.neighborList.add(node8); 50 | 51 | node5.neighborList.add(node10); 52 | 53 | node8.neighborList.add(node7); 54 | 55 | node7.neighborList.add(node9); 56 | } 57 | 58 | @Test 59 | public void testPathCheckDFS(){ 60 | Assert.assertTrue(DirectedGraphPathCheck.pathCheckDFS(node1, node9)); 61 | Assert.assertTrue(DirectedGraphPathCheck.pathCheckDFS(node4, node4)); 62 | 63 | Assert.assertTrue(DirectedGraphPathCheck.pathCheckDFS(node4, node8)); 64 | 65 | Assert.assertTrue(DirectedGraphPathCheck.pathCheckDFS(node4, node9)); 66 | Assert.assertTrue(DirectedGraphPathCheck.pathCheckDFS(node9, node4)); 67 | 68 | Assert.assertFalse(DirectedGraphPathCheck.pathCheckDFS(node3, node4)); 69 | Assert.assertFalse(DirectedGraphPathCheck.pathCheckDFS(node6, node4)); 70 | } 71 | 72 | @Test 73 | public void testPathCheckBFS(){ 74 | Assert.assertTrue(DirectedGraphPathCheck.pathCheckBFS(node1, node9)); 75 | Assert.assertTrue(DirectedGraphPathCheck.pathCheckBFS(node4, node4)); 76 | 77 | Assert.assertTrue(DirectedGraphPathCheck.pathCheckBFS(node4, node8)); 78 | 79 | Assert.assertTrue(DirectedGraphPathCheck.pathCheckBFS(node4, node9)); 80 | Assert.assertTrue(DirectedGraphPathCheck.pathCheckBFS(node9, node4)); 81 | 82 | Assert.assertFalse(DirectedGraphPathCheck.pathCheckBFS(node3, node4)); 83 | Assert.assertFalse(DirectedGraphPathCheck.pathCheckBFS(node6, node4)); 84 | } 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/graph/GraphSearchTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.graph; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | /** 9 | * GraphSearch测试 10 | * @author weijielu 11 | * @see GraphNode 12 | * @see GraphSearch 13 | */ 14 | public class GraphSearchTest { 15 | GraphNode node1; 16 | GraphNode node2; 17 | GraphNode node3; 18 | GraphNode node4; 19 | GraphNode node5; 20 | GraphNode node6; 21 | GraphNode node7; 22 | GraphNode node8; 23 | GraphNode node9; 24 | GraphNode node10; 25 | 26 | @Before 27 | public void before(){ 28 | node1 = new GraphNode(1); 29 | node2 = new GraphNode(2); 30 | node3 = new GraphNode(3); 31 | node4 = new GraphNode(4); 32 | node5 = new GraphNode(5); 33 | node6 = new GraphNode(6); 34 | node7 = new GraphNode(7); 35 | node8 = new GraphNode(8); 36 | node9 = new GraphNode(9); 37 | node10 = new GraphNode(10); 38 | 39 | node1.neighborList.add(node2); 40 | node1.neighborList.add(node3); 41 | 42 | node2.neighborList.add(node4); 43 | node2.neighborList.add(node5); 44 | node2.neighborList.add(node6); 45 | 46 | node3.neighborList.add(node1); 47 | node3.neighborList.add(node6); 48 | node3.neighborList.add(node7); 49 | node3.neighborList.add(node8); 50 | 51 | node4.neighborList.add(node2); 52 | node4.neighborList.add(node5); 53 | 54 | node5.neighborList.add(node2); 55 | node5.neighborList.add(node4); 56 | node5.neighborList.add(node6); 57 | 58 | node6.neighborList.add(node2); 59 | node6.neighborList.add(node5); 60 | node6.neighborList.add(node3); 61 | node6.neighborList.add(node8); 62 | node6.neighborList.add(node9); 63 | node6.neighborList.add(node10); 64 | 65 | node7.neighborList.add(node3); 66 | 67 | node8.neighborList.add(node3); 68 | node8.neighborList.add(node6); 69 | node8.neighborList.add(node9); 70 | 71 | node9.neighborList.add(node6); 72 | node9.neighborList.add(node8); 73 | node9.neighborList.add(node10); 74 | 75 | node10.neighborList.add(node6); 76 | node10.neighborList.add(node9); 77 | } 78 | 79 | @Test 80 | public void searchDFSTest(){ 81 | GraphSearch graphSearch = new GraphSearch(); 82 | graphSearch.searchDFS(node1); 83 | 84 | String expectedSearchPath = "1->2->4->5->6->3->7->8->9->10"; 85 | Assert.assertEquals(expectedSearchPath, graphSearch.searchPathDFS.toString()); 86 | } 87 | 88 | @Test 89 | public void searchBFSTest(){ 90 | GraphSearch graphSearch = new GraphSearch(); 91 | graphSearch.searchBFS(node1); 92 | 93 | String expectedSearchPath = "1->2->3->4->5->6->7->8->9->10"; 94 | Assert.assertEquals(expectedSearchPath, graphSearch.searchPathBFS.toString()); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/linkedlist/LinkedListLoopTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.linkedlist; 2 | 3 | import org.buptdavid.datastructure.Node; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | /** 8 | * LinkedListRing测试类 9 | * @author weijielu 10 | * @see LinkedListLoop 11 | */ 12 | public class LinkedListLoopTest { 13 | 14 | @Test 15 | public void test(){ 16 | Node node1 = null; 17 | Node node2 = null; 18 | Node node3 = null; 19 | Node node4 = null; 20 | 21 | Assert.assertFalse(LinkedListLoop.isExistLoop(node1)); 22 | Assert.assertEquals(0, LinkedListLoop.loopLength(node1)); 23 | Assert.assertEquals(null, LinkedListLoop.findLoopEntrance(node1)); 24 | 25 | node1 = new Node(1); 26 | node1.next = node1; 27 | Assert.assertTrue(LinkedListLoop.isExistLoop(node1)); 28 | Assert.assertEquals(1, LinkedListLoop.loopLength(node1)); 29 | Assert.assertEquals(node1, LinkedListLoop.findLoopEntrance(node1)); 30 | 31 | node1 = new Node(1); 32 | node2 = new Node(2); 33 | node1.next = node2; 34 | node2.next = node1; 35 | Assert.assertTrue(LinkedListLoop.isExistLoop(node1)); 36 | Assert.assertEquals(2, LinkedListLoop.loopLength(node1)); 37 | Assert.assertEquals(node1, LinkedListLoop.findLoopEntrance(node1)); 38 | 39 | node1 = new Node(1); 40 | node2 = new Node(2); 41 | node3 = new Node(3); 42 | node1.next = node2; 43 | node2.next = node3; 44 | node3.next = node2; 45 | Assert.assertTrue(LinkedListLoop.isExistLoop(node1)); 46 | Assert.assertEquals(2, LinkedListLoop.loopLength(node1)); 47 | Assert.assertEquals(node2, LinkedListLoop.findLoopEntrance(node1)); 48 | 49 | node1 = new Node(1); 50 | node2 = new Node(2); 51 | node3 = new Node(3); 52 | node1.next = node2; 53 | node2.next = node3; 54 | Assert.assertFalse(LinkedListLoop.isExistLoop(node1)); 55 | Assert.assertEquals(0, LinkedListLoop.loopLength(node1)); 56 | Assert.assertEquals(null, LinkedListLoop.findLoopEntrance(node1)); 57 | 58 | node1 = new Node(1); 59 | node2 = new Node(2); 60 | node3 = new Node(3); 61 | node4 = new Node(4); 62 | node1.next = node2; 63 | node2.next = node3; 64 | node3.next = node4; 65 | node4.next = node2; 66 | Assert.assertTrue(LinkedListLoop.isExistLoop(node1)); 67 | Assert.assertEquals(3, LinkedListLoop.loopLength(node1)); 68 | Assert.assertEquals(node2, LinkedListLoop.findLoopEntrance(node1)); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/queue/QueueTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.queue; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.buptdavid.datastructure.Node; 6 | import org.junit.Test; 7 | 8 | /** 9 | * 队列的测试类 10 | * @author weijielu 11 | * @see IQueue 12 | * @see Queue 13 | * @see Node 14 | */ 15 | public class QueueTest { 16 | IQueue queue; 17 | 18 | @Test 19 | public void testQueue(){ 20 | queue = new Queue(); 21 | test(); 22 | } 23 | 24 | @Test 25 | public void testQueueWith2Stack(){ 26 | queue = new QueueWith2Stack(); 27 | test(); 28 | } 29 | 30 | public void test(){ 31 | queue.enqueue(1); 32 | queue.enqueue(2); 33 | Assert.assertEquals(Integer.valueOf(1), queue.peek()); 34 | Assert.assertEquals(Integer.valueOf(1), queue.dequeue()); 35 | 36 | queue.enqueue(3); 37 | Assert.assertFalse(queue.isEmpty()); 38 | Assert.assertEquals(Integer.valueOf(2), queue.dequeue()); 39 | Assert.assertEquals(Integer.valueOf(3), queue.dequeue()); 40 | 41 | Assert.assertEquals(null, queue.dequeue()); 42 | Assert.assertEquals(null, queue.peek()); 43 | Assert.assertTrue(queue.isEmpty()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/search/BinarySearchTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.search; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Test; 6 | 7 | 8 | /** 9 | * 二分查找测试 10 | * @author weijielu 11 | * @see BinarySearch 12 | */ 13 | public class BinarySearchTest { 14 | int[] array = {-2, -1, 0, 2, 3, 4, 5, 8, 10}; 15 | 16 | @Test 17 | public void testSearchCirculation(){ 18 | Assert.assertEquals(Integer.valueOf(-2), BinarySearch.searchCirculation(array, -2)); 19 | Assert.assertEquals(Integer.valueOf(10), BinarySearch.searchCirculation(array, 10)); 20 | 21 | Assert.assertEquals(Integer.valueOf(0), BinarySearch.searchCirculation(array, 0)); 22 | 23 | Assert.assertEquals(null, BinarySearch.searchCirculation(array, 1)); 24 | } 25 | 26 | @Test 27 | public void testSearchRecursive(){ 28 | Assert.assertEquals(Integer.valueOf(-2), BinarySearch.searchRecursive(array, -2)); 29 | Assert.assertEquals(Integer.valueOf(10), BinarySearch.searchRecursive(array, 10)); 30 | 31 | Assert.assertEquals(Integer.valueOf(0), BinarySearch.searchRecursive(array, 0)); 32 | 33 | Assert.assertEquals(null, BinarySearch.searchRecursive(array, 1)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/sort/SortTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.sort; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | /** 9 | * 排序测试 10 | * @author weijielu 11 | * @see ISort 12 | * @see BubbleSort 13 | * @see SelectionSort 14 | * @see MergeSort 15 | * @see QuickSort 16 | */ 17 | public class SortTest { 18 | int[] array = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 19 | ISort sort; 20 | 21 | @Before 22 | public void before(){ 23 | int[] arrayIni = {10, 9, 8, 7, 6, 5, 4, 4, 1, -1}; 24 | for(int i = 0; i < array.length; i++){ 25 | array[i] = arrayIni[i]; 26 | } 27 | } 28 | 29 | @Test 30 | public void testBubbleSort(){ 31 | sort = new BubbleSort(); 32 | sort.sort(array); 33 | validate(); 34 | } 35 | 36 | @Test 37 | public void testSelectionSort(){ 38 | sort = new SelectionSort(); 39 | sort.sort(array); 40 | validate(); 41 | } 42 | 43 | @Test 44 | public void testMergeSort(){ 45 | sort = new MergeSort(); 46 | sort.sort(array); 47 | validate(); 48 | 49 | } 50 | 51 | @Test 52 | public void testQuickSort(){ 53 | sort = new QuickSort(); 54 | sort.sort(array); 55 | validate(); 56 | } 57 | 58 | @Test 59 | public void testInsertSort(){ 60 | sort = new InsertSort(); 61 | sort.sort(array); 62 | validate(); 63 | } 64 | 65 | @Test 66 | public void testInsertOptimizeSort(){ 67 | sort = new InsertOptimizeSort(); 68 | sort.sort(array); 69 | validate(); 70 | } 71 | 72 | private void validate(){ 73 | for(int i = 0; i < array.length - 1; i++){ 74 | Assert.assertTrue(array[i] <= array[i + 1]); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/stack/StackTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.stack; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.buptdavid.datastructure.Node; 6 | import org.junit.Test; 7 | 8 | /** 9 | * 栈的实现测试类 10 | * @author weijielu 11 | * @see Stack 12 | * @see SetOfStacks 13 | * @see StackWithMin 14 | * @see IStack 15 | * @see Node 16 | */ 17 | public class StackTest { 18 | IStack stack; 19 | 20 | @Test 21 | public void testStack(){ 22 | stack = new Stack(); 23 | stack.push(1); 24 | stack.push(2); 25 | Assert.assertEquals(Integer.valueOf(2), stack.peek()); 26 | Assert.assertEquals(Integer.valueOf(2), stack.pop()); 27 | 28 | stack.push(3); 29 | Assert.assertEquals(Integer.valueOf(3), stack.pop()); 30 | Assert.assertFalse(stack.isEmpty()); 31 | Assert.assertEquals(Integer.valueOf(1), stack.pop()); 32 | 33 | Assert.assertEquals(null, stack.peek()); 34 | Assert.assertEquals(null, stack.pop()); 35 | Assert.assertTrue(stack.isEmpty()); 36 | } 37 | 38 | @Test 39 | public void testSetOfStacks(){ 40 | stack = new SetOfStacks(3); 41 | stack.push(5); 42 | stack.push(8); 43 | stack.push(7); 44 | stack.push(3); 45 | stack.push(2); 46 | 47 | Assert.assertEquals(Integer.valueOf(2), stack.pop()); 48 | Assert.assertEquals(Integer.valueOf(3), stack.peek()); 49 | Assert.assertEquals(Integer.valueOf(3), stack.pop()); 50 | stack.push(1); 51 | Assert.assertEquals(Integer.valueOf(1), stack.peek()); 52 | Assert.assertEquals(Integer.valueOf(1), stack.pop()); 53 | Assert.assertTrue(stack.pop().equals(7)); 54 | } 55 | 56 | @Test 57 | public void testStackWithMin(){ 58 | StackWithMin s = new StackWithMin(); 59 | s.push(4); 60 | s.push(2); 61 | Assert.assertEquals(Integer.valueOf(2), s.min()); 62 | 63 | s.push(3); 64 | Assert.assertEquals(Integer.valueOf(2), s.min()); 65 | 66 | s.push(1); 67 | Assert.assertEquals(Integer.valueOf(1), s.min()); 68 | 69 | Assert.assertEquals(Integer.valueOf(1), s.peek()); 70 | Assert.assertEquals(Integer.valueOf(1), s.pop()); 71 | Assert.assertEquals(Integer.valueOf(2), s.min()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/tree/BinarySearchTreeTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.tree; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | /** 9 | * 二叉查找树测试 10 | * @author weijielu 11 | * @see BinarySearchTree 12 | * @see TreeNode 13 | */ 14 | public class BinarySearchTreeTest { 15 | TreeNode node8; 16 | TreeNode node6; 17 | TreeNode node4; 18 | TreeNode node7; 19 | TreeNode node5; 20 | TreeNode node4_4; 21 | TreeNode node11; 22 | TreeNode node9; 23 | TreeNode node9_9; 24 | TreeNode node12; 25 | 26 | @Before 27 | public void testBefore(){ 28 | node8 = new TreeNode(8); 29 | node6 = new TreeNode(6); 30 | node4 = new TreeNode(4); 31 | node7 = new TreeNode(7); 32 | node5 = new TreeNode(5); 33 | node4_4 = new TreeNode(4); 34 | node11 = new TreeNode(11); 35 | node9 = new TreeNode(9); 36 | node9_9 = new TreeNode(9); 37 | node12 = new TreeNode(12); 38 | } 39 | 40 | /** 41 | * 测试是二叉树情况 42 | */ 43 | @Test 44 | public void testYES(){ 45 | node8.left = node6; 46 | node8.right = node11; 47 | 48 | node6.left = node4; 49 | node6.right = node7; 50 | 51 | node4.left = node4_4; 52 | node4.right = node5; 53 | 54 | node11.left = node9; 55 | node11.right = node12; 56 | 57 | node9.left = node9_9; 58 | 59 | Assert.assertTrue(BinarySearchTree.checkBST(node8)); 60 | } 61 | 62 | /** 63 | * 测试非二叉树情况 64 | */ 65 | public void testNO(){ 66 | node8.left = node6; 67 | node8.right = node11; 68 | 69 | node6.left = node4; 70 | node6.right = node7; 71 | 72 | node4.left = node5; 73 | node4.right = node4_4; 74 | 75 | node11.left = node9; 76 | node11.right = node12; 77 | 78 | node9.left = node9_9; 79 | 80 | Assert.assertFalse(BinarySearchTree.checkBST(node8)); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/tree/CheckBalanceTreeTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.tree; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * 平衡树Check测试类 9 | * @author weijielu 10 | * @see CheckBalanceTree 11 | * @see TreeNode 12 | */ 13 | public class CheckBalanceTreeTest { 14 | @Test 15 | public void testNull(){ 16 | Assert.assertTrue(CheckBalanceTree.isBalanced(null)); 17 | Assert.assertTrue(CheckBalanceTree.isBalancedGood(null)); 18 | } 19 | 20 | @Test 21 | public void testBalanced(){ 22 | TreeNode node1 = new TreeNode(1); 23 | TreeNode node2 = new TreeNode(2); 24 | TreeNode node3 = new TreeNode(3); 25 | TreeNode node4 = new TreeNode(4); 26 | TreeNode node5 = new TreeNode(5); 27 | TreeNode node6 = new TreeNode(6); 28 | TreeNode node7 = new TreeNode(7); 29 | TreeNode node8 = new TreeNode(8); 30 | TreeNode node9 = new TreeNode(9); 31 | 32 | node1.left = node2; 33 | node1.right = node3; 34 | 35 | node2.left = node4; 36 | node2.right = node5; 37 | 38 | node3.left = node6; 39 | node3.right = node7; 40 | 41 | node4.left = node8; 42 | 43 | node7.right = node9; 44 | 45 | Assert.assertTrue(CheckBalanceTree.isBalanced(node1)); 46 | Assert.assertTrue(CheckBalanceTree.isBalancedGood(node1)); 47 | } 48 | 49 | @Test 50 | public void testUnBalanced(){ 51 | TreeNode node1 = new TreeNode(1); 52 | TreeNode node2 = new TreeNode(2); 53 | TreeNode node3 = new TreeNode(3); 54 | TreeNode node4 = new TreeNode(4); 55 | TreeNode node5 = new TreeNode(5); 56 | TreeNode node6 = new TreeNode(6); 57 | TreeNode node7 = new TreeNode(7); 58 | TreeNode node8 = new TreeNode(8); 59 | TreeNode node9 = new TreeNode(9); 60 | TreeNode node10 = new TreeNode(10); 61 | 62 | node1.left = node2; 63 | node1.right = node3; 64 | 65 | node2.left = node4; 66 | node2.right = node5; 67 | 68 | node3.left = node6; 69 | node3.right = node7; 70 | 71 | node4.left = node8; 72 | 73 | node7.right = node9; 74 | 75 | node9.left = node10; 76 | 77 | Assert.assertFalse(CheckBalanceTree.isBalanced(node1)); 78 | Assert.assertFalse(CheckBalanceTree.isBalancedGood(node1)); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/tree/CommonAncestorSearchTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.tree; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | /** 9 | * CommonAncestorSearch测试类 10 | * @author weijielu 11 | * @see CommonAncestorSearch 12 | * @see TreeNode 13 | */ 14 | public class CommonAncestorSearchTest { 15 | TreeNode root; 16 | TreeNode node8; 17 | TreeNode node6; 18 | TreeNode node4; 19 | TreeNode node7; 20 | TreeNode node5; 21 | TreeNode node3; 22 | TreeNode node11; 23 | TreeNode node9; 24 | TreeNode node10; 25 | TreeNode node12; 26 | 27 | /** 28 | * 8 29 | * / \ 30 | * 6 11 31 | * / \ / \ 32 | * 4 7 9 12 33 | * / \ / 34 | * 3 5 10 35 | */ 36 | @Before 37 | public void testBefore(){ 38 | node8 = new TreeNode(8); 39 | node6 = new TreeNode(6); 40 | node4 = new TreeNode(4); 41 | node7 = new TreeNode(7); 42 | node5 = new TreeNode(5); 43 | node3 = new TreeNode(3); 44 | node11 = new TreeNode(11); 45 | node9 = new TreeNode(9); 46 | node10 = new TreeNode(10); 47 | node12 = new TreeNode(12); 48 | 49 | node8.left = node6; 50 | node8.right = node11; 51 | 52 | node6.left = node4; 53 | node6.right = node7; 54 | 55 | node4.left = node3; 56 | node4.right = node5; 57 | 58 | node11.left = node9; 59 | node11.right = node12; 60 | 61 | node9.left = node10; 62 | 63 | root = node8; 64 | } 65 | 66 | @Test 67 | public void searchCommonAncestorTest(){ 68 | Assert.assertEquals(node4, CommonAncestorSearch.searchCommonAncestor(root, node3, node5)); 69 | Assert.assertEquals(node6, CommonAncestorSearch.searchCommonAncestor(root, node3, node7)); 70 | 71 | Assert.assertEquals(root, CommonAncestorSearch.searchCommonAncestor(root, node5, node10)); 72 | 73 | Assert.assertEquals(node11, CommonAncestorSearch.searchCommonAncestor(root, node10, node12)); 74 | 75 | Assert.assertEquals(null, CommonAncestorSearch.searchCommonAncestor(node6, node3, node10)); 76 | Assert.assertEquals(null, CommonAncestorSearch.searchCommonAncestor(node6, root, node3)); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/test/java/org/buptdavid/datastructure/tree/TreeSearchTest.java: -------------------------------------------------------------------------------- 1 | package org.buptdavid.datastructure.tree; 2 | 3 | import junit.framework.Assert; 4 | 5 | import org.junit.BeforeClass; 6 | import org.junit.Test; 7 | 8 | /** 9 | * TreeSearch测试类 10 | * @author weijielu 11 | * @see TreeSearch 12 | * @see TreeNode 13 | */ 14 | public class TreeSearchTest { 15 | 16 | private static TreeNode root; 17 | 18 | @BeforeClass 19 | public static void beforeClass(){ 20 | TreeNode node1 = new TreeNode(1); 21 | TreeNode node2 = new TreeNode(2); 22 | TreeNode node3 = new TreeNode(3); 23 | TreeNode node4 = new TreeNode(4); 24 | TreeNode node5 = new TreeNode(5); 25 | TreeNode node6 = new TreeNode(6); 26 | TreeNode node7 = new TreeNode(7); 27 | TreeNode node8 = new TreeNode(8); 28 | TreeNode node9 = new TreeNode(9); 29 | TreeNode node10 = new TreeNode(10); 30 | 31 | node1.left = node2; 32 | node1.right = node3; 33 | 34 | node2.left = node4; 35 | node2.right = node5; 36 | 37 | node3.left = node6; 38 | node3.right = node7; 39 | 40 | node4.left = node8; 41 | 42 | node7.right = node9; 43 | 44 | node9.left = node10; 45 | 46 | root = node1; 47 | } 48 | 49 | /** 50 | * 前序遍历测试 51 | */ 52 | @Test 53 | public void preorderTraversalTest(){ 54 | TreeSearch treeSearch = new TreeSearch(); 55 | 56 | Integer value = 5; 57 | String expectedSearchPath = "1->2->4->8->5"; 58 | treeSearch.preorderTraversal(root, value); 59 | Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString())); 60 | 61 | treeSearch = new TreeSearch(); 62 | 63 | value = 6; 64 | expectedSearchPath = "1->2->4->8->5->3->6"; 65 | treeSearch.preorderTraversal(root, value); 66 | Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString())); 67 | } 68 | 69 | /** 70 | * 中序遍历测试 71 | */ 72 | @Test 73 | public void inorderTraversalTest(){ 74 | TreeSearch treeSearch = new TreeSearch(); 75 | 76 | Integer value = 5; 77 | String expectedSearchPath = "8->4->2->5"; 78 | treeSearch.inorderTraversal(root, value); 79 | Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString())); 80 | 81 | treeSearch = new TreeSearch(); 82 | 83 | value = 6; 84 | expectedSearchPath = "8->4->2->5->1->6"; 85 | treeSearch.inorderTraversal(root, value); 86 | Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString())); 87 | } 88 | 89 | /** 90 | * 后序遍历测试 91 | */ 92 | @Test 93 | public void postorderTraversalTest(){ 94 | TreeSearch treeSearch = new TreeSearch(); 95 | 96 | Integer value = 5; 97 | String expectedSearchPath = "8->4->5"; 98 | treeSearch.postorderTraversal(root, value); 99 | Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString())); 100 | 101 | treeSearch = new TreeSearch(); 102 | 103 | value = 6; 104 | expectedSearchPath = "8->4->5->2->6"; 105 | treeSearch.postorderTraversal(root, value); 106 | Assert.assertTrue(expectedSearchPath.equals(treeSearch.searchPath.toString())); 107 | } 108 | } 109 | --------------------------------------------------------------------------------