// 线索化二叉树操作
public class ThreadedTree<T extends Comparable<? super T>> {
public TreeNode<T> root;
public TreeNode<T> pre = null;
public ThreadedTree(TreeNode<T> root) {
this.root = root;
}
public ThreadedTree(){}
// 递归遍历
private void preTree(TreeNode<T> node){
if (node == null) return;
System.out.println(node.data);
preTree(node.left);
preTree(node.right);
}
private void infixTree(TreeNode<T> node){
if (node == null) return;
infixTree(node.left);
System.out.println(node.data);
infixTree(node.right);
}
private void afterTree(TreeNode<T> node){
if (node == null) return;
if (!node.leftType){
afterTree(node.left);
}
if (!node.rightType){
afterTree(node.right);
}
System.out.println(node.data);
}
public void preTree(){
this.preTree(root);
}
public void infixTree(){
this.infixTree(root);
}
public void afterTree(){
this.afterTree(root);
}
// add
public ThreadedTree<T> add(T data){
TreeNode<T> node = new TreeNode<>(data);
if (this.root == null) this.root = node;
else this.root.add(node);
return this;
}
// 线索化
private void preThreadedTree(TreeNode<T> node){
if (node == null) return;
if (node.left == null){
node.leftType = true;
node.left = pre;
}
if (pre != null && pre.right == null){
pre.right = node;
pre.rightType = true;
}
pre = node;
if (!node.leftType) preThreadedTree(node.left);
if (!node.rightType) preThreadedTree(node.right);
}
public void preThreadedTree(){
pre = null;
this.preThreadedTree(root);
}
private void infixThreadedTree(TreeNode<T> node){
if (node == null) return;
infixThreadedTree(node.left);
if (node.left == null){
node.left = pre;
node.leftType = true;
}
if (pre != null && pre.right == null){
pre.right = node;
pre.rightType = true;
}
pre = node;
infixThreadedTree(node.right);
}
public void infixThreadedTree(){
pre = null;
this.infixThreadedTree(root);
}
private void afterThreadedTree(TreeNode<T> node){
if (node == null) return;
afterThreadedTree(node.left);
afterThreadedTree(node.right);
if (node.left == null){
node.left = pre;
node.leftType = true;
}
if (pre != null && pre.right == null){
pre.right = node;
pre.rightType = true;
}
pre = node;
}
public void afterThreadedTree(){
pre = null;
this.afterThreadedTree(root);
}
// 清除线索
private void clearThreaded(TreeNode<T> node){
if (node == null) return;
if (node.leftType){
node.leftType = false;
node.left = null;
}else{
clearThreaded(node.left);
}
if (node.rightType){
node.rightType = false;
node.right = null;
}else{
clearThreaded(node.right);
}
}
public void clearThreaded(){
this.clearThreaded(root);
}
// 线索化遍历
public void preThreadedPrint(){
if (root == null) return;
TreeNode<T> node = root;
while (node != null){
while (!node.leftType){ // 递归当前子树的左节点,输出
System.out.println(node.data);
node = node.left;
}
System.out.println(node.data);
node = node.right; // 该语句区别于中序线索遍历,可以通过画图理解
}
}
public void infixThreadedPrint(){
if (root == null) return;
TreeNode<T> node = root;
while (node != null){ // 遍历到当前子树的第一个节点
while (!node.leftType){
node = node.left;
}
System.out.println(node.data);
while (node.rightType){ // 后驱节点,只管输出(因为当前节点的下一个就是后驱节点)
node = node.right;
System.out.println(node.data);
}
node = node.right;
// 不写会死归,理解 当前树遍历(先找到第一个节点-也就是最左子节点,然后经过上面2次while操作后,返回到当前子树的第一个节点
// 而 这步操作保证node 指向 当前子树的下一个节点)
}
}
// 后续线索化遍历 仍采用递归方式(相较于常规遍历没有明显的提升)
/*
情况有4:
1. 当前node就是根节点,没有父亲节点 打印结束 退出
2. 当前节点是其父亲节点的左节点,且其父亲节点的左节点为空(node == node.parent.left && node.parent.rightType = false)
或者 当前节点是其父亲节点的右节点(node == node.parent.right)
则 节点变更为其父亲节点(node = node.parent)
3. 当前节点是其父亲节点的左节点且其父亲节点的右节点不为空,则 node = 其父亲节点的右子树的第一个打印节点
*/
public void afterThreadedPrint(TreeNode<T> node){
// 找到当前子树第一个节点
while (true){ // 当当前节点为当前子树第一个输出的节点
while (!node.leftType){
node = node.left;
}
if (!node.rightType){
node = node.right;
}
if (node.rightType && node.leftType || node.rightType && node.left == null){
break;
}
}
System.out.println(node.data); // 当前子树的第一个节点打印
// 遍历节点直到不是右驱节点
while (node.rightType){
node = node.right;
System.out.println(node.data);
}
// 按情况判断下一个节点=?,可以划分3种情况(树的根节点必定是最后一个打印),
boolean condition2 = true; // 用于情况2 下一个节点为父节点,无需当做子树处理
while (condition2){
condition2 = false;
if (node == root){
}
else if (node == node.parent.right || (node == node.parent.left && node.parent.rightType )){
node = node.parent;
System.out.println(node.data);
condition2 = true;
}
else if(node.parent.right == null){ // 这种属于额外情况:父节点没有右子节点
System.out.println(node.parent.data);
}
else if(node == node.parent.left && !node.parent.rightType){
// 递归当前节点的父节点的右子节点
afterThreadedPrint(node.parent.right);
}
}
}
public void afterThreadedPrint(){
this.afterThreadedPrint(root);
}
}
class TreeNode<T extends Comparable<? super T>>{
public T data;
public TreeNode<T> left;
public TreeNode<T> right;
public TreeNode<T> parent;
public Boolean leftType = false;
public Boolean rightType= false;
public TreeNode(T data){
this.data = data;
}
public void add(TreeNode<T> node){
if (this.data.compareTo(node.data) == 0){
System.out.println("value repeat");
}else if (this.data.compareTo(node.data) > 0){
if (this.left == null){
this.left = node;
node.parent = this;
return;
}
this.left.add(node);
}else if (this.data.compareTo(node.data) < 0){
if (this.right == null){
this.right = node;
node.parent = this;
return;
}
this.right.add(node);
}
}
}
class TestForThreadedTree{
public static void main(String[] args) {
ThreadedTree<Integer> tree = new ThreadedTree<>();
// tree.add(30).add(20).add(13).add(18).add(10).add(25).add(12) ;
// tree.add(12).add(13).add(14).add(15).add(19).add(16);
tree.add(20).add(13).add(25).add(18).add(10).add(30).add(24);
// 后续线索化、遍历测试
tree.afterThreadedTree();
tree.afterThreadedPrint();
tree.clearThreaded();
// 中序线索化、遍历测试
tree.infixThreadedTree();
tree.infixThreadedPrint();
tree.clearThreaded();
// 前序线索化、遍历测试
tree.preThreadedTree();
tree.preThreadedPrint();
}
}
线索化、遍历二叉树
于 2022-04-30 09:19:05 首次发布