Java数据结构与算法———(57)创建一个二叉树,删除其中的结点

先创建一个二叉树,并添加结点,然后根据结点id删除对应的结点。

一、代码
import java.util.Scanner;

public class BinaryTreeDemo {

	public static void main(String[] args) {

		//先创建一颗二叉树
		BinaryTree binaryTree = new BinaryTree();
		//创建需要的结点
		HeroNode root = new HeroNode(1, "宋江");//二叉树的根节点
		HeroNode node2 = new HeroNode(2, "吴用");
		HeroNode node3 = new HeroNode(3, "卢俊义");
		HeroNode node4 = new HeroNode(4, "林冲");
		HeroNode node5 = new HeroNode(5, "关胜");
		
		//说明,先手动创建该二叉树,即手动设置左右节点,后面再学习用递归的方式创建二叉树
		binaryTree.setRoot(root);
		root.setLeft(node2);
		root.setRight(node3);
		node3.setRight(node4);
		node3.setLeft(node5);
		
		//测试
		System.out.println("前序遍历");//1, 2, 3, 5, 4
		binaryTree.preOrder();
		System.out.println("中序遍历");//2, 1, 5, 3, 4
		binaryTree.infixOrder();
		System.out.println("后序遍历");//2, 5, 4, 3, 1
		binaryTree.postOrder();
		
		Scanner scanner = new Scanner(System.in);
		int id;
		
		//测试删除结点
		System.out.println("删除前,前序遍历:");
		binaryTree.preOrder();
		System.out.println("输入你要删除的英雄编号:");
		id = scanner.nextInt();
		binaryTree.delNode(id);
		System.out.println("删除后,前序遍历:");
		binaryTree.preOrder();
	}

}

//创建二叉树类  BinaryTree
class BinaryTree{
	
	//声明一个根结点引用变量,暂不赋值
	private HeroNode root;
	
	//给根节点赋值
	public void setRoot(HeroNode root) {
		this.root = root;
	}
	
	//前序遍历输出(调用HeorNode类的前序遍历方法)
	public void preOrder() {
		if(this.root != null) {//说明至少有一个结点
			this.root.preOrder();
		}else {
			System.out.println("二叉树为空,无法遍历");
		}
	}
	
	//中序遍历输出(调用HeorNode类的中序遍历方法)
	public void infixOrder() {
		if(this.root != null) {//说明至少有一个结点
			this.root.infixOrder();
		}else {
			System.out.println("二叉树为空,无法遍历");
		}
	}
	
	//后序遍历输出(调用HeorNode类的后序遍历方法)
	public void postOrder() {
		if(root != null) {//说明至少有一个结点
			this.root.postOrder();
		}else {
			System.out.println("二叉树为空,无法遍历");
		}
	}
	
	//前序遍历查找
	public HeroNode preOrderSearch(int id) {
		if(root != null) {//说明至少有一个结点
			return root.preOrderSearch(id);
		}else {
			return null;
		}
	}
	
	//中序遍历查找
	public HeroNode infixOrderSearch(int id) {
		if(root != null) {//说明至少有一个结点
			return root.infixOrderSearch(id);
		}else {
			return null;
		}
	}
	
	//后续遍历查找
	public HeroNode postOrderSearch(int id) {
		if(root != null) {//说明至少有一个结点
			return root.postOrderSearch(id);
		}else {
			return null;
		}
	}
	
	//递归删除结点
	public void delNode(int id) {
		if(root != null) {
			//判断root是否是待删除结点
			if(root.getId() == id) {
				root = null;
			}else {
				//递归删除
				root.delNode(id);
			}
		}else {
			System.out.println("空树");
		}
	}
}


//创建结点类  HeroNode
class HeroNode{
	
	//定义属性
	private int id;
	private String name;
	private HeroNode left;//默认为null
	private HeroNode right;//默认为null
	
	//构造器
	public HeroNode(int id, String name) {
		this.id = id;
		this.name = name;
	}
	
