代码实现
package Tree.BinaryTree; //顺序存储二叉树 public class ArrBinaryTree { public static void main(String[] args) { int[] arr = {1, 2, 3, 4, 5, 6, 7}; ArrTree tree = new ArrTree(arr); tree.preOrder(); System.out.println(); tree.infixOrder(); System.out.println(); tree.postOrder(); System.out.println(); } } //编写一个ArrBinaryTree,实现顺序存储二叉树遍历 class ArrTree { private int[] arr; public ArrTree(int[] arr) { this.arr = arr; } //重载后外部无需再输入参数下标 public void preOrder() { this.preOrder(0); } public void infixOrder() { this.infixOrder(0); } public void postOrder() { this.postOrder(0); } //前序遍历 public void preOrder(int index) {//数组下标 if (arr == null || arr.length == 0) { System.out.println("数组为空,无法遍历"); return; } System.out.print(arr[index] + " "); //向左遍历递归 if (index * 2 + 1 < arr.length) { preOrder(index * 2 + 1); } if (index * 2 + 2 < arr.length) { preOrder(index * 2 + 2); } } //中序遍历 public void infixOrder(int index) {//数组下标 if (arr == null || arr.length == 0) { System.out.println("数组为空,无法遍历"); return; } if (index * 2 + 1 < arr.length) { infixOrder(index * 2 + 1); } System.out.print(arr[index] + " "); if (index * 2 + 2 < arr.length) { infixOrder(index * 2 + 2); } } //后序遍历 public void postOrder(int index) {//数组下标 if (arr == null || arr.length == 0) { System.out.println("数组为空,无法遍历"); return; } if (index * 2 + 1 < arr.length) { postOrder(index * 2 + 1); } if (index * 2 + 2 < arr.length) { postOrder(index * 2 + 2); } System.out.print(arr[index] + " "); } }
注:
1、n个节点共有2n个指针,除去根节点的其他n-1个节点,会占用对应父节点的一个指针,因此,空指针的数量等于二者相减
2、节点=》该节点
数组中打头的没有前驱节点,末尾的没有后继节点
说明中的情况要在代码中体现
思路分析
1、先取到要遍历的第一个节点(第一个lefttType=1但left=0的节点)
2、如果后驱节点一直存在,就一直输出,直到遇到right域指向的是右子树的节点时(即rightType=0时),将当前临时节点node替换为此节点
3、继续通过新的node节点执行上述的操作,直到right指向为空
解释:因为实现线索化二叉树中是通过下个节点的pre来设置后驱节点,而最后一个节点无下个节点,不会被设置后驱,rightTpye=0所以走外层while:通过右子树是否为空这个条件,作为判断是否实现全部二叉树的线索化遍历的依据
重要提示:在中序线索化中,是在回溯的过程中进行节点的pre域进行操作,因此递归不需要对pre指向的是前驱节点还是左子树进行判断;而在前序线索化中,是先进行了节点操作后进行递归,因此在递归时有必要判断,即递归的条件是leftType=0
代码实现
package Tree.ThreadedBinaryTree; public class ThreadedBinaryTree { public static void main(String[] args) { HeroNode root = new HeroNode(1, "1"); HeroNode n2 = new HeroNode(3, "3"); HeroNode n3 = new HeroNode(6, "6"); HeroNode n4 = new HeroNode(8, "8"); HeroNode n5 = new HeroNode(10, "10"); HeroNode n6 = new HeroNode(14, "14"); root.left = n2; root.right = n3; n2.left = n4; n2.right = n5; n3.left = n6; ThreadTree tree = new ThreadTree(); tree.setRoot(root); // tree.threadedInfixNodes(); //找一个点做验证,10的前后是否是3和1 // System.out.println(n6.left); // System.out.println(n6.right); // tree.threadedInfixList(); System.out.println("==============="); // tree.threadedPreNodes(); // System.out.println(n4.left); // System.out.println(n4.right); // tree.threadedPreList(); tree.threadedPostNodes(); // System.out.println(n4.left); // System.out.println(n4.right); tree.threadedPostList(); } } //定义一个树 class ThreadTree { private HeroNode root; //为了实现线索化,需要创建一个指向当前节点的前驱节点的指针 //在递归仅限线索化时,pre始终保留前一个结点 private HeroNode pre = null; public void setRoot(HeroNode root) { this.root = root; } //重载 public void threadedInfixNodes() { this.threadedInfixNodes(root); } public void threadedPreNodes() { this.threadedPreNodes(root); } public void threadedPostNodes() { this.threadedPostNodes(root); } //二叉树前序线索化 public void threadedPreNodes(HeroNode node) { if (node == null) { return; } //左指针为空时,指向前驱节点 if (node.left == null) { node.left = pre; node.leftType = 1; } //后继节点是在下一次处理的(在下一个节点中,用pre表示上一个节点然后进行设置) //最后一个节点没有下一个节点,自然也就没有了后继节点 if (pre != null && pre.right == null) { pre.right = node; pre.rightType = 1; } pre = node; //处理左子树 if (node.leftType == 0) { threadedPreNodes(node.left); } //处理右子树 if (node.rightType == 0) { threadedPreNodes(node.right); } } //二叉树中序线索化 public void threadedInfixNodes(HeroNode node) {//需要线索化的节点 if (node == null) { return; } ; //先线索化左子树、再当前节点、再右子树 threadedInfixNodes(node.left); //线索化当前节点 if (node.left == null) {//前驱节点使用pre node.left = pre; node.leftType = 1; } //后继节点是在下一次处理的(在下一个节点中,用pre表示上一个节点然后进行设置) //最后一个节点没有下一个节点,自然也就没有了后继节点 if (pre != null && pre.right == null) { pre.right = node; pre.rightType = 1; } pre = node; threadedInfixNodes(node.right); } //二叉树后序线索化 public void threadedPostNodes(HeroNode node) { if (node == null) { return; } //处理左子树 if (node.leftType == 0) { threadedPostNodes(node.left); } //处理右子树 if (node.rightType == 0) { threadedPostNodes(node.right); } //左指针为空时,指向前驱节点 if (node.left == null) { node.left = pre; node.leftType = 1; } //后继节点是在下一次处理的(在下一个节点中,用pre表示上一个节点然后进行设置) //最后一个节点没有下一个节点,自然也就没有了后继节点 if (pre != null && pre.right == null) { pre.right = node; pre.rightType = 1; } pre = node; } //线索化前序遍历 public void threadedPreList() { HeroNode node = root; while (node != null) { //循环的找到leftType=1的节点 while (node.leftType == 0) {//第一个leftType=1的节点就是首节点 System.out.println(node); node = node.left; } //打印当前这个节点 System.out.println(node); node = node.right; } } //线索化中序遍历 public void threadedInfixList() { //定义一个临时变量,存储当前遍历的节点,从root开始 HeroNode node = root; while (node != null) { //循环的找到leftType=1的节点 while (node.leftType == 0) {//第一个leftType=1的节点就是首节点 node = node.left; } //打印当前这个节点 System.out.println(node); //如果当前节点的右指针指向的是后继节点,就一直输出 while (node.rightType == 1) { node = node.right; System.out.println(node); } //while结束时,说明遇到了右指针指向的是右子树的节点, // 此时把这个节点替换为node,重复进行新一轮的while操作 node = node.right; } } //线索化后序遍历 public void threadedPostList() { //定义一个临时变量,存储当前遍历的节点,从root开始 HeroNode node = root; //找后序遍历开始的节点 HeroNode pre = null; while (node != null && node.leftType == 0) { node = node.left; } while (node!=null){ if (node.rightType==1){ System.out.println(node); pre=node; node=node.right; } else { //如果上个处理的节点是当前节点的右节点 if (node.right==pre){ System.out.println(node); if (node==root){ return; } pre = node; node=node.parent; } else {//如果是从左节点进入则找到有子树的最左节点 node=node.right; while (node!=null&&node.leftType==0){ node=node.left; } } } } } //前序遍历 public void preOrder() { if (root != null) { this.root.preOrder(); } else { System.out.println("当前二叉树为空,无法遍历"); } } //中序遍历 public void infixOrder() { if (root != null) { this.root.infixOrder(); } else { System.out.println("当前二叉树为空,无法遍历"); } } //后序遍历 public void postOrder() { if (root != null) { this.root.postOrder(); } else { System.out.println("当前二叉树为空,无法遍历"); } } //前序查找 public HeroNode preOrderSearch(int no) { if (root != null) { HeroNode res = this.root.preOrderSearch(no); if (res.no == no) { return res; } return null; } else { return null; } } //中序查找 public HeroNode infixOrderSearch(int no) { if (root != null) { HeroNode res = this.root.infixOrderSearch(no); if (res.no == no) { return res; } return null; } else { return null; } } //后序查找 public HeroNode postOrderSearch(int no) { if (root != null) { HeroNode res = this.root.postOrderSearch(no); if (res.no == no) { return res; } return null; } else { return null; } } //删除 public void del(int no) { if (root != null) { if (root.no == no) { root = null; } else { this.root.del(no); } } else { System.out.println("二叉树为空,无法继续删除"); } } } //先创建HeroNode节点 class HeroNode { public int no; public String name; public HeroNode left; public HeroNode right; public int leftType;//等于0代表是左子树,等于1代表是前驱节点 public int rightType; public HeroNode parent; public HeroNode() { } public HeroNode(int no, String name) { this.no = no; this.name = name; } @Override public String toString() { return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + '}'; } //前序遍历的方法 public void preOrder() { System.out.println(this);//先输出当前节点(初始化时是根节点) if (this.left != null) {//向左递归前序遍历 this.left.preOrder(); } if (this.right != null) {//向右递归前序遍历 this.right.preOrder(); } } //中序遍历的方法 public void infixOrder() { if (this.left != null) { this.left.infixOrder(); } System.out.println(this); if (this.right != null) { this.right.infixOrder(); } } //后序遍历的方法 public void postOrder() { if (this.left != null) { this.left.postOrder(); } if (this.right != null) { this.right.postOrder(); } System.out.println(this); } //前序查找 public HeroNode preOrderSearch(int no) { //先判断父节点 if (this.no == no) { return this; } else { HeroNode resNode = null; if (this.left != null) {//递归前序查找 resNode = this.left.preOrderSearch(no); } if (resNode != null) {//说明左子树找到 return resNode; } if (this.right != null) { resNode = this.right.preOrderSearch(no); } return resNode;//为空说明都没找到,不为空说明在右子树找到,最后的判断放在上层做 } } //中序查找 public HeroNode infixOrderSearch(int no) { HeroNode resNode = null; if (this.left != null) {//递归前序查找 resNode = this.left.infixOrderSearch(no); } if (resNode != null) {//说明左子树找到 return resNode; } if (this.no == no) { return this; } if (this.right != null) { resNode = this.right.infixOrderSearch(no); } return resNode; } //后序查找 public HeroNode postOrderSearch(int no) { HeroNode resNode = null; if (this.left != null) { resNode = this.left.postOrderSearch(no); } if (resNode != null) { return resNode; } if (this.right != null) { resNode = this.right.postOrderSearch(no); } if (resNode != null) { return resNode; } return this; } //删除 public void del(int no) { if (this.left != null && this.left.no == no) { if (this.left.left != null) { this.left = this.left.left; } else if (this.left.right != null) { this.left = this.left.right; } else { this.left = null; } return; } if (this.right != null && this.right.no == no) { if (this.right.left != null) { this.right = this.right.left; } else if (this.right.right != null) { this.right = this.right.right; } else { this.right = null; } return; } if (this.left != null) { this.left.del(no); } if (this.right != null) { this.right.del(no); } } }