import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
BinaryThreadTree tree = new BinaryThreadTree();
System.out.println("Welcome to the threading tree system!\n");
Scanner sc = new Scanner(System.in);
int menu;
boolean active = true;
while (active) {
System.out.println("**********************************************************************************************");
System.out.println("1.Create a binary tree \t 2.Levelorder traversal \t 3.Preorder threading traversal \n" +
"4.Inorder threading traversal \t 5.Postorder threading traversal \t 6.The binary tree deepth \n" +
"7.Destroy the binary tree \t 8.Exit");
System.out.println("**********************************************************************************************");
System.out.print("----------Please type the menu number:");
menu = sc.nextInt();
sc.nextLine();
switch (menu) {
case 1:
System.out.println("Please enter several numbers as the tree items:");
String str = sc.nextLine();
String[] strs = str.split(" ");
int[] items = new int[strs.length];
for (int i = 0; i < strs.length; i++) {
items[i] = Integer.parseInt(strs[i]);
}
tree.createBinaryThreadTree(items);
System.out.println("The binary tree has been created!");
break;
case 2:
tree.levelorderTraversal();
break;
case 3:
tree.preorderThreadingTree();
tree.preorderTraversal();
tree.clearThreadingNode();
break;
case 4:
tree.inorderThreadingTree();
tree.inorderTraversal();
tree.clearThreadingNode();
break;
case 5:
tree.postorderThreadingTree();
tree.postorderTraversal();
tree.clearThreadingNode();
break;
case 7:
tree.destroyTree();
System.out.println("Destroy binary tree successfully!");
break;
case 6:
tree.printTreeDeepth();
break;
case 8:
System.out.println("Bye!");
active = false;
break;
default:
System.out.println("Please retype menu number!");
}
}
}
}
class BinaryThreadTreeNode {
public int leftTag;
public int rightTag;
public BinaryThreadTreeNode leftChild;
public BinaryThreadTreeNode rightChild;
public int data;
public BinaryThreadTreeNode(int data, BinaryThreadTreeNode leftChild, BinaryThreadTreeNode rightChild) {
this.data = data;
this.leftChild = leftChild;
this.rightChild = rightChild;
this.leftTag = 0;
this.rightTag = 0;
}
}
class BinaryThreadTree {
private BinaryThreadTreeNode root;
public BinaryThreadTree() {
root = null;
}
public void createBinaryThreadTree(int ... elements) {
BinaryThreadTreeNode p = null;
BinaryThreadTreeNode q = null;
Deque<BinaryThreadTreeNode> deque = new ArrayDeque<>();
for (int elem : elements) {
p = new BinaryThreadTreeNode(elem, null, null);
if (root == null) {
root = p;
} else {
deque.addLast(root);
while (!deque.isEmpty()) {
q = deque.pollFirst();
if (q.leftChild == null) {
q.leftChild = p;
break;
} else {
deque.addLast(q.leftChild);
}
if (q.rightChild == null) {
q.rightChild = p;
break;
} else {
deque.addLast(q.rightChild);
}
}
deque.clear();
}
}
}
private boolean checkTreeNull() {
if (root == null) {
System.out.println("The thread tree is empty!");
return true;
}
return false;
}
public void preorderThreadingTree() {
if (checkTreeNull()) {
return;
}
Deque<BinaryThreadTreeNode> deque = new ArrayDeque<>();
Deque<BinaryThreadTreeNode> dequeThreadNode = new ArrayDeque<>();
BinaryThreadTreeNode p = root;
BinaryThreadTreeNode q;
while (p != null || !deque.isEmpty()) {
while (p != null) {
deque.push(p);
if (!dequeThreadNode.isEmpty()) {
q = dequeThreadNode.pop();
q.rightTag = 1;
q.rightChild = p;
if (p.leftChild == null) {
p.leftChild = q;
p.leftTag = 1;
}
}
if (p.leftChild == null) {
p.leftChild = deque.getLast();
p.leftTag = 1;
}
if (p.rightChild == null) {
dequeThreadNode.push(p);
}
if (p.leftTag == 0) {
p = p.leftChild;
} else {
p = null;
}
}
p = deque.pop();
if (p.rightTag == 0) {
p = p.rightChild;
} else {
p = null;
}
}
}
private void threadingTree(Deque<BinaryThreadTreeNode> deque) {
if (deque.isEmpty()) {
return;
}
BinaryThreadTreeNode p;
BinaryThreadTreeNode q;
q = deque.pollFirst();
while (!deque.isEmpty()) {
p = deque.pollFirst();
if (q.rightChild == null) {
q.rightChild = p;
q.rightTag = 1;
}
if (p.leftChild == null) {
p.leftChild = q;
p.leftTag = 1;
}
q = p;
}
}
public void inorderThreadingTree() {
if (checkTreeNull()) {
return;
}
Deque<BinaryThreadTreeNode> deque = new ArrayDeque<>();
Deque<BinaryThreadTreeNode> dequeThreadNode = new ArrayDeque<>();
BinaryThreadTreeNode p = root;
while (p != null || !deque.isEmpty()) {
while (p != null) {
deque.push(p);
p = p.leftChild;
}
p = deque.pop();
dequeThreadNode.addLast(p);
p = p.rightChild;
}
threadingTree(dequeThreadNode);
}
public void postorderThreadingTree() {
if (checkTreeNull()) {
return;
}
Deque<BinaryThreadTreeNode> deque = new ArrayDeque<>();
Deque<Integer> dequeThreadTag = new ArrayDeque<>();
Deque<BinaryThreadTreeNode> dequeThreadNode = new ArrayDeque<>();
BinaryThreadTreeNode p = root;
while (p != null || !deque.isEmpty()) {
while (p != null) {
deque.push(p);
dequeThreadTag.push(0);
p = p.leftChild;
}
p = deque.pop();
if (dequeThreadTag.pop() == 0) {
dequeThreadTag.push(1);
deque.push(p);
} else {
dequeThreadNode.addLast(p);
p = null;
continue;
}
p = p.rightChild;
}
threadingTree(dequeThreadNode);
}
public void preorderTraversal() {
if (checkTreeNull()) {
return;
}
System.out.println("----------------------------------------------------------------");
BinaryThreadTreeNode p = root;
while ((p.leftChild != null && p.leftTag == 0) || p.rightTag == 1) {
printNodePlain(p);
if (p.rightTag == 1) {
p = p.rightChild;
} else {
p = p.leftChild;
}
if (p.leftTag == 1 && p.rightTag == 0) {
printNodePlain(p);
}
}
System.out.println("\n----------------------------------------------------------------");
}
public void inorderTraversal() {
if (checkTreeNull()) {
return;
}
System.out.println("----------------------------------------------------------------");
BinaryThreadTreeNode p = root;
boolean tag = true;
while (true) {
while (p.leftChild != null && p.leftTag == 0 && tag) {
p = p.leftChild;
}
printNodePlain(p);
if (p.rightChild != null) {
tag = p.rightTag == 1 ? false : true;
p = p.rightChild;
} else {
break;
}
}
System.out.println("\n----------------------------------------------------------------");
}
public void postorderTraversal() {
if (checkTreeNull()) {
return;
}
System.out.println("---------------------------------------------------------------");
Deque<BinaryThreadTreeNode> deque = new ArrayDeque<>();
Deque<Integer> dequeTag = new ArrayDeque<>();
BinaryThreadTreeNode p = root;
boolean find = true;
while (true) {
while (p.leftChild != null && p.leftTag != 1 && find) {
if (p.leftTag == 0 && p.rightTag == 0 && p.leftChild.leftTag == 0 && p.leftChild.rightTag == 0) {
deque.push(p);
dequeTag.push(0);
}
p = p.leftChild;
}
printNodePlain(p);
if (p == root) {
break;
}
if (p.rightTag == 1) {
p = p.rightChild;
if (p == deque.peekFirst()) {
deque.pop();
dequeTag.pop();
}
find = false;
} else {
p = deque.pop();
find = false;
if (dequeTag.pop() == 0) {
dequeTag.push(1);
deque.push(p);
p = p.rightChild;
find = true;
}
}
}
System.out.println("\n----------------------------------------------------------------");
}
private int getPreSpace(int level) {
int deepth = getTreeDeepth(root);
return (int)(deepth - (level + 1) < 0 ? -1 : Math.pow(2.0, (double)deepth - (level + 1)));
}
private int getSpace(int level) {
return (int)Math.pow(2.0, (double)getTreeDeepth(root) - level);
}
private int getLevel(BinaryThreadTreeNode root, BinaryThreadTreeNode node, int level) {
if (root == node) {
return level;
}
int findL = -1, findR = -1;
if (root.leftChild != null) {
findL = getLevel(root.leftChild, node, level + 1);
}
if (root.rightChild != null) {
findR = getLevel(root.rightChild, node, level + 1);
}
return findL == -1 ? (findR == -1 ? -1 : findR) : findL;
}
public void levelorderTraversal() {
if (checkTreeNull()) {
return;
}
System.out.println("----------------------------------------------------------------");
Deque<BinaryThreadTreeNode> deque = new ArrayDeque<>();
BinaryThreadTreeNode p = null;
int curLevel = -1, preSpace, space, level;
deque.addLast(root);
while (!deque.isEmpty()) {
p = deque.pollFirst();
level = getLevel(root, p, 1);
if (level != curLevel) {
if (curLevel != -1) {
System.out.println("\n");
}
curLevel = level;
preSpace = getPreSpace(curLevel);
if (preSpace == -1) {
System.out.print(" ");
} else {
for (int i = 0; i < preSpace; i++) {
System.out.print("\t");
}
}
}
space = getSpace(curLevel);
System.out.print(p.data);
for (int i = 0; i < space; i++) {
System.out.print("\t");
if (curLevel == getTreeDeepth(root)) {
System.out.print(" ");
}
}
if (p.leftChild != null && p.leftTag == 0) {
deque.addLast(p.leftChild);
}
if (p.rightChild != null && p.rightTag == 0) {
deque.addLast(p.rightChild);
}
}
System.out.println("\n----------------------------------------------------------------");
}
public void clearThreadingNode() {
Deque<BinaryThreadTreeNode> deque = new ArrayDeque<>();
BinaryThreadTreeNode p = null;
deque.addLast(root);
while (!deque.isEmpty()) {
p = deque.pollFirst();
if (p.leftTag != 0) {
p.leftTag = 0;
p.leftChild = null;
}
if (p.rightTag != 0) {
p.rightTag = 0;
p.rightChild = null;
}
if (p.leftChild != null) {
deque.addLast(p.leftChild);
}
if (p.rightChild != null) {
deque.addLast(p.rightChild);
}
}
}
private void printNode(BinaryThreadTreeNode node) {
System.out.println(node.data + "\t" + node.leftTag + "\t" + node.rightTag);
}
private void printNodePlain(BinaryThreadTreeNode node) {
System.out.print(node.data + "\t");
}
private int getTreeDeepth(BinaryThreadTreeNode root) {
if (root == null) {
return 0;
}
int leftCount, rightCount;
leftCount = getTreeDeepth(root.leftChild) + 1;
rightCount = getTreeDeepth(root.rightChild) + 1;
return leftCount > rightCount ? leftCount : rightCount;
}
public void printTreeDeepth() {
int deepth = getTreeDeepth(root);
System.out.println("The tree deepth is : " + deepth + " !");
}
public void destroyTree() {
this.root = null;
}
}