	//操作属性的一些方法
	public void setId(int id) {
		this.id = id;
	}
	public int getId() {
		return id;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setLeft(HeroNode left) {
		this.left = left;
	}
	public HeroNode getLeft() {
		return left;
	}
	public void setRight(HeroNode right) {
		this.right = right;
	}
	public HeroNode getRight() {
		return right;
	}
	
	//为了显示方便,重写toString方法
	public String toString() {
		return "[id = " + id + ", name = " + name + "]";
	}
	
	// 递归删除结点
	// 规则:
	// 1. 如果删除的结点是叶子结点,则删除该结点
	// 2. 如果删除的结点不是叶子结点,则删除该该子树
	public void delNode(int id) {
		//思路
		/*
		 * 1. 因为二叉树是单向的,所以是判断当前结点的子节点是否是待待删除结点,而不能去判断当前结点是否是待删除结点
		 * 2.如果当前结点的左子结点不为空,并且左子结点就是待删除结点,就 this.left = null,并且用 return 语句来结束递归
		 * 3.如果当前结点的右子节点不为空,并且右子结点就是待删除结点,就 this.right = null,并且用 return 语句来结束递归
		 * 4.如果第2、3步骤都没有删除结点,就继续向左子树进行递归删除,注意:递归前要判断左结点是否为空
		 * 5.如果第4步骤也没有删除结点,则应当向右子树递归删除,注意:递归前要判断右结点是否为空
		 */
		
		//如果当前结点的左子结点不为空,并且左子结点就是待删除结点,就 this.left = null,并且用 return 语句来结束递归
		if(this.left != null && this.left.id == id) {
			this.left = null;
			return;
		}
		//如果当前结点的右子节点不为空,并且右子结点就是待删除结点,就 this.right = null,并且用 return 语句来结束递归
		if(this.right != null && this.right.id == id) {
			this.right = null;
			return;
		}
		//如果第2、3步骤都没有删除结点,就继续向左子树进行递归删除
		if(this.left != null) {//注意:递归前要判断左结点是否为空
			this.left.delNode(id);
		}
		//如果第4步骤也没有删除结点,则应当向右子树递归删除
		if(this.right != null) {//注意:递归前要判断右结点是否为空
			this.right.delNode(id);
		}
	}
	
	
	//前序遍历输出(父左右)
	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);
	}
	
	//前序遍历查找
	/**
	 * 
	 * @param id 待查找的id
	 * @return 返回一个HeroNode结点,如果这个结点非空,则说明找到了,如果为空,则说明没找到(调用时再判断返回的结点是否为空)
	 */
	public HeroNode preOrderSearch(int id) {
		//先比较当前结点
		System.out.println("进入前序遍历查找一次");//用于统计查找的次数,只有和输入的id比较时才能算一次查找
		if(this.id == id) {
			return this;
		}
		//再判断当前结点的左子树是否为空,如果不为空,则递归前序查找
		//如果左递归前序查没找到,就继续左子树递归前序查找
		HeroNode resNode = null;
		if(this.left != null) {//没找到,继续左子树递归前序查找
			resNode = this.left.preOrderSearch(id);//用当前结点的左节点递归
		}
		//如果找到了,就返回
		if(resNode != null) {
			return resNode;
		}
		//再判断当前结点的右子树是否为空,如果不为空,则递归前序查找
		if(this.right != null) {
			resNode = this.right.preOrderSearch(id);
		}
		//注意:不管右子树前序递归有没有找到,都要返回resNode,因为谦虚遍历是以右边收尾的
		return resNode;
	}
	
	//中序遍历查找
	public HeroNode infixOrderSearch(int id) {
		//如果当前结点的左结点非空,就往左中序遍历查找
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.infixOrderSearch(id);
		}
		if(resNode != null) {//找到了就返回
			return resNode;
		}
		//在当前结点的左子树没找到,就判断当前结点
		System.out.println("进入中序遍历查找一次");//用于统计查找的次数,只有和输入的id比较时才能算一次查找
		if(this.id == id) {//找到了就返回当前结点
			return this;
		}
		//如果当前结点也不是要找的结点,则继续判断右子树是否非空
		//如果非空,则继续右子树中序遍历查找,
		if(this.right != null) {
			resNode = this.right.infixOrderSearch(id);
		}
		return resNode;
	}
	
	//后续遍历查找
	public HeroNode postOrderSearch(int id) {
		//如果当前结点的左节点非空,则对左子树进行后续查找
		HeroNode resNode = null;
		if(this.left != null) {
			resNode = this.left.postOrderSearch(id);
		}
		//如果在左子树找到了,就返回找到的结点
		if(resNode != null) {
			return resNode;
		}
		//如果在左子树没找到,就继续对右子树后序遍历查找
		//只要该节点的右结点非空,就继续递归查找
		if(this.right != null) {
			resNode = this.right.postOrderSearch(id);
		}
		//如果找到了就返回
		if(resNode != null) {
			return resNode;
		}
		//如果在该节点的右子树也没找到,则判断该节点
		System.out.println("进入后序遍历查找一次");//用于统计查找的次数,只有和输入的id比较时才能算一次查找
		if(this.id == id) {//找到了
			return this;
		}
		//没找到,直接返回resNode
		return resNode;
	}
}
二、结果
1. 删除编号为5的结点
前序遍历
[id = 1, name = 宋江]
[id = 2, name = 吴用]
[id = 3, name = 卢俊义]
[id = 5, name = 关胜]
[id = 4, name = 林冲]
中序遍历
[id = 2, name = 吴用]
[id = 1, name = 宋江]
[id = 5, name = 关胜]
[id = 3, name = 卢俊义]
[id = 4, name = 林冲]
后序遍历
[id = 2, name = 吴用]
[id = 5, name = 关胜]
[id = 4, name = 林冲]
[id = 3, name = 卢俊义]
[id = 1, name = 宋江]
删除前,前序遍历:
[id = 1, name = 宋江]
[id = 2, name = 吴用]
[id = 3, name = 卢俊义]
[id = 5, name = 关胜]
[id = 4, name = 林冲]
输入你要删除的英雄编号:
5
删除后,前序遍历:
[id = 1, name = 宋江]
[id = 2, name = 吴用]
[id = 3, name = 卢俊义]
[id = 4, name = 林冲]
2. 删除编号为3的结点
前序遍历
[id = 1, name = 宋江]
[id = 2, name = 吴用]
[id = 3, name = 卢俊义]
[id = 5, name = 关胜]
[id = 4, name = 林冲]
中序遍历
[id = 2, name = 吴用]
[id = 1, name = 宋江]
[id = 5, name = 关胜]
[id = 3, name = 卢俊义]
[id = 4, name = 林冲]
后序遍历
[id = 2, name = 吴用]
[id = 5, name = 关胜]
[id = 4, name = 林冲]
[id = 3, name = 卢俊义]
[id = 1, name = 宋江]
删除前,前序遍历:
[id = 1, name = 宋江]
[id = 2, name = 吴用]
[id = 3, name = 卢俊义]
[id = 5, name = 关胜]
[id = 4, name = 林冲]
输入你要删除的英雄编号:
3
删除后,前序遍历:
[id = 1, name = 宋江]
[id = 2, name = 吴用]
3. 删除编号为1的结点
前序遍历
[id = 1, name = 宋江]
[id = 2, name = 吴用]
[id = 3, name = 卢俊义]
[id = 5, name = 关胜]
[id = 4, name = 林冲]
中序遍历
[id = 2, name = 吴用]
[id = 1, name = 宋江]
[id = 5, name = 关胜]
[id = 3, name = 卢俊义]
[id = 4, name = 林冲]
后序遍历
[id = 2, name = 吴用]
[id = 5, name = 关胜]
[id = 4, name = 林冲]
[id = 3, name = 卢俊义]
[id = 1, name = 宋江]
删除前,前序遍历:
[id = 1, name = 宋江]
[id = 2, name = 吴用]
[id = 3, name = 卢俊义]
[id = 5, name = 关胜]
[id = 4, name = 林冲]
输入你要删除的英雄编号:
1
删除后,前序遍历:
二叉树为空,无法遍历

你可能感兴趣的:(Java数据结构与算法,二叉树,算法,数据结构,java,链表)