├── .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