下面是作业要求:
ICSI 213 Data Structures Lab
Week 12 Lab 7, November 27th.
Topics:
Binary Search Tree
Study materials:
See lecture notes and relevant materials from the textbook.Instructions:
Write a program that can convert a sorted array into a binary search tree. The program allows the user to enter a number n, generates an array of n random integers, sorts the array, and then converts the sorted array into a binary search tree. You can display the tree by printing each node, its left child, and its right child per line.
ICSI 213数据结构实验课
第12周实验7,11月27日。
话题:
二进制搜索树
学习资料:
参阅教科书中的讲义和相关材料。说明:
编写一个可以将排序数组转换为二叉搜索树的程序。 该程序允许用户输入数字n,生成n个随机整数数组,对数组进行排序,然后将排序后的数组转换为二叉搜索树。 您可以通过每行打印每个节点,其左子节点和右子节点来显示树。
实验课作业,反正必须写,不如写点好玩儿的东西,用上了前段时间刷屏的“老板有毛病吧,写完排序就让我走”这个段子里的睡眠排序大法。
其实睡眠排序问题很多,比如不能排负数;当数字相差很小,会不精准;当出现一个很大的数字,会睡眠很长时间。总而言之,在实际生活中,这玩意儿没什么卵用,但是不妨在无关紧要的地方写着玩儿。
其实在把睡眠排序用到作业里的过程中遇到了不少问题,最大的问题就是排序的结果不容易取出来,一是睡眠排序的原理决定了你没办法用数组来存结果,因为你也不知道谁先出来,二是多线程用静态全局变量也不能被各个线程读到,第一个问题还算好办,每当一个线程睡眠完毕,就往一个stack里push这个元素就好了,但是第二个问题就没那么方便,只能想办法让多个线程之间共享数据,最后的解决方案是将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个SortThread对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样实现针对该数据进行的各个操作的互斥和通信。
这还没完,各个SortThread还没跑完,主线程就已经开始试图从stack里取数据了,当然什么都没有,于是被糊了一脸bug,还出现了一边抱错一边输出正确结果的奇观,(一些SortThread跑完就有结果了),每个SortThread跑的时间不一样于是只能按照SortThread可能的最长时间来让主线程等着,取到stack后还不能直接发回去(这个stack在ShareData里),要把他往SleepSort里的另外一个stack里来倒腾一遍然后才能return回去。
大致的坑就这么多,代码在下面。
-
Driver.java
import Controller.Controller;
/**
* filename: Driver.java
* @author:Xu Wanxiang
* date:2018.11.27
* description: this class start the project.
* @version 1.0
*/
public class Driver {
public static void main(String[] args) {
new Controller();
}
}
-
Controller.java
package Controller;
import java.util.*;
import BinarySearchTree.*;
import Sort.*;
/**
* filename: Controller.java
* package:Controller
* @author:Xu Wanxiang
* date:2018.11.27
* description: this class let the user to choose the function that they want to use.
* @version 1.0
*/
public class Controller {
public static Stack stack = new Stack();
public Controller(){
System.out.println("Please type the size of the tree you wish to generate");
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
List<Integer> al = new ArrayList<>();
for(int i = 0;i < n;i ++){
Random randon = new Random();
int r = randon.nextInt(100);
al.add(r);
}
System.out.print(al);
System.out.println("\n");
int[]AL = new int[al.size()];
for (int i = 0;i < al.size();i ++){
AL[i] = al.get(i);
}
SleepSort SS = new SleepSort(AL);
stack = SS.getStack();
BinarySearchTree<Integer, String> bst = new BinarySearchTree<Integer, String>();
// while((!stack.empty())){
// System.out.println((int)stack.pop());
// }
while (!(stack.empty())){
bst.insert((int)stack.pop(),"a");
}
//print begin by root of the BinarySearchTree
TreePrintUtil.pirnt(bst.getRoot());
}
}
-
SleepSort.java
package Sort;
import java.util.*;
import Controller.*;
/**
* filename: SleepSort.java
* package:Sort
* @author:Xu Wanxiang
* date:2018.11.27
* description: this class sort a array.
* @version 1.0
*/
public class SleepSort {
public Stack<Integer> stack2 = new Stack<Integer>();
// Create a stack object
public SleepSort(int[] arr){
final ShareData shareData = new ShareData();
//Create a sleep thread
SortThread[] sortThreads = new SortThread[arr.length];
//Initialize sleep thread
for (int i = 0; i < sortThreads.length; i++) {
sortThreads[i] = new SortThread(arr[i],shareData);
}
for (int i = 0; i < sortThreads.length; i++) {
sortThreads[i].start();
}
try { Thread.sleep ( 10000 ) ;
} catch (InterruptedException ie){}
while (!shareData.getStack().empty()){
stack2.push(shareData.getStack().pop());
}
}
public Stack getStack(){
return stack2;
}
class SortThread extends Thread{
public int ms;
private ShareData shareData;
public SortThread(int s,ShareData shareData){
this.shareData = shareData;
this.ms = s;
}
public void run(){
try {
sleep(ms*10+10); //Sleep specified time
} catch (InterruptedException e) {
e.printStackTrace();
}
// System.out.println(ms);
shareData.sent(ms);
}
}
static class ShareData{
Stack<Integer> stack = new Stack<Integer>();
public synchronized void sent(int ms){
stack.push(ms);
}
public Stack<Integer> getStack() {
return stack;
}
}
}
-
TreeNode.java
package BinarySearchTree;
/**
* filename: TreeNode.java
* package:BinarySearchTree
* @author:Xu Wanxiang
* date:2018.11.27
* description: this class is TreeNode.
* @version 1.0
*/
public interface TreeNode {
String getPrintInfo();
TreeNode getLeftChild();
TreeNode getRightChild();
}
-
BinarySearchTree.java
package BinarySearchTree;
/**
* filename: BinarySearchTree.java
* package:BinarySearchTree
* @author:Xu Wanxiang
* date:2018.11.27
* description: this class construct BinarySearchTree.
* @version 1.0
*/
public class BinarySearchTree<K extends Comparable<K>, V> {
private int count;
private Node<K, V> root;
private int maxLevel;
public int size() {
return count;
}
public boolean isEmpty() {
return count == 0;
}
public void insert(K k, V v) {
Node<K, V> node = new Node<>(k, v);
if (insertToNode(root, node, 0)) {
// If it is inserted, count+1
count++;
}
}
public Node getRoot() {
return root;
}
/**
*
* @param parint
* @param node
* @return If the new returns true, if only the update returns false
*/
private boolean insertToNode(Node<K, V> parent, Node<K, V> node, int level) {
if (root == null) {
root = node;
maxLevel = 1;
return true;
}
if (parent.k.compareTo(node.k) == 0) {
// update if key is the same
parent.v = node.v;
return false;
} else if (parent.k.compareTo(node.k) < 0) {
// If node is larger than parent, insert it into the right subtree
if (parent.right == null) {
parent.right = node;
if (level + 1 > maxLevel) {
maxLevel = level + 1;
}
return true;
}
return insertToNode(parent.right, node, level + 1);
} else {
// If the node is smaller than the parent, insert the left subtree
if (parent.left == null) {
parent.left = node;
if (level + 1 > maxLevel) {
maxLevel = level + 1;
}
return true;
}
return insertToNode(parent.left, node, level + 1);
}
}
private static class Node<K extends Comparable<K>, V> implements TreeNode {
K k;
V v;
Node left, right;
public Node(K k, V v) {
this.k = k;
this.v = v;
}
@Override
public String toString() {
return "[" + k + "]";
}
@Override
public String getPrintInfo() {
return toString();
}
@Override
public TreeNode getLeftChild() {
// TODO Auto-generated method stub
return left;
}
@Override
public TreeNode getRightChild() {
// TODO Auto-generated method stub
return right;
}
}
}
-
TreePrintUtil.java
package BinarySearchTree;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* filename: TreePrintUtil.java
* package:BinarySearchTree
* @author:Xu Wanxiang
* date:2018.11.27
* description: this class print the BinarySearchTree just like a tree.
* @version 1.0
*/
public class TreePrintUtil {
public static void pirnt(TreeNode root) {
// Find the maximum offset on the left
int maxLeftOffset = findMaxOffset(root, 0, true);
int maxRightOffset = findMaxOffset(root, 0, false);
int offset = Math.max(maxLeftOffset, maxRightOffset);
// Calculate the maximum offset
Map<Integer, PrintLine> lineMap = new HashMap();
calculateLines(root, offset, lineMap, 0, true);
Iterator<Integer> lineNumbers = lineMap.keySet().iterator();
int maxLine = 0;
while (lineNumbers.hasNext()) {
int lineNumber = lineNumbers.next();
if (lineNumber > maxLine) {
maxLine = lineNumber;
}
}
for (int i = 0; i <= maxLine; i++) {
PrintLine line = lineMap.get(i);
if (line != null) {
System.out.println(line.getLineString());
}
}
}
private static void calculateLines(TreeNode parent, int offset, Map<Integer, PrintLine> lineMap, int level,
boolean right) {
if (parent == null) {
return;
}
int nameoffset = parent.toString().length() / 2;
PrintLine line = lineMap.get(level);
if (line == null) {
line = new PrintLine();
lineMap.put(level, line);
}
line.putString(right ? offset : (offset - nameoffset), parent.toString());
// Determine if there is a next level
if (parent.getLeftChild() == null && parent.getRightChild() == null) {
return;
}
// If there is, add a split line/\
PrintLine separateLine = lineMap.get(level + 1);
if (separateLine == null) {
separateLine = new PrintLine();
lineMap.put(level + 1, separateLine);
}
if (parent.getLeftChild() != null) {
separateLine.putString(offset - 1, "/");
calculateLines(parent.getLeftChild(), offset - nameoffset - 1, lineMap, level + 2, false);
}
if (parent.getRightChild() != null) {
separateLine.putString(offset + nameoffset + 1, "\\");
calculateLines(parent.getRightChild(), offset + nameoffset + 1, lineMap, level + 2, true);
}
}
private static class PrintLine {
/**
* record map of offset and String
*/
Map<Integer, String> printItemsMap = new HashMap<>();
int maxOffset = 0;
public void putString(int offset, String info) {
printItemsMap.put(offset, info);
if (offset > maxOffset) {
maxOffset = offset;
}
}
public String getLineString() {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i <= maxOffset; i++) {
String info = printItemsMap.get(i);
if (info == null) {
buffer.append(" ");
} else {
buffer.append(info);
i += info.length();
}
}
return buffer.toString();
}
}
private static int findMaxOffset(TreeNode parent, int offset, boolean findLeft) {
if (parent != null) {
offset += parent.toString().length();
}
if (findLeft && parent.getLeftChild() != null) {
offset += 1;
return findMaxOffset(parent.getLeftChild(), offset, findLeft);
}
if (!findLeft && parent.getRightChild() != null) {
return findMaxOffset(parent.getRightChild(), offset, findLeft);
}
return offset;
}
}
-
test.java
package Test;
import Controller.Controller;
import Sort.SleepSort;
import BinarySearchTree.*;
/**
* filename: test.java
* package:Test
* @author:Xu Wanxiang
* date:2018.11.27
* description: this class test the project.
* @version 1.0
*/
public class test {
public static void main(String[] args) {
BinarySearchTree<Integer, String> bst = new BinarySearchTree<Integer, String>();
bst.insert(10, "a");
bst.insert(15, "b");
bst.insert(5, "d");
bst.insert(9, "e");
bst.insert(33, "f");
bst.insert(38, "g");
bst.insert(1, "h");
bst.insert(0, "i");
bst.insert(90, "j");
bst.insert(100, "k");
bst.insert(7, "l");
bst.insert(1, "m");
//从根开始打印
TreePrintUtil.pirnt(bst.getRoot());
}
}