From 7f184a854e05fb85a3b6f7ed0db97214fdcb9df8 Mon Sep 17 00:00:00 2001 From: Rico Lin Date: Sat, 3 Jun 2017 21:23:58 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BinarySearchTree/BinarySearchTree.java | 159 ++++++++++++++++++ .../tju/rico/BinarySearchTree/TreeNode.java | 19 +++ src/cn/edu/tju/rico/backtrack/EightQueen.java | 89 ++++++++++ .../rico/sort/QuickSort_PartitionOnly.java | 49 ++++++ .../tju/rico/test/BinarySearchTreeTest.java | 35 ++++ src/cn/edu/tju/rico/test/SortTest.java | 2 +- src/cn/edu/tju/rico/tree/BinaryTree.java | 54 ++++++ 7 files changed, 406 insertions(+), 1 deletion(-) create mode 100644 src/cn/edu/tju/rico/BinarySearchTree/BinarySearchTree.java create mode 100644 src/cn/edu/tju/rico/BinarySearchTree/TreeNode.java create mode 100644 src/cn/edu/tju/rico/backtrack/EightQueen.java create mode 100644 src/cn/edu/tju/rico/sort/QuickSort_PartitionOnly.java create mode 100644 src/cn/edu/tju/rico/test/BinarySearchTreeTest.java diff --git a/src/cn/edu/tju/rico/BinarySearchTree/BinarySearchTree.java b/src/cn/edu/tju/rico/BinarySearchTree/BinarySearchTree.java new file mode 100644 index 0000000..127448b --- /dev/null +++ b/src/cn/edu/tju/rico/BinarySearchTree/BinarySearchTree.java @@ -0,0 +1,159 @@ +package cn.edu.tju.rico.BinarySearchTree; + +public class BinarySearchTree { + + private TreeNode root; + + /** + * @description 根据已知序列构建二叉搜索树 + * @author rico + * @created 2017年6月3日 下午6:15:54 + * @param input + */ + public BinarySearchTree(int[] input) { + createBinarySearchTree(input); + } + + /** + * @description 根据已知序列构建二叉搜索树 + * @author rico + * @created 2017年6月3日 下午6:15:06 + * @param input + */ + public void createBinarySearchTree(int[] input) { + if (input != null) { + for (int i = 0; i < input.length; i++) { + root = insert(input[i], root); + } + } + } + + /** + * @description 二叉搜索树的搜索算法,递归算法 + * @author rico + * @created 2017年6月3日 下午3:27:43 + * @param target + * 目标值 + * @param root + * 二叉搜索树的根结点 + * @return + */ + public TreeNode search(int target, TreeNode root) { + TreeNode result = null; + if (root != null) { // 递归终止条件 + if (target == root.data) { // 递归终止条件 + result = root; + return result; + } else if (target < root.data) { // 目标值小于根结点值,从左子树查找 + result = search(target, root.left); + } else { // 目标值大于根结点值,从右子树查找 + result = search(target, root.right); + } + } + return result; + } + + /** + * @description 二叉搜索树的插入操作 + * @author rico + * @created 2017年6月3日 下午5:55:05 + * @param target + * @param node + * @return + */ + public TreeNode insert(int target, TreeNode node) { + if (search(target, node) == null) { + if (node == null) { + return new TreeNode(target); + } else { + if (target < node.data) { + node.left = insert(target, node.left); + } else { + node.right = insert(target, node.right); + } + } + } + return node; + } + + /** + * @description 删除搜索二叉树的制定结点 + * @author rico + * @created 2017年6月3日 下午8:43:29 + * @param target + * @param node + * @return + */ + public TreeNode remove(int target, TreeNode node) { + TreeNode tmp = null; + if (node != null) { + if (target < node.data) { // 从左子树删除 + node.left = remove(target, node.left); + } else if (target > node.data) { // 从右子树删除 + node.right = remove(target, node.right); + } else if (node.left != null && node.right != null) { // 找到待删除结点,且其左右子树不为空 + // 找到以待删除结点右子树的中序遍历第一个结点(最小结点) + tmp = node.right; + while (tmp.left != null) { + tmp = tmp.left; + } + + // 用最小结点补位待删除结点 + node.data = tmp.data; + + // 删除待删除结点右子树上补位结点 + node.right = remove(node.data, node.right); + } else { + if (node.left == null) { + node = node.right; + } else { + node = node.left; + } + } + } + return node; + } + + /** + * @description 中序遍历二叉搜索树,递归算法,升序排序 + * @author rico + * @created 2017年6月3日 下午3:52:54 + * @param root + */ + public void inOrder(TreeNode node) { + if (node != null) { + inOrder(node.left); + System.out.print(root.data + " "); + inOrder(node.right); + } + } + + /** + * @description 打印二叉搜索树 + * @author rico + * @created 2017年6月3日 下午6:08:42 + * @param node + */ + public void printTree(TreeNode node) { + if (node != null) { + System.out.print(node.data); + if (node.left != null || node.right != null) { + System.out.print("("); + printTree(node.left); + System.out.print(","); + printTree(node.right); + System.out.print(")"); + } + } + } + + /** + * @description 访问二叉搜索树的根结点 + * @author rico + * @created 2017年6月3日 下午3:54:49 + * @return + */ + public TreeNode getRoot() { + return root; + } +} diff --git a/src/cn/edu/tju/rico/BinarySearchTree/TreeNode.java b/src/cn/edu/tju/rico/BinarySearchTree/TreeNode.java new file mode 100644 index 0000000..e15ed64 --- /dev/null +++ b/src/cn/edu/tju/rico/BinarySearchTree/TreeNode.java @@ -0,0 +1,19 @@ + +package cn.edu.tju.rico.BinarySearchTree; + +public class TreeNode { + + public int data; + public TreeNode left; + public TreeNode right; + + public TreeNode(int data){ + this.data = data; + } + + @Override + public String toString() { + return "TreeNode [data=" + data + "]"; + } + +} diff --git a/src/cn/edu/tju/rico/backtrack/EightQueen.java b/src/cn/edu/tju/rico/backtrack/EightQueen.java new file mode 100644 index 0000000..ec8f295 --- /dev/null +++ b/src/cn/edu/tju/rico/backtrack/EightQueen.java @@ -0,0 +1,89 @@ +package cn.edu.tju.rico.backtrack; + +import java.util.Arrays; +import java.util.Date; + +/** + * Title: 八皇后问题(递归算法) Description: 在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击, + * 即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 + * + * @author rico + * @created 2017年5月31日 下午4:54:17 + */ +public class EightQueen { + + private static final short N = 8; // 使用常量来定义,方便之后解N皇后问题 + private static int count = 0; // 结果计数器 + + public static void main(String[] args) { + Date begin = new Date(); + // 初始化棋盘,全部置0 + short chess[][] = new short[N][N]; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + chess[i][j] = 0; + } + } + + putQueenAtRow(chess, 0); + Date end = new Date(); + System.out.println("解决 " + N + " 皇后问题,用时:" + + String.valueOf(end.getTime() - begin.getTime()) + "毫秒,计算结果:" + + count); + } + + private static void putQueenAtRow(short[][] chess, int row) { + // 递归终止判断:如果row==N,则说明已经成功摆放了8个皇后 输出结果,终止递归 + if (row == N) { + count++; + System.out.println("第 " + count + " 种解:"); + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + System.out.print(chess[i][j] + " "); + } + System.out.println(); + } + return; + } + + short[][] chessTemp = chess.clone(); + + /** + * 向这一行的每一个位置尝试排放皇后 然后检测状态,如果安全则继续执行递归函数摆放下一行皇后 + */ + for (int i = 0; i < N; i++) { + // 摆放这一行的皇后,之前要清掉所有这一行摆放的记录,防止污染棋盘 + for (int j = 0; j < N; j++) + chessTemp[row][j] = 0; + + chessTemp[row][i] = 1; + + if (isSafety(chessTemp, row, i)) { + putQueenAtRow(chessTemp, row + 1); +// System.out.println("-----------"); +// for (int k = 0; k < N; k++) { +// for (int j = 0; j < N; j++) { +// System.out.print(chess[k][j] + " "); +// } +// System.out.println(); +// } + } + } + } + + private static boolean isSafety(short[][] chess, int row, int col) { + // 判断中上、左上、右上是否安全 + int step = 1; + while (row - step >= 0) { + if (chess[row - step][col] == 1) // 中上 + return false; + if (col - step >= 0 && chess[row - step][col - step] == 1) // 左上 + return false; + if (col + step < N && chess[row - step][col + step] == 1) // 右上 + return false; + + step++; + } + return true; + } +} \ No newline at end of file diff --git a/src/cn/edu/tju/rico/sort/QuickSort_PartitionOnly.java b/src/cn/edu/tju/rico/sort/QuickSort_PartitionOnly.java new file mode 100644 index 0000000..e80d983 --- /dev/null +++ b/src/cn/edu/tju/rico/sort/QuickSort_PartitionOnly.java @@ -0,0 +1,49 @@ +package cn.edu.tju.rico.sort; + +import java.util.Arrays; + + +/** + * Title:快速排序的变形 + * Description: 本质上不断调用经典快排的划分算法 + * 时间复杂度:O(n^2) + * @author rico + * @created 2017年6月2日 下午9:10:43 + */ +public class QuickSort_PartitionOnly { + /** + * @description 依次以数组中的每个元素为基准点进行划分, + * 直到遍历所有元素都 + * @author rico + * @param array + */ + public void quicksort(int[] array) { + if (array != null && array.length != 0) { + for (int i = 0; i < array.length; i++) { + // 以下是快排的划分算法 + int base_index = 0; + int base = array[i]; + base_index = i; + for (int j = i+1; j < array.length; j++) { + if (array[j] <= base ) { + base_index ++; + if (base_index != j) { + int temp = array[base_index]; + array[base_index] = array[j]; + array[j] = temp; + } + } + } + array[i] = array[base_index]; + array[base_index] = base; + System.out.println(Arrays.toString(array)); + } + } + } + + public static void main(String[] args) { +// int[] array = { 1, 2, 3, 2, 2, 2, 5, 4, 2 }; + int[] array = { 1, 2, 3, 5, 0, 4, 9, 2, 6 }; + new QuickSort_PartitionOnly().quicksort(array); + } +} diff --git a/src/cn/edu/tju/rico/test/BinarySearchTreeTest.java b/src/cn/edu/tju/rico/test/BinarySearchTreeTest.java new file mode 100644 index 0000000..a2e8067 --- /dev/null +++ b/src/cn/edu/tju/rico/test/BinarySearchTreeTest.java @@ -0,0 +1,35 @@ +package cn.edu.tju.rico.test; + +import cn.edu.tju.rico.BinarySearchTree.BinarySearchTree; + +public class BinarySearchTreeTest { + public static void main(String[] args) { + int[] input = {53,78,65,17,87,9,81,45,23}; + BinarySearchTree tree = new BinarySearchTree(input); + + System.out.println("中序遍历二叉搜索树:"); + tree.inOrder(tree.getRoot()); + System.out.println(); + System.out.println("\n------------------------\n"); + System.out.println("打印二叉搜索树:"); + tree.printTree(tree.getRoot()); + System.out.println(); + System.out.println("\n------------------------\n"); + + System.out.println("二叉搜索树搜索目标值:"); + System.out.println(tree.search(23, tree.getRoot())); + System.out.println("\n------------------------\n"); + + System.out.println("向二叉搜索树插入目标值:"); + tree.insert(10, tree.getRoot()); + tree.printTree(tree.getRoot()); + System.out.println(); + System.out.println("\n------------------------\n"); + + System.out.println("向二叉搜索树删除目标值:"); + tree.remove(78, tree.getRoot()); + tree.printTree(tree.getRoot()); + System.out.println(); + System.out.println("\n------------------------\n"); + } +} diff --git a/src/cn/edu/tju/rico/test/SortTest.java b/src/cn/edu/tju/rico/test/SortTest.java index 0529a5d..025e501 100644 --- a/src/cn/edu/tju/rico/test/SortTest.java +++ b/src/cn/edu/tju/rico/test/SortTest.java @@ -57,7 +57,7 @@ public static void main(String[] args) { System.out.println("\n----------------------\n"); System.out.println("希尔排序 : "); - int[] target7 = { 21, 25, 49, 25, 16, 8, 31, 41 }; + int[] target7 = { 21, 25, 49, 25, 16, 8, 31, 41,1,16 }; System.out.println("原数组 : " + Arrays.toString(target7)); ShellSort.shellSort(target7); System.out.println(Arrays.toString(target7)); diff --git a/src/cn/edu/tju/rico/tree/BinaryTree.java b/src/cn/edu/tju/rico/tree/BinaryTree.java index b07f916..6642877 100644 --- a/src/cn/edu/tju/rico/tree/BinaryTree.java +++ b/src/cn/edu/tju/rico/tree/BinaryTree.java @@ -132,6 +132,60 @@ public void createBinaryTree(String exp) { node = null; // node链入后,置空 } } + + /** + * @description 根据广义表表达式创建树 + * @author rico + * @created 2017年5月22日 下午3:16:01 + * @param exp 广义表 + */ + public static Node createBinaryTree(String exp, Node root) { + LinkedList stack = new LinkedList(); // 辅助栈 + Node node = null; // 新结点 + Node temp = null; // 用于入栈 + Node parent = null; // 父亲结点 + boolean flag = false; // true 表示链入到父结点的左孩子位置,false表示链入父结点的右孩子位置 + + for (int i = 0; i < exp.length(); i++) { // 逐个读入表达式的各个字符 + char c = exp.charAt(i); + switch (c) { + case '(': // 当前节点有孩子节点,入栈以便设置其孩子 + stack.push(temp); + flag = true; + break; + case ')': // 设置好了栈顶节点的孩子,出栈 + stack.pop(); + break; + case ',': // 当前节点无孩子,不需要设置其孩子节点,因此不需要入栈 + flag = false; + break; + default: // 创建根据内容创建节点 + node = new Node(c); + break; + } + + // 若树不存在,则创建树的根结点 + if (root == null) { + root = node; + } + + // 为栈顶节点链入子女 + if (!stack.isEmpty()) { + if (node != null) { // 当读入的是'('、')'、','字符时,略过 + parent = stack.peek(); + if (flag) { + parent.left = node; + } else { + parent.right = node; + } + } + } + + temp = node; // 用于入栈 + node = null; // node链入后,置空 + } + return root; + } /** * @description 广序/层次遍历,工作队列 From 1fddf6c7604c67170296fea2a8e2555b622d3753 Mon Sep 17 00:00:00 2001 From: Rico Lin Date: Sun, 3 Sep 2017 11:51:55 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E7=AE=97=E6=B3=95=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BinarySearchTree/BinarySearchTree.java | 23 +++- src/cn/edu/tju/rico/backtrack/EightQueen.java | 1 - src/cn/edu/tju/rico/list/LinkedList.java | 37 +++++- src/cn/edu/tju/rico/list/Node.java | 2 +- src/cn/edu/tju/rico/sort/MergeSort.java | 119 ++++++++++-------- src/cn/edu/tju/rico/sort/QuickSort.java | 5 + src/cn/edu/tju/rico/sort/ShellSort.java | 99 ++++++++++----- .../tju/rico/sort/StraightInsertionSort.java | 49 ++++---- .../tju/rico/test/BinarySearchTreeTest.java | 3 +- src/cn/edu/tju/rico/test/LinkedListTest.java | 52 ++++---- src/cn/edu/tju/rico/test/SortTest.java | 2 +- src/cn/edu/tju/rico/tree/BinaryTree.java | 33 ++--- 12 files changed, 269 insertions(+), 156 deletions(-) diff --git a/src/cn/edu/tju/rico/BinarySearchTree/BinarySearchTree.java b/src/cn/edu/tju/rico/BinarySearchTree/BinarySearchTree.java index 127448b..02ee267 100644 --- a/src/cn/edu/tju/rico/BinarySearchTree/BinarySearchTree.java +++ b/src/cn/edu/tju/rico/BinarySearchTree/BinarySearchTree.java @@ -1,5 +1,17 @@ package cn.edu.tju.rico.BinarySearchTree; +/** + * Title: 二叉搜索树的数据结构及其算法 + * Description: 二叉搜索树或者是一颗空树,或者具有以下性质, + * 所有节点的关键码互不相同,即唯一; + * 左子树上所有节点都小于父结点,右子树上所有节点都大于父结点 + * 左子树、右子树都是二叉搜索树 + * + * 二叉搜索树的插入、搜索、删除节点的时间复杂度均为O(lgn) + * + * @author rico + * @created 2017年6月4日 上午9:51:16 + */ public class BinarySearchTree { private TreeNode root; @@ -62,10 +74,11 @@ public TreeNode search(int target, TreeNode root) { * @return */ public TreeNode insert(int target, TreeNode node) { - if (search(target, node) == null) { - if (node == null) { + if (search(target, node) == null) { // 先检查元素是否已经存在 + if (node == null) { // 创建插入结点 return new TreeNode(target); } else { + // 寻找插入点并插入 if (target < node.data) { node.left = insert(target, node.left); } else { @@ -77,7 +90,7 @@ public TreeNode insert(int target, TreeNode node) { } /** - * @description 删除搜索二叉树的制定结点 + * @description 删除搜索二叉树的指定结点 * @author rico * @created 2017年6月3日 下午8:43:29 * @param target @@ -103,7 +116,7 @@ public TreeNode remove(int target, TreeNode node) { // 删除待删除结点右子树上补位结点 node.right = remove(node.data, node.right); - } else { + } else { // 待删除结点的左子树或右子树至少有一个为空,递归的终止条件 if (node.left == null) { node = node.right; } else { @@ -123,7 +136,7 @@ public TreeNode remove(int target, TreeNode node) { public void inOrder(TreeNode node) { if (node != null) { inOrder(node.left); - System.out.print(root.data + " "); + System.out.print(node.data + " "); inOrder(node.right); } } diff --git a/src/cn/edu/tju/rico/backtrack/EightQueen.java b/src/cn/edu/tju/rico/backtrack/EightQueen.java index ec8f295..7ecdee4 100644 --- a/src/cn/edu/tju/rico/backtrack/EightQueen.java +++ b/src/cn/edu/tju/rico/backtrack/EightQueen.java @@ -1,6 +1,5 @@ package cn.edu.tju.rico.backtrack; -import java.util.Arrays; import java.util.Date; /** diff --git a/src/cn/edu/tju/rico/list/LinkedList.java b/src/cn/edu/tju/rico/list/LinkedList.java index 0315a2e..b35c011 100644 --- a/src/cn/edu/tju/rico/list/LinkedList.java +++ b/src/cn/edu/tju/rico/list/LinkedList.java @@ -179,7 +179,42 @@ public void reverseLinkedList() { } head.next = pre; // 将原链表的头结点指向反转后的链表 } - + +// public void ReverseList() { +// Node head1 = head.next; +// if (head1 != null && head1.next != null) { +// Node p1 = head1; +// Node p2 = p1.next; +// while(p2 != null){ +// Node tmp = p2.next; +// p2.next = p1; +// if (p1 == head1) { +// p1.next = null; +// } +// p1 = p2; +// p2 = tmp; +// } +// +// head.next = p1; +// } +// } + +// public void ReverseList1() { +// java.util.LinkedList stack = new java.util.LinkedList(); +// Node head1 = head.next; +// Node cur = head1; +// while(cur != null){ +// stack.push(cur.data); +// cur = cur.next; +// } +// +// cur = head1; +// while (cur!= null) { +// cur.data = stack.pop(); +// cur = cur.next; +// } +// } + /** * @description 判断单链表是否为空 * @author rico diff --git a/src/cn/edu/tju/rico/list/Node.java b/src/cn/edu/tju/rico/list/Node.java index 88848f3..022e14f 100644 --- a/src/cn/edu/tju/rico/list/Node.java +++ b/src/cn/edu/tju/rico/list/Node.java @@ -9,7 +9,7 @@ */ public class Node { //包可见性 - Node next; + public Node next; T data; /** diff --git a/src/cn/edu/tju/rico/sort/MergeSort.java b/src/cn/edu/tju/rico/sort/MergeSort.java index 1bac7ca..ac65a6f 100644 --- a/src/cn/edu/tju/rico/sort/MergeSort.java +++ b/src/cn/edu/tju/rico/sort/MergeSort.java @@ -3,83 +3,96 @@ import java.util.Arrays; /** - * Title: 归并排序 ,概念上最为简单的排序算法,是一个递归算法 - * Description:归并排序包括两个过程:归 和 并 - * "归"是指将原序列分成半子序列,分别对子序列进行递归排序 - * "并"是指将排好序的各子序列合并成原序列 + * Title: 归并排序 ,概念上最为简单的排序算法,是一个递归算法 Description:归并排序包括两个过程:归 和 并 + * "归"是指将原序列分成半子序列,分别对子序列进行递归排序 "并"是指将排好序的各子序列合并成原序列 * * 归并排序的主要问题是:需要一个与原待排序数组一样大的辅助数组空间 * - * 归并排序不依赖于原始序列,因此其最好情形、平均情形和最差情形时间复杂度都一样 - * 时间复杂度:最好情形O(n),平均情形O(n^2),最差情形O(n^2) - * 空间复杂度:O(n) - * 稳 定 性:稳定 - * 内部排序(在排序过程中数据元素完全在内存) + * 归并排序不依赖于原始序列,因此其最好情形、平均情形和最差情形时间复杂度都一样 时间复杂度:最好情形O(n),平均情形O(n^2),最差情形O(n^2) + * 空间复杂度:O(n) 稳 定 性:稳定 内部排序(在排序过程中数据元素完全在内存) * * @author rico * @created 2017年5月20日 上午10:40:00 */ public class MergeSort { - /** + /** * @description 归并排序算法(递归算法):递去分解,归来合并 - * @author rico - * @created 2017年5月20日 下午4:04:52 - * @param target 待排序序列 - * @param left 待排序序列起始位置 - * @param right 待排序序列终止位置 - * @return + * @author rico + * @created 2017年5月20日 下午4:04:52 + * @param target + * 待排序序列 + * @param left + * 待排序序列起始位置 + * @param right + * 待排序序列终止位置 + * @return */ - public static int[] mergeSort(int[] target, int left, int right) { - - if(right > left){ // 递归终止条件 - int mid = (left + right)/2; - mergeSort(target, left, mid); // 归并排序第一个子序列 - mergeSort(target, mid+1, right); // 归并排序第二个子序列 - return merge(target,left,mid,right); // 合并子序列成原序列 + + public static void mergeSort(int[] target) { + int[] copy = Arrays.copyOf(target, target.length); // 空间复杂度O(n) + mergeSort(target, copy, 0, target.length - 1); + } + + public static void mergeSort(int[] target, int[] copy, int left, int right) { + if (right > left) { // 递归终止条件 + int mid = (left + right) / 2; + mergeSort(target, copy, left, mid); // 归并排序第一个子序列 + mergeSort(target, copy, mid + 1, right); // 归并排序第二个子序列 + merge(target, copy, left, mid, right); // 合并子序列成原序列 } - return target; } - - - /** + + /** * @description 两路归并算法 - * @author rico - * @created 2017年5月20日 下午3:59:16 - * @param target 用于存储归并结果 - * @param left 第一个有序表的第一个元素所在位置 - * @param mid 第一个有序表的最后一个元素所在位置 - * @param right 第二个有序表的最后一个元素所在位置 - * @return + * @author rico + * @created 2017年5月20日 下午3:59:16 + * @param target + * 用于存储归并结果 + * @param left + * 第一个有序表的第一个元素所在位置 + * @param mid + * 第一个有序表的最后一个元素所在位置 + * @param right + * 第二个有序表的最后一个元素所在位置 + * @return */ - public static int[] merge(int[] target, int left, int mid, int right){ - - // 需要一个与原待排序数组一样大的辅助数组空间 - int[] temp = Arrays.copyOf(target, target.length); - + public static void merge(int[] target, int[] copy, int left, int mid, + int right) { + // s1,s2是检查指针,index 是存放指针 int s1 = left; int s2 = mid + 1; int index = left; - + // 两个表都未检查完,两两比较 - while(s1 <= mid && s2 <= right){ - if(temp[s1] <= temp[s2]){ // 稳定性 - target[index++] = temp[s1++]; - }else{ - target[index++] = temp[s2++]; + while (s1 <= mid && s2 <= right) { + if (copy[s1] <= copy[s2]) { // 稳定性 + target[index++] = copy[s1++]; + } else { + target[index++] = copy[s2++]; } } - - //若第一个表未检查完,复制 - while(s1 <= mid){ - target[index++] = temp[s1++]; + + // 若第一个表未检查完,复制 + while (s1 <= mid) { + target[index++] = copy[s1++]; + } + + // 若第二个表未检查完,复制 + while (s2 <= right) { + target[index++] = copy[s2++]; } - //若第二个表未检查完,复制 - while(s2 <= right){ - target[index++] = temp[s2++]; + // 更新辅助数组 copy + for (int i = left; i <= right; i++) { + copy[i] = target[i]; } - return target; + } + + public static void main(String[] args) { + int[] target = { 21, 25, 49, 25, 16, 8, 31, 41 }; + mergeSort(target); + System.out.println(Arrays.toString(target)); } } diff --git a/src/cn/edu/tju/rico/sort/QuickSort.java b/src/cn/edu/tju/rico/sort/QuickSort.java index bc174da..d85ffa2 100644 --- a/src/cn/edu/tju/rico/sort/QuickSort.java +++ b/src/cn/edu/tju/rico/sort/QuickSort.java @@ -83,4 +83,9 @@ public static int partition(int[] target, int left, int right){ return base_index; //返回划分后基准元素的位置 } + + public static void main(String[] args) { + int array[] = {17,8,3,25,17,1,13,19,18,4,6,24}; + QuickSort.quickSort(array, 0, array.length-1); + } } diff --git a/src/cn/edu/tju/rico/sort/ShellSort.java b/src/cn/edu/tju/rico/sort/ShellSort.java index 8e05328..c922a6c 100644 --- a/src/cn/edu/tju/rico/sort/ShellSort.java +++ b/src/cn/edu/tju/rico/sort/ShellSort.java @@ -1,47 +1,78 @@ package cn.edu.tju.rico.sort; - -/** - * Title: 插入排序中的希尔排序 - * Description: 分别对间隔为gap的gap个子序列进行直接插入排序,不断缩小gap,直至为 1 + +import java.util.Arrays; + +/** + * Title: 插入排序中的希尔排序 Description: 分别对间隔为gap的gap个子序列进行直接插入排序,不断缩小gap,直至为 1 * - * 刚开始时,gap较大,每个子序列元素较少,排序速度较快; - * 待到排序后期,gap变小,每个子序列元素较多,但大部分元素基本有序,所以排序速度仍较快。 + * 刚开始时,gap较大,每个子序列元素较少,排序速度较快; 待到排序后期,gap变小,每个子序列元素较多,但大部分元素基本有序,所以排序速度仍较快。 * - * 时间复杂度:O(n) ~ O(n^2) - * 空间复杂度:O(1) - * 稳 定 性:不稳定 - * 内部排序(在排序过程中数据元素完全在内存) - * @author rico - * @created 2017年5月20日 上午10:40:00 - */ + * 时间复杂度:O(n) ~ O(n^2) 空间复杂度:O(1) 稳 定 性:不稳定 内部排序(在排序过程中数据元素完全在内存) + * + * @author rico + * @created 2017年5月20日 上午10:40:00 + */ public class ShellSort { - - - /** - * @description - * @author rico - * @created 2017年5月21日 下午7:56:03 + + /** + * @description + * @author rico + * @created 2017年5月21日 下午7:56:03 * @param target - * @return + * @return */ - public static int[] shellSort(int[] target){ - if(target != null && target.length != 1){ - int gap = target.length; // gap个大小为gap的子序列 - do{ - gap = gap/3 + 1; // 不断缩小gap直至为1 - for (int i = 0 + gap; i < target.length; i++) { // 对每个子序列进行直接插入排序 - if(target[i] < target[i-gap]){ + public static int[] shellSort(int[] target) { + if (target != null && target.length != 1) { + int gap = target.length; // gap个大小为gap的子序列 + do { + gap = gap / 3 + 1; // 不断缩小gap直至为1 + for (int i = 0 + gap; i < target.length; i++) { // 对每个子序列进行直接插入排序 + if (target[i] < target[i - gap]) { int j = i - gap; - int temp = target[i]; // 待插入值 - do{ - target[j + gap] = target[j]; // 后移元素 - j = j - gap; // 再比较前一个元素 - }while(j >= 0 && target[j] > temp); // 向前比较的终止条件 - target[j + gap] = temp; // 将待插入值插入合适的位置 + int temp = target[i]; // 待插入值 + do { + target[j + gap] = target[j]; // 后移元素 + j = j - gap; // 再比较前一个元素 + } while (j >= 0 && target[j] > temp); // 向前比较的终止条件 + target[j + gap] = temp; // 将待插入值插入合适的位置 } } - }while(gap > 1); + } while (gap > 1); } return target; } + + public static void shellSort1(int[] target) { + if (target != null && target.length != 1) { + int gap = target.length; + while (gap > 1) { // gap为int型,自动取整 + gap = gap / 3 + 1; + for (int i = gap; i < target.length; i++) { + int j = i - gap; + while (j >= 0) { + if (target[j + gap] < target[j]) { + swap(target, j, j+gap); + j -= gap; + }else{ + break; + } + } + } + } + } + } + + public static void swap(int[] target, int i, int j) { + int temp = target[i]; + target[i] = target[j]; + target[j] = temp; + } + + public static void main(String[] args) { + int[] target = {10,9,8,7,6,5,4,3,2,1,0}; + System.out.println("排序前: " + Arrays.toString(target)); + shellSort1(target); + System.out.println("排序后: " + Arrays.toString(target)); + + } } diff --git a/src/cn/edu/tju/rico/sort/StraightInsertionSort.java b/src/cn/edu/tju/rico/sort/StraightInsertionSort.java index 40a1f44..e9fb783 100644 --- a/src/cn/edu/tju/rico/sort/StraightInsertionSort.java +++ b/src/cn/edu/tju/rico/sort/StraightInsertionSort.java @@ -1,30 +1,37 @@ package cn.edu.tju.rico.sort; - -/** - * Title: 插入排序中的直接插入排序 ,依赖于初始序列 - * Description: 在有序序列中不断插入新的记录以达到扩大有序区到整个数组的目的 - * 时间复杂度:最好情形O(n),平均情形O(n^2),最差情形O(n^2) - * 空间复杂度:O(1) - * 稳 定 性:稳定 - * 内部排序(在排序过程中数据元素完全在内存) - * @author rico - * @created 2017年5月20日 上午10:40:00 - */ + +import java.util.Arrays; + +/** + * Title: 插入排序中的直接插入排序 ,依赖于初始序列 Description: 在有序序列中不断插入新的记录以达到扩大有序区到整个数组的目的 + * 时间复杂度:最好情形O(n),平均情形O(n^2),最差情形O(n^2) 空间复杂度:O(1) 稳 定 性:稳定 + * 内部排序(在排序过程中数据元素完全在内存) + * + * @author rico + * @created 2017年5月20日 上午10:40:00 + */ public class StraightInsertionSort { - - public static int[] insertSort(int[] target){ - - if(target != null && target.length != 1){ // 待排序数组不为空且长度大于1 - for (int i = 1; i < target.length; i++) { // 不断扩大有序序列,直到扩展到整个数组 - for (int j = i; j > 0; j--) { // 向有序序列中插入新的元素 - if(target[j] < target[j-1]){ // 交换 + + public static int[] insertSort(int[] target) { + + if (target != null && target.length != 1) { // 待排序数组不为空且长度大于1 + for (int i = 1; i < target.length; i++) { // 不断扩大有序序列,直到扩展到整个数组 + for (int j = i; j > 0; j--) { // 向有序序列中插入新的元素 + if (target[j] < target[j - 1]) { // 交换 int temp = target[j]; - target[j] = target[j-1]; - target[j-1] = temp; + target[j] = target[j - 1]; + target[j - 1] = temp; + } else { + break; } } } } return target; } -} \ No newline at end of file + + public static void main(String[] args) { + int[] test = {1,9,3,5,2,0,3,5}; + System.out.println(Arrays.toString(StraightInsertionSort.insertSort(test))); + } +} diff --git a/src/cn/edu/tju/rico/test/BinarySearchTreeTest.java b/src/cn/edu/tju/rico/test/BinarySearchTreeTest.java index a2e8067..7c85821 100644 --- a/src/cn/edu/tju/rico/test/BinarySearchTreeTest.java +++ b/src/cn/edu/tju/rico/test/BinarySearchTreeTest.java @@ -11,6 +11,7 @@ public static void main(String[] args) { tree.inOrder(tree.getRoot()); System.out.println(); System.out.println("\n------------------------\n"); + System.out.println("打印二叉搜索树:"); tree.printTree(tree.getRoot()); System.out.println(); @@ -27,7 +28,7 @@ public static void main(String[] args) { System.out.println("\n------------------------\n"); System.out.println("向二叉搜索树删除目标值:"); - tree.remove(78, tree.getRoot()); + tree.remove(10, tree.getRoot()); tree.printTree(tree.getRoot()); System.out.println(); System.out.println("\n------------------------\n"); diff --git a/src/cn/edu/tju/rico/test/LinkedListTest.java b/src/cn/edu/tju/rico/test/LinkedListTest.java index fb3fc17..556e125 100644 --- a/src/cn/edu/tju/rico/test/LinkedListTest.java +++ b/src/cn/edu/tju/rico/test/LinkedListTest.java @@ -40,31 +40,35 @@ public static void main(String[] args) throws Exception { list1.print(); list1.reverseLinkedList(); list1.print(); +// list1.ReverseList(); +// list1.print(); +// list1.ReverseList1(); +// list1.print(); System.out.println(); - System.out.println("倒序打印链表:"); - list1.reversePrint(list1.getHead()); - System.out.println(); - System.out.println(); - - System.out.println("打印链表中间节点:"); - list1.printMiddleNodes(); - System.out.println(); - - - LinkedList list2 = new LinkedList(); - list2.add("书呆子"); - list2.add(list1.getEndK(2)); - System.out.println("判断两链表是否相交:"); - list1.print(); - list2.print(); - System.out.println(list1.size() + " : " + list2.size()); - System.out.println("是否相交 : " + list1.isIntersect(list2)); - System.out.println("交点是 : " + list1.getIntersectionPoint(list2)); - System.out.println(); - - list1.deleteNodeWithoutHead(list1.getEndK(2)); - System.out.println("打印删除特定节点后的链表:"); - list1.print(); +// System.out.println("倒序打印链表:"); +// list1.reversePrint(list1.getHead()); +// System.out.println(); +// System.out.println(); +// +// System.out.println("打印链表中间节点:"); +// list1.printMiddleNodes(); +// System.out.println(); +// +// +// LinkedList list2 = new LinkedList(); +// list2.add("书呆子"); +// list2.add(list1.getEndK(2)); +// System.out.println("判断两链表是否相交:"); +// list1.print(); +// list2.print(); +// System.out.println(list1.size() + " : " + list2.size()); +// System.out.println("是否相交 : " + list1.isIntersect(list2)); +// System.out.println("交点是 : " + list1.getIntersectionPoint(list2)); +// System.out.println(); +// +// list1.deleteNodeWithoutHead(list1.getEndK(2)); +// System.out.println("打印删除特定节点后的链表:"); +// list1.print(); } } diff --git a/src/cn/edu/tju/rico/test/SortTest.java b/src/cn/edu/tju/rico/test/SortTest.java index 025e501..a536dbb 100644 --- a/src/cn/edu/tju/rico/test/SortTest.java +++ b/src/cn/edu/tju/rico/test/SortTest.java @@ -45,7 +45,7 @@ public static void main(String[] args) { System.out.println("归并排序 : "); int[] target5 = { 21, 25, 49, 25, 16, 8, 31, 41 }; System.out.println("原数组 : " + Arrays.toString(target5)); - MergeSort.mergeSort(target5, 0, target5.length - 1); + MergeSort.mergeSort(target5); System.out.println(Arrays.toString(target5)); System.out.println("\n----------------------\n"); diff --git a/src/cn/edu/tju/rico/tree/BinaryTree.java b/src/cn/edu/tju/rico/tree/BinaryTree.java index 6642877..2c8ebe3 100644 --- a/src/cn/edu/tju/rico/tree/BinaryTree.java +++ b/src/cn/edu/tju/rico/tree/BinaryTree.java @@ -211,7 +211,7 @@ public String levelOrder() { } return sb.toString().trim(); } - + /** * @description 前序遍历(递归) * @author rico @@ -221,12 +221,14 @@ public String levelOrder() { */ public String preOrder(Node root) { StringBuilder sb = new StringBuilder(); // 存到递归调用栈 - if (root != null) { // 递归终止条件 + if (root == null) { + return ""; + }else { // 递归终止条件 sb.append(root.data + " "); // 前序遍历当前结点 sb.append(preOrder(root.left)); // 前序遍历左子树 sb.append(preOrder(root.right)); // 前序遍历右子树 - } - return sb.toString(); + return sb.toString(); + } } /** @@ -351,17 +353,18 @@ public String postOrder() { * @return */ public Node createBinaryTreeByPreAndIn(String pre, String in) { - if (pre.length() > 0) { + if (pre.length() <= 0) { // 递归终止条件 + return null; // 简单情景 + }else{ Node root = new Node(pre.charAt(0)); int index = in.indexOf(pre.charAt(0)); root.left = createBinaryTreeByPreAndIn(pre.substring(1, index + 1), - in.substring(0, index)); + in.substring(0, index)); // 重复逻辑,缩小范围 root.right = createBinaryTreeByPreAndIn( pre.substring(index + 1, pre.length()), - in.substring(index + 1, in.length())); + in.substring(index + 1, in.length())); // 重复逻辑,缩小范围 return root; } - return null; } /** @@ -371,20 +374,22 @@ public Node createBinaryTreeByPreAndIn(String pre, String in) { * @return */ public Node createBinaryTreeByInAndPost(String in, String post) { - if (post.length() > 0) { + if (post.length() <= 0) { //递归终止条件 + return null; // 简单情景 + }else{ Node root = new Node(post.charAt(post.length() - 1)); int index = in.indexOf(post.charAt(post.length() - 1)); - + root.left = createBinaryTreeByInAndPost(in.substring(0, index), - post.substring(0, index)); + post.substring(0, index)); // 重复逻辑,缩小范围 + root.right = createBinaryTreeByInAndPost( in.substring(index + 1, in.length()), - post.substring(index, post.length() - 1)); + post.substring(index, post.length() - 1)); // 重复逻辑,缩小范围 return root; } - return null; } - + /** * @description 根据原树的根结点复制出一颗一模一样的树 * @author rico