能提高数据存储,读取的效率, 比如利用 二叉排序树(Binary Sort Tree),既可以保证数据的检索速度,同时也可以保证数据的插入,删除,修改的速度。
前序遍历: 先输出父节点,再遍历左子树和右子树
中序遍历: 先遍历左子树,再输出父节点,再遍历右子树
后序遍历: 先遍历左子树,再遍历右子树,最后输出父节点
小结: 看输出父节点的顺序,就确定是前序,中序还是后序
示例:
将下列二叉树 前序、中序、后序输出
1 package com.tree; 2 3 /** 4 * Created by wanbf on 2019/7/9. 5 */ 6 7 public class BinaryTreeDemo { 8 9 public static void main(String[] args) { 10 //先需要创建一颗二叉树 11 BinaryTree binaryTree = new BinaryTree(); 12 //创建需要的结点 13 HeroNode root = new HeroNode(1, "宋江"); 14 HeroNode node2 = new HeroNode(2, "吴用"); 15 HeroNode node3 = new HeroNode(3, "卢俊义"); 16 HeroNode node4 = new HeroNode(4, "林冲"); 17 //HeroNode node5 = new HeroNode(5, "关胜"); 18 19 //说明,我们先手动创建该二叉树,后面我们学习递归的方式创建二叉树 20 root.setLeft(node2); 21 root.setRight(node3); 22 node3.setRight(node4); 23 //node3.setLeft(node5); 24 binaryTree.setRoot(root); 25 26 //测试 27 System.out.println("前序遍历"); // 1,2,3,4 28 binaryTree.preOrder(); 29 30 //测试 31 System.out.println("中序遍历"); 32 binaryTree.infixOrder(); // 2,1,3,4 33 34 System.out.println("后序遍历"); 35 binaryTree.postOrder(); // 2,4,3,1 36 37 } 38 39 } 40 41 42 43 44 //定义BinaryTree 二叉树 45 class BinaryTree { 46 private HeroNode root; 47 48 public void setRoot(HeroNode root) { 49 this.root = root; 50 } 51 //前序遍历 52 public void preOrder() { 53 if(this.root != null) { 54 this.root.preOrder(); 55 }else { 56 System.out.println("二叉树为空,无法遍历"); 57 } 58 } 59 60 //中序遍历 61 public void infixOrder() { 62 if(this.root != null) { 63 this.root.infixOrder(); 64 }else { 65 System.out.println("二叉树为空,无法遍历"); 66 } 67 } 68 //后序遍历 69 public void postOrder() { 70 if(this.root != null) { 71 this.root.postOrder(); 72 }else { 73 System.out.println("二叉树为空,无法遍历"); 74 } 75 } 76 } 77 78 79 //先创建HeroNode 结点 80 class HeroNode { 81 private int no; 82 private String name; 83 private HeroNode left; //默认null 84 private HeroNode right; //默认null 85 public HeroNode(int no, String name) { 86 this.no = no; 87 this.name = name; 88 } 89 public int getNo() { 90 return no; 91 } 92 public void setNo(int no) { 93 this.no = no; 94 } 95 public String getName() { 96 return name; 97 } 98 public void setName(String name) { 99 this.name = name; 100 } 101 public HeroNode getLeft() { 102 return left; 103 } 104 public void setLeft(HeroNode left) { 105 this.left = left; 106 } 107 public HeroNode getRight() { 108 return right; 109 } 110 public void setRight(HeroNode right) { 111 this.right = right; 112 } 113 @Override 114 public String toString() { 115 return "HeroNode [no=" + no + ", name=" + name + "]"; 116 } 117 118 //编写前序遍历的方法 119 public void preOrder() { 120 System.out.println(this); //先输出父结点 121 //递归向左子树前序遍历 122 if(this.left != null) { 123 this.left.preOrder(); 124 } 125 //递归向右子树前序遍历 126 if(this.right != null) { 127 this.right.preOrder(); 128 } 129 } 130 //中序遍历 131 public void infixOrder() { 132 133 //递归向左子树中序遍历 134 if(this.left != null) { 135 this.left.infixOrder(); 136 } 137 //输出父结点 138 System.out.println(this); 139 //递归向右子树中序遍历 140 if(this.right != null) { 141 this.right.infixOrder(); 142 } 143 } 144 //后序遍历 145 public void postOrder() { 146 if(this.left != null) { 147 this.left.postOrder(); 148 } 149 if(this.right != null) { 150 this.right.postOrder(); 151 } 152 System.out.println(this); 153 } 154 }
1 前序遍历 2 HeroNode [no=1, name=宋江] 3 HeroNode [no=2, name=吴用] 4 HeroNode [no=3, name=卢俊义] 5 HeroNode [no=4, name=林冲] 6 中序遍历 7 HeroNode [no=2, name=吴用] 8 HeroNode [no=1, name=宋江] 9 HeroNode [no=3, name=卢俊义] 10 HeroNode [no=4, name=林冲] 11 后序遍历 12 HeroNode [no=2, name=吴用] 13 HeroNode [no=4, name=林冲] 14 HeroNode [no=3, name=卢俊义] 15 HeroNode [no=1, name=宋江]
前上图的 3号节点 "卢俊" , 增加一个左子节点 [5, 关胜]
使用前序,中序,后序遍历,请写出各自输出的顺序是什么?
1 public static void main(String[] args) { 2 //先需要创建一颗二叉树 3 BinaryTree binaryTree = new BinaryTree(); 4 //创建需要的结点 5 HeroNode root = new HeroNode(1, "宋江"); 6 HeroNode node2 = new HeroNode(2, "吴用"); 7 HeroNode node3 = new HeroNode(3, "卢俊义"); 8 HeroNode node4 = new HeroNode(4, "林冲"); 9 HeroNode node5 = new HeroNode(5, "关胜"); 10 11 //说明,我们先手动创建该二叉树,后面我们学习递归的方式创建二叉树 12 root.setLeft(node2); 13 root.setRight(node3); 14 node3.setRight(node4); 15 node3.setLeft(node5); 16 binaryTree.setRoot(root); 17 18 //测试 19 System.out.println("前序遍历"); // 1,2,3,5,4 20 binaryTree.preOrder(); 21 22 //测试 23 System.out.println("中序遍历"); 24 binaryTree.infixOrder(); // 2,1,5,3,4 25 26 System.out.println("后序遍历"); 27 binaryTree.postOrder(); // 2,5,4,3,1 28 29 }
1 前序遍历 2 HeroNode [no=1, name=宋江] 3 HeroNode [no=2, name=吴用] 4 HeroNode [no=3, name=卢俊义] 5 HeroNode [no=5, name=关胜] 6 HeroNode [no=4, name=林冲] 7 中序遍历 8 HeroNode [no=2, name=吴用] 9 HeroNode [no=1, name=宋江] 10 HeroNode [no=5, name=关胜] 11 HeroNode [no=3, name=卢俊义] 12 HeroNode [no=4, name=林冲] 13 后序遍历 14 HeroNode [no=2, name=吴用] 15 HeroNode [no=5, name=关胜] 16 HeroNode [no=4, name=林冲] 17 HeroNode [no=3, name=卢俊义] 18 HeroNode [no=1, name=宋江]
1.编写前序查找,中序查找和后序查找的方法。
2.并分别使用三种查找方式,查找 heroNO = 5 的节点
3.并分析各种查找方式,分别比较了多少次
思路分析
1 /** 2 * Created by wanbf on 2019/7/9. 3 */ 4 public class BinaryTreeDemo { 5 6 public static void main(String[] args) { 7 //先需要创建一颗二叉树 8 BinaryTree binaryTree = new BinaryTree(); 9 //创建需要的结点 10 HeroNode root = new HeroNode(1, "宋江"); 11 HeroNode node2 = new HeroNode(2, "吴用"); 12 HeroNode node3 = new HeroNode(3, "卢俊义"); 13 HeroNode node4 = new HeroNode(4, "林冲"); 14 HeroNode node5 = new HeroNode(5, "关胜"); 15 16 //说明,我们先手动创建该二叉树,后面我们学习递归的方式创建二叉树 17 root.setLeft(node2); 18 root.setRight(node3); 19 node3.setRight(node4); 20 node3.setLeft(node5); 21 binaryTree.setRoot(root); 22 23 //前序遍历 24 //前序遍历的次数 :4 25 System.out.println("前序遍历方式~~~"); 26 HeroNode resNode = binaryTree.preOrderSearch(5); 27 if (resNode != null) { 28 System.out.printf("找到了,信息为 no=%d name=%s", resNode.getNo(), resNode.getName()); 29 } else { 30 System.out.printf("没有找到 no = %d 的英雄", 5); 31 } 32 33 //中序遍历查找 34 //中序遍历3次 35 System.out.println("中序遍历方式~~~"); 36 HeroNode resNode = binaryTree.infixOrderSearch(5); 37 if (resNode != null) { 38 System.out.printf("找到了,信息为 no=%d name=%s", resNode.getNo(), resNode.getName()); 39 } else { 40 System.out.printf("没有找到 no = %d 的英雄", 5); 41 } 42 43 //后序遍历查找 44 //后序遍历查找的次数 2次 45 System.out.println("后序遍历方式~~~"); 46 HeroNode resNode = binaryTree.postOrderSearch(5); 47 if (resNode != null) { 48 System.out.printf("找到了,信息为 no=%d name=%s", resNode.getNo(), resNode.getName()); 49 } else { 50 System.out.printf("没有找到 no = %d 的英雄", 5); 51 } 52 } 53 54 } 55 56 //定义BinaryTree 二叉树 57 class BinaryTree { 58 private HeroNode root; 59 60 public void setRoot(HeroNode root) { 61 this.root = root; 62 } 63 //前序遍历查找 64 public HeroNode preOrderSearch(int no) { 65 if(root != null) { 66 return root.preOrderSearch(no); 67 } else { 68 return null; 69 } 70 } 71 //中序遍历查找 72 public HeroNode infixOrderSearch(int no) { 73 if(root != null) { 74 return root.infixOrderSearch(no); 75 }else { 76 return null; 77 } 78 } 79 //后序遍历查找 80 public HeroNode postOrderSearch(int no) { 81 if(root != null) { 82 return this.root.postOrderSearch(no); 83 }else { 84 return null; 85 } 86 } 87 } 88 89 //先创建HeroNode 结点 90 class HeroNode { 91 private int no; 92 private String name; 93 private HeroNode left; //默认null 94 private HeroNode right; //默认null 95 public HeroNode(int no, String name) { 96 this.no = no; 97 this.name = name; 98 } 99 public int getNo() { 100 return no; 101 } 102 public void setNo(int no) { 103 this.no = no; 104 } 105 public String getName() { 106 return name; 107 } 108 public void setName(String name) { 109 this.name = name; 110 } 111 public HeroNode getLeft() { 112 return left; 113 } 114 public void setLeft(HeroNode left) { 115 this.left = left; 116 } 117 public HeroNode getRight() { 118 return right; 119 } 120 public void setRight(HeroNode right) { 121 this.right = right; 122 } 123 @Override 124 public String toString() { 125 return "HeroNode [no=" + no + ", name=" + name + "]"; 126 } 127 //前序遍历查找 128 /** 129 * 130 * @param no 查找no 131 * @return 如果找到就返回该Node ,如果没有找到返回 null 132 */ 133 public HeroNode preOrderSearch(int no) { 134 System.out.println("进入前序遍历"); 135 //比较当前结点是不是 136 if(this.no == no) { 137 return this; 138 } 139 //1.则判断当前结点的左子节点是否为空,如果不为空,则递归前序查找 140 //2.如果左递归前序查找,找到结点,则返回 141 HeroNode resNode = null; 142 if(this.left != null) { 143 resNode = this.left.preOrderSearch(no); 144 } 145 if(resNode != null) {//说明我们左子树找到 146 return resNode; 147 } 148 //1.左递归前序查找,找到结点,则返回,否继续判断, 149 //2.当前的结点的右子节点是否为空,如果不空,则继续向右递归前序查找 150 if(this.right != null) { 151 resNode = this.right.preOrderSearch(no); 152 } 153 return resNode; 154 } 155 156 //中序遍历查找 157 public HeroNode infixOrderSearch(int no) { 158 //判断当前结点的左子节点是否为空,如果不为空,则递归中序查找 159 HeroNode resNode = null; 160 if(this.left != null) { 161 resNode = this.left.infixOrderSearch(no); 162 } 163 if(resNode != null) { 164 return resNode; 165 } 166 System.out.println("进入中序查找"); 167 //如果找到,则返回,如果没有找到,就和当前结点比较,如果是则返回当前结点 168 if(this.no == no) { 169 return this; 170 } 171 //否则继续进行右递归的中序查找 172 if(this.right != null) { 173 resNode = this.right.infixOrderSearch(no); 174 } 175 return resNode; 176 177 } 178 179 //后序遍历查找 180 public HeroNode postOrderSearch(int no) { 181 182 //判断当前结点的左子节点是否为空,如果不为空,则递归后序查找 183 HeroNode resNode = null; 184 if(this.left != null) { 185 resNode = this.left.postOrderSearch(no); 186 } 187 if(resNode != null) {//说明在左子树找到 188 return resNode; 189 } 190 191 //如果左子树没有找到,则向右子树递归进行后序遍历查找 192 if(this.right != null) { 193 resNode = this.right.postOrderSearch(no); 194 } 195 if(resNode != null) { 196 return resNode; 197 } 198 System.out.println("进入后序查找"); 199 //如果左右子树都没有找到,就比较当前结点是不是 200 if(this.no == no) { 201 return this; 202 } 203 return resNode; 204 } 205 206 }
1 前序遍历方式~~~ 2 进入前序遍历 3 进入前序遍历 4 进入前序遍历 5 进入前序遍历 6 找到了,信息为 no=5 name=关胜中序遍历方式~~~ 7 进入中序查找 8 进入中序查找 9 进入中序查找 10 找到了,信息为 no=5 name=关胜后序遍历方式~~~ 11 进入后序查找 12 进入后序查找 13 找到了,信息为 no=5 name=关胜
定义:
思路分析:
实现删除代码:
1 //定义BinaryTree 二叉树 2 class BinaryTree { 3 private HeroNode root; 4 5 public void setRoot(HeroNode root) { 6 this.root = root; 7 } 8 9 //删除结点 10 public void delNode(int no) { 11 if(root != null) { 12 //如果只有一个root结点, 这里立即判断root是不是就是要删除结点 13 if(root.getNo() == no) { 14 root = null; 15 } else { 16 //递归删除 17 root.delNode(no); 18 } 19 }else{ 20 System.out.println("空树,不能删除~"); 21 } 22 } 23 } 24 class HeroNode { 25 private int no; 26 private String name; 27 private HeroNode left; //默认null 28 private HeroNode right; //默认null 29 public HeroNode(int no, String name) { 30 this.no = no; 31 this.name = name; 32 } 33 public int getNo() { 34 return no; 35 } 36 public void setNo(int no) { 37 this.no = no; 38 } 39 public String getName() { 40 return name; 41 } 42 public void setName(String name) { 43 this.name = name; 44 } 45 public HeroNode getLeft() { 46 return left; 47 } 48 public void setLeft(HeroNode left) { 49 this.left = left; 50 } 51 public HeroNode getRight() { 52 return right; 53 } 54 public void setRight(HeroNode right) { 55 this.right = right; 56 } 57 @Override 58 public String toString() { 59 return "HeroNode [no=" + no + ", name=" + name + "]"; 60 } 61 //递归删除结点 62 //1.如果删除的节点是叶子节点,则删除该节点 63 //2.如果删除的节点是非叶子节点,则删除该子树 64 public void delNode(int no) { 65 66 //思路 67 /* 68 * 1. 因为我们的二叉树是单向的,所以我们是判断当前结点的子结点是否需要删除结点,而不能去判断当前这个结点是不是需要删除结点. 69 2. 如果当前结点的左子结点不为空,并且左子结点 就是要删除结点,就将this.left = null; 并且就返回(结束递归删除) 70 3. 如果当前结点的右子结点不为空,并且右子结点 就是要删除结点,就将this.right= null ;并且就返回(结束递归删除) 71 4. 如果第2和第3步没有删除结点,那么我们就需要向左子树进行递归删除 72 5. 如果第4步也没有删除结点,则应当向右子树进行递归删除. 73 74 */ 75 //2. 如果当前结点的左子结点不为空,并且左子结点 就是要删除结点,就将this.left = null; 并且就返回(结束递归删除) 76 if(this.left != null && this.left.no == no) { 77 this.left = null; 78 return; 79 } 80 //3.如果当前结点的右子结点不为空,并且右子结点 就是要删除结点,就将this.right= null ;并且就返回(结束递归删除) 81 if(this.right != null && this.right.no == no) { 82 this.right = null; 83 return; 84 } 85 //4.我们就需要向左子树进行递归删除 86 if(this.left != null) { 87 this.left.delNode(no); 88 } 89 //5.则应当向右子树进行递归删除 90 if(this.right != null) { 91 this.right.delNode(no); 92 } 93 } 94 }
测试:
1 public static void main(String[] args) { 2 //先需要创建一颗二叉树 3 BinaryTree binaryTree = new BinaryTree(); 4 //创建需要的结点 5 HeroNode root = new HeroNode(1, "宋江"); 6 HeroNode node2 = new HeroNode(2, "吴用"); 7 HeroNode node3 = new HeroNode(3, "卢俊义"); 8 HeroNode node4 = new HeroNode(4, "林冲"); 9 HeroNode node5 = new HeroNode(5, "关胜"); 10 11 //说明,我们先手动创建该二叉树,后面我们学习递归的方式创建二叉树 12 root.setLeft(node2); 13 root.setRight(node3); 14 node3.setRight(node4); 15 node3.setLeft(node5); 16 binaryTree.setRoot(root); 17 System.out.println("删除前,前序遍历"); 18 binaryTree.preOrder(); // 1,2,3,5,4 19 binaryTree.delNode(5); 20 //binaryTree.delNode(3); 21 System.out.println("删除后,前序遍历"); 22 binaryTree.preOrder(); // 1,2,3,4 23 } 24 输出: 25 删除前,前序遍历 26 HeroNode [no=1, name=宋江] 27 HeroNode [no=2, name=吴用] 28 HeroNode [no=3, name=卢俊义] 29 HeroNode [no=5, name=关胜] 30 HeroNode [no=4, name=林冲] 31 删除后,前序遍历 32 HeroNode [no=1, name=宋江] 33 HeroNode [no=2, name=吴用] 34 HeroNode [no=3, name=卢俊义] 35 HeroNode [no=4, name=林冲] 36 如果是删除binaryTree.delNode(3); 37 则输出: 38 删除前,前序遍历 39 HeroNode [no=1, name=宋江] 40 HeroNode [no=2, name=吴用] 41 HeroNode [no=3, name=卢俊义] 42 HeroNode [no=5, name=关胜] 43 HeroNode [no=4, name=林冲] 44 删除后,前序遍历 45 HeroNode [no=1, name=宋江] 46 HeroNode [no=2, name=吴用]
拓展:
上面我们定义了两个删除规则,那么我们考虑另外删除规则又怎么实现。‘
如果要删除的节点是非叶子节点,现在我们不希望将该非叶子节点为根节点的子树删除,需要指定规则, 假如规定如下:
这个代码实现在后续讲二叉排序树时,在讲解具体的删除方法。
基本说明
从数据存储来看,数组存储方式和树 的存储方式可以相互转换,即数组可 以转换成树,树也可以转换成数组, 看示意图。
要求:
顺序存储二叉树的特点:
需求: 给你一个数组 {1,2,3,4,5,6,7},要求以二叉树前序遍历的方式进行遍历。 前序遍历的结果应当为 1,2,4,5,3,6,7
1 public class ArrBinaryTreeDemo { 2 3 public static void main(String[] args) { 4 int[] arr = { 1, 2, 3, 4, 5, 6, 7 }; 5 //创建一个 ArrBinaryTree 6 ArrBinaryTree arrBinaryTree = new ArrBinaryTree(arr); 7 arrBinaryTree.preOrder(); // 1,2,4,5,3,6,7 8 } 9 10 } 11 12 //编写一个ArrayBinaryTree, 实现顺序存储二叉树遍历 13 14 class ArrBinaryTree { 15 private int[] arr;//存储数据结点的数组 16 17 public ArrBinaryTree(int[] arr) { 18 this.arr = arr; 19 } 20 21 //重载preOrder 22 public void preOrder() { 23 this.preOrder(0); 24 } 25 26 //编写一个方法,完成顺序存储二叉树的前序遍历 27 /** 28 * 29 * @param index 数组的下标 30 */ 31 public void preOrder(int index) { 32 //如果数组为空,或者 arr.length = 0 33 if(arr == null || arr.length == 0) { 34 System.out.println("数组为空,不能按照二叉树的前序遍历"); 35 } 36 //输出当前这个元素 37 System.out.println(arr[index]); 38 //向左递归遍历 39 if((index * 2 + 1) < arr.length) { 40 preOrder(2 * index + 1 ); 41 } 42 //向右递归遍历 43 if((index * 2 + 2) < arr.length) { 44 preOrder(2 * index + 2); 45 } 46 } 47 48 }
八大排序算法中的堆排序,就会使用到顺序存储二叉树, 关于堆排序后续在讲。
原文:https://www.cnblogs.com/justBobo/p/11154643.html