一、二叉树的介绍
1.二叉树:每个节点最多只能有两个子节点的一种形式的树
2.左右节点:也叫孩子节点,二叉树的子节点分为左节点和右节点,如图21为11的左子节点,31为11的右子节点,11为21和31的父节点
3.叶子节点:叶子节点就是树中最底段的节点,叶子节点没有子节点。
4.满二叉树:二叉树的所有叶子节点都在最后一层,并且满足节点总数为2^(n-1),n为层数。
5.完全二叉树:二叉树的所有叶子节点都在最后一层或者分布在倒数第二层,并且满足最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续!
6.满二叉树是完全二叉树的一个特列,但完全二叉树不一定是满二叉树
二、二叉树的前序,中序,后续遍历
1.逻辑结构示意图
2.前序中序后序遍历思路分析即步骤
1.创建一颗二叉树
2.前序遍历思路分析:
先输出父节点,在输出左子节点,在输出右子节点
步骤
①先输出当前节点(初始的时候是root节点)
②如果左子节点不为空,则左子节点递归继续前序遍历
③如果右子节点不为空,则右子节点递归继续前序遍历
3.中序遍历思路分析:
先输出左子节点,在输出父节点,在输出右子节点
步骤
3.1如果当前节点的左子节点不为空,则左子节点递归中序遍历,
3.2输出当前节点
3.2如果当前节点的右子节点不为空,则右子节点递归中序遍历
4.后序遍历思路分析:
先输出左子节点,在输出右子节点,最后输出父节点
步骤
3.1如果当前节点的左子节点不为空,则左子节点递归后序遍历,
3.2如果当前节点的右子节点不为空,则右子节点递归后序遍历
3.3输出当前节点
代码实现
package tree;
public class TreeTest {
public static void main(String[] args){
//初始化节点
HeroNode root = new HeroNode(1,"宋江","及时雨");
HeroNode hero2 = new HeroNode(2,"吴用","智多星");
HeroNode hero3 = new HeroNode(3,"李逵","黑旋风");
HeroNode hero4 = new HeroNode(4,"卢俊义","玉麒麟");
HeroNode hero5 = new HeroNode(5,"武松","豹子头");
//初始化二叉树
BinaryTree tree = new BinaryTree();
//数中添加节点
tree.setRoot(root);
root.setLeft(hero2);
root.setRight(hero3);
hero3.setLeft(hero4);
hero3.setRight(hero5);
System.out.println("-----------①遍历测试-------------");
//前序遍历
System.out.println("--------前序遍历--------");
tree.preOrder();
//中序遍历
System.out.println("--------中序遍历--------");
tree.infixOrder();
//后序遍历
System.out.println("--------后序遍历--------");
tree.postOrder()
}
//定义一个二叉树
class BinaryTree{
private HeroNode root;//定义一个根节点
public void setRoot(HeroNode root) {
this.root = root;
}
//前序遍历
public void preOrder(){
if (this.root != null){
this.root.preOrder();
}else{
System.out.println("该二叉树没有根节点,无法遍历");
}
}
//中序遍历
public void infixOrder(){
if (this.root != null){
this.root.infixOrder();
}else{
System.out.println("该二叉树没有根节点,无法遍历");
}
}
//后序遍历
public void postOrder(){
if (this.root != null){
this.root.postOrder();
}else{
System.out.println("该二叉树没有根节点,无法遍历");
}
}
}
//定义一个节点类
class HeroNode{
private int id;//id
private String name;//姓名
private String nickName;//别名
private HeroNode left;//左节点
private HeroNode right;//右节点,默认为空
//无参构造器
public HeroNode() {
}
//有参构造器
public HeroNode(int id, String name, String nickName) {
this.id = id;
this.name = name;
this.nickName = nickName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
//重写toString 不用加左右节点,默认为空
@Override
public String toString() {
return "HeroNode{" +
"id=" + id +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
//前序遍历
public void preOrder(){
//1.先输出父节点
System.out.println(this);
//2.左子树递归前序遍历
if (this.left != null){
this.left.preOrder();
}
//3.右子树递归前序遍历
if (this.right != null){
this.right.preOrder();
}
}
///中序遍历
public void infixOrder(){
//1.左子树递归中序遍历
if (this.left != null){
this.left.infixOrder();
}
//2.输出父节点
System.out.println(this);
//3.右子树递归中序遍历
if (this.right != null){
this.right.infixOrder();
}
}
//后续遍历
public void postOrder(){
//1.左子树递归后序遍历
if (this.left != null){
this.left.postOrder();
}
//2.右子树递归后序遍历
if (this.right != null) {
this.right.postOrder();
}
//3.输出父节点
System.out.println(this);
}
}
结果截图
三、二叉树的前序,中序,后续查找
前序查找思路
1.先判断当前结点的no是否等于要查找的
2.如果是相等,则返回当前结点
3.如果不等,则判断当前结点的左子节点是否为空,如果不为空,则递归前序查找
4.如果左递归前序查找,找到结点,则返回,否继续判断,当前的结点的右子节点是否为空,如果不空,则继续向右递归前序查找
中序查找思路
1.判断当前结点的左子节点是否为空,如果不为空,则递归中序查找
2.如果找到,则返回,如果没有找到,就和当前结点比较,如果是则返回当前结点,否则继续进行右递归的中序查找
3.如果右递归中序查找,找到就返回,否则返回null
后序查找思路
1.判断当前结点的左子节点是否为空,如果不为空,则递归后序查找
2.如果找到,就返回,如果没有找到,就判断当前结点的右子节点是否为空,如果不为空,则右递归进行后序查找,如果找到,就返回。
3.就和当前结点进行,比如,如果是则返回,否则返回null
package tree;
public class TreeTest {
public static void main(String[] args){
//初始化节点
HeroNode root = new HeroNode(1,"宋江","及时雨");
HeroNode hero2 = new HeroNode(2,"吴用","智多星");
HeroNode hero3 = new HeroNode(3,"李逵","黑旋风");
HeroNode hero4 = new HeroNode(4,"卢俊义","玉麒麟");
HeroNode hero5 = new HeroNode(5,"武松","豹子头");
//初始化二叉树
BinaryTree tree = new BinaryTree();
//数中添加节点
tree.setRoot(root);
root.setLeft(hero2);
root.setRight(hero3);
hero3.setLeft(hero4);
hero3.setRight(hero5);
System.out.println("-----------①遍历测试-------------");
//前序遍历
System.out.println("--------前序遍历--------");
tree.preOrder();
//中序遍历
System.out.println("--------中序遍历--------");
tree.infixOrder();
//后序遍历
System.out.println("--------后序遍历--------");
tree.postOrder();
System.out.println("-----------②查找测试-------------");
//前序查找编号为5的节点信息
System.out.println("查找编号为5的节点信息..");
HeroNode searchHero = tree.preOrderSearch(1);
if (searchHero != null){
System.out.printf("查找成功!!节点信息:id=%d,name=%s,nickName=%s\n",searchHero.getId(),searchHero.getName(),searchHero.getNickName());
}else{
System.out.printf("查询失败!!没有编号%d的节点信息\n",1);
}
//中序查找编号为6的节点信息
System.out.println("查找编号为6的节点信息..");
HeroNode curNode = tree.infixOrderSearch(6);
if (curNode != null){
System.out.printf("查找成功!!节点信息:id=%d,name=%s,nickName=%s\n",curNode.getId(),curNode.getName(),curNode.getNickName());
}else{
System.out.printf("查询失败!!没有编号%d的节点信息\n",6);
}
//后续查找编号为5的节点信息
System.out.println("查找编号为7的节点信息..");
HeroNode heroNode = tree.postOrderSearch(3);
if (heroNode != null){
System.out.printf("查找成功!!节点信息:id=%d,name=%s,nickName=%s\n",heroNode.getId(),heroNode.getName(),heroNode.getNickName());
}else{
System.out.printf("查询失败!!没有编号%d的节点信息\n",3);
}
System.out.println("-----------③删除测试-------------");
//删除4号节点
System.out.println("删除4号节点中.....");
tree.delNode(4);
System.out.println("删除后,前序遍历...");
tree.preOrder();
System.out.println("删除后,中序遍历...");
tree.infixOrder();
System.out.println("删除后,后续遍历...");
tree.postOrder();
}
}
//定义一个二叉树
class BinaryTree{
private HeroNode root;//定义一个根节点
public void setRoot(HeroNode root) {
this.root = root;
}
//前序查找
public HeroNode preOrderSearch(int no){
if (this.root != null){
return this.root.preOrderSearch(no);
}else{
return null;
}
}
//中序查找
public HeroNode infixOrderSearch(int no){
if (this.root != null){
return this.root.infixOrderSearch(no);
}else{
return null;
}
}
//后序查找
public HeroNode postOrderSearch(int no){
if (this.root != null){
return this.root.postOrderSearch(no);
}else{
return null;
}
}
}
//定义一个节点类
class HeroNode{
private int id;//id
private String name;//姓名
private String nickName;//别名
private HeroNode left;//左节点
private HeroNode right;//右节点,默认为空
//无参构造器
public HeroNode() {
}
//有参构造器
public HeroNode(int id, String name, String nickName) {
this.id = id;
this.name = name;
this.nickName = nickName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
//重写toString 不用加左右节点,默认为空
@Override
public String toString() {
return "HeroNode{" +
"id=" + id +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
//前序查找
public HeroNode preOrderSearch(int no) {
System.out.println("查找中~~~~~");
//1.判断当前节点的no是不是要查找的
if (this.id == no) {
return this;
}
//定义一个当前节点,用于返回
HeroNode curNode = null;
//2.左递归
if (this.left != null) {
curNode = this.left.preOrderSearch(no);
}
if (curNode != null) {//当前节点不为空,说明找到该节点
return curNode;
}
//3.右递归
if (this.right != null) {
curNode = this.right.preOrderSearch(no);
}
return curNode;
}
//中序查找
public HeroNode infixOrderSearch(int no) {
//定义一个当前节点,用于返回
HeroNode curNode = null;
//1.左递归
if (this.left != null) {
curNode = this.left.infixOrderSearch(no);
}
if (curNode != null) {//当前节点不为空,说明找到该节点
return curNode;
}
System.out.println("查找中~~~~~");
//判断当前节点的no是不是要查找的
if (this.id == no) {
return this;
}
//右递归
if (this.right != null) {
curNode = this.right.infixOrderSearch(no);
}
return curNode;
}
//后序查找
public HeroNode postOrderSearch(int no) {
//定义一个当前节点,用于返回
HeroNode curNode = null;
//1.左递归
if (this.left != null) {
curNode = this.left.postOrderSearch(no);
}
if (curNode != null) {//当前节点不为空,说明找到该节点
return curNode;
}
//右递归
if (this.right != null) {
curNode = this.right.postOrderSearch(no);
}
if (curNode != null) {
return curNode;
}
System.out.println("查找中~~~~~");
//判断当前节点的no是不是要查找的
if (this.id == no) {
return this;
}
return curNode;
}
}
结果截图
四、二叉树的删除操作
完成删除结点的操作
1)如果刪除的节点是叶子节点,则删除该节点
2)如果删除的节点是非叶子节点,则删除该子树
思路
首先先处理:
如果树是空树root,如果只有一个root结点,则等价将二叉树置空
接着进行下面步骤
1.因为我们的二叉树是单向的,所以我们是判断当前结点的子结点是否需要删除结点,而不能去判断当前这个结点是不是需要删除结点.
2.如果当前结点的左子结点不为空,并且左子结点就是要删除结点,就将this.eft=null;并且就返回(结束递归删除)
3.如果当前结点的右子结点不为空,并且右子结点就是要删除结点,就将this.right=null ;并且就返回(结束递归删除)
4.如果第2和第3步没有删除结点,那么我们就需要向左子树进行递归删除
5.如果第4步也没有删除结点,则应当向右子树进行递归删除.
二叉树全代码
package tree;
public class TreeTest {
public static void main(String[] args){
//初始化节点
HeroNode root = new HeroNode(1,"宋江","及时雨");
HeroNode hero2 = new HeroNode(2,"吴用","智多星");
HeroNode hero3 = new HeroNode(3,"李逵","黑旋风");
HeroNode hero4 = new HeroNode(4,"卢俊义","玉麒麟");
HeroNode hero5 = new HeroNode(5,"武松","豹子头");
//初始化二叉树
BinaryTree tree = new BinaryTree();
//数中添加节点
tree.setRoot(root);
root.setLeft(hero2);
root.setRight(hero3);
hero3.setLeft(hero4);
hero3.setRight(hero5);
System.out.println("-----------①遍历测试-------------");
//前序遍历
System.out.println("--------前序遍历--------");
tree.preOrder();
//中序遍历
System.out.println("--------中序遍历--------");
tree.infixOrder();
//后序遍历
System.out.println("--------后序遍历--------");
tree.postOrder();
System.out.println("-----------②查找测试-------------");
//前序查找编号为5的节点信息
System.out.println("查找编号为5的节点信息..");
HeroNode searchHero = tree.preOrderSearch(1);
if (searchHero != null){
System.out.printf("查找成功!!节点信息:id=%d,name=%s,nickName=%s\n",searchHero.getId(),searchHero.getName(),searchHero.getNickName());
}else{
System.out.printf("查询失败!!没有编号%d的节点信息\n",1);
}
//中序查找编号为6的节点信息
System.out.println("查找编号为6的节点信息..");
HeroNode curNode = tree.infixOrderSearch(6);
if (curNode != null){
System.out.printf("查找成功!!节点信息:id=%d,name=%s,nickName=%s\n",curNode.getId(),curNode.getName(),curNode.getNickName());
}else{
System.out.printf("查询失败!!没有编号%d的节点信息\n",6);
}
//后续查找编号为5的节点信息
System.out.println("查找编号为7的节点信息..");
HeroNode heroNode = tree.postOrderSearch(3);
if (heroNode != null){
System.out.printf("查找成功!!节点信息:id=%d,name=%s,nickName=%s\n",heroNode.getId(),heroNode.getName(),heroNode.getNickName());
}else{
System.out.printf("查询失败!!没有编号%d的节点信息\n",3);
}
System.out.println("-----------③删除测试-------------");
//删除4号节点
System.out.println("删除4号节点中.....");
tree.delNode(4);
System.out.println("删除后,前序遍历...");
tree.preOrder();
System.out.println("删除后,中序遍历...");
tree.infixOrder();
System.out.println("删除后,后续遍历...");
tree.postOrder();
}
}
//定义一个二叉树
class BinaryTree{
private HeroNode root;//定义一个根节点
public void setRoot(HeroNode root) {
this.root = root;
}
//前序遍历
public void preOrder(){
if (this.root != null){
this.root.preOrder();
}else{
System.out.println("该二叉树没有根节点,无法遍历");
}
}
//中序遍历
public void infixOrder(){
if (this.root != null){
this.root.infixOrder();
}else{
System.out.println("该二叉树没有根节点,无法遍历");
}
}
//后序遍历
public void postOrder(){
if (this.root != null){
this.root.postOrder();
}else{
System.out.println("该二叉树没有根节点,无法遍历");
}
}
//前序查找
public HeroNode preOrderSearch(int no){
if (this.root != null){
return this.root.preOrderSearch(no);
}else{
return null;
}
}
//中序查找
public HeroNode infixOrderSearch(int no){
if (this.root != null){
return this.root.infixOrderSearch(no);
}else{
return null;
}
}
//后序查找
public HeroNode postOrderSearch(int no){
if (this.root != null){
return this.root.postOrderSearch(no);
}else{
return null;
}
}
//删除节点
public void delNode(int no){
//先判断当前树是否为空树
if (root != null){
//只有一个root节点
if (root.getId() == no){
root =null;
}else{
//root有左右节点,则递归删除
root.delNode(no);
}
}else{
System.out.println("当前树是空树,不能删除!!");
}
}
}
//定义一个节点类
class HeroNode{
private int id;//id
private String name;//姓名
private String nickName;//别名
private HeroNode left;//左节点
private HeroNode right;//右节点,默认为空
//无参构造器
public HeroNode() {
}
//有参构造器
public HeroNode(int id, String name, String nickName) {
this.id = id;
this.name = name;
this.nickName = nickName;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
//重写toString 不用加左右节点,默认为空
@Override
public String toString() {
return "HeroNode{" +
"id=" + id +
", name='" + name + '\'' +
", nickName='" + nickName + '\'' +
'}';
}
//前序遍历
public void preOrder(){
//1.先输出父节点
System.out.println(this);
//2.左子树递归前序遍历
if (this.left != null){
this.left.preOrder();
}
//3.右子树递归前序遍历
if (this.right != null){
this.right.preOrder();
}
}
///中序遍历
public void infixOrder(){
//1.左子树递归中序遍历
if (this.left != null){
this.left.infixOrder();
}
//2.输出父节点
System.out.println(this);
//3.右子树递归中序遍历
if (this.right != null){
this.right.infixOrder();
}
}
//后续遍历
public void postOrder(){
//1.左子树递归后序遍历
if (this.left != null){
this.left.postOrder();
}
//2.右子树递归后序遍历
if (this.right != null) {
this.right.postOrder();
}
//3.输出父节点
System.out.println(this);
}
//前序查找
public HeroNode preOrderSearch(int no) {
System.out.println("查找中~~~~~");
//1.判断当前节点的no是不是要查找的
if (this.id == no) {
return this;
}
//定义一个当前节点,用于返回
HeroNode curNode = null;
//2.左递归
if (this.left != null) {
curNode = this.left.preOrderSearch(no);
}
if (curNode != null) {//当前节点不为空,说明找到该节点
return curNode;
}
//3.右递归
if (this.right != null) {
curNode = this.right.preOrderSearch(no);
}
return curNode;
}
//中序查找
public HeroNode infixOrderSearch(int no) {
//定义一个当前节点,用于返回
HeroNode curNode = null;
//1.左递归
if (this.left != null) {
curNode = this.left.infixOrderSearch(no);
}
if (curNode != null) {//当前节点不为空,说明找到该节点
return curNode;
}
System.out.println("查找中~~~~~");
//判断当前节点的no是不是要查找的
if (this.id == no) {
return this;
}
//右递归
if (this.right != null) {
curNode = this.right.infixOrderSearch(no);
}
return curNode;
}
//后序查找
public HeroNode postOrderSearch(int no) {
//定义一个当前节点,用于返回
HeroNode curNode = null;
//1.左递归
if (this.left != null) {
curNode = this.left.postOrderSearch(no);
}
if (curNode != null) {//当前节点不为空,说明找到该节点
return curNode;
}
//右递归
if (this.right != null) {
curNode = this.right.postOrderSearch(no);
}
if (curNode != null) {
return curNode;
}
System.out.println("查找中~~~~~");
//判断当前节点的no是不是要查找的
if (this.id == no) {
return this;
}
return curNode;
}
//节点删除,因为二叉树是单向的,所以需要判断是当前节点的子节点需要删除
public void delNode(int no){
//1.如果当前节点的左子树不为空,并且左子树刚好是待删除节点
if (this.left != null && this.left.id == no){
this.left =null;
return;
}
//2.如果当前节点的右子树不为空,并且右子树刚好是待删除节点
if (this.right != null && this.right.id == no){
this.right =null;
return;
}
//3.当1,2都不满足,则左子树递归删除
if (this.left != null){
this.left.delNode(no);
}
//4.当3不满足时,递归删除右子树
if (this.left != null){
this.right.delNode(no);
}
}
}
删除截图