二叉排序树

二叉排序树的作用

数组删除和插入的效率很低,链表查找的效率很低,而二叉排序树可以让查找,删除,添加(因为二叉排序树是有序的,所以添加也即是插入)的效率都变的很高。

特点:

  • 基于二叉树,但是有一定的规则,每个节点的左子节点总是比它小,右子节点总是比它大
  • 中序遍历就是一个升序的序列
  • 查找效率近似二分查找

 

 节点类

public class TreeNode {
	public int value;
	public TreeNode left;
	public TreeNode right;
	public TreeNode(int value) {
		super();
		this.value = value;
	}
	//添加节点
	public void add(TreeNode node) {
		if(node == null) { //如果传入的节点为空直接返回
			return;
		}
		if(node.value < this.value) { //判断是否比当前节点小
			if(this.left == null) { //如果左子节点为空,则直接把节点添加为该节点的左子节点
				this.left = node;
			}else {
				this.left.add(node);//从左子节点继续判断,寻找合适的位置
			}
		}else {
			if(this.right == null) {
				this.right = node;
			}else {
				this.right.add(node);
			}
		}
	}
	//中序遍历
	public void midOrder() {
		if(this.left != null) {
			this.left.midOrder();
		}
		System.out.println(this);
		if(this.right != null) {
			this.right.midOrder();
		}
	}
	//查找目标节点
	public TreeNode search(int value) {
		if(value == this.value) {
			return this;
		}else if(value < this.value) {
			if(this.left == null) {
				return null;
			}else {
				return this.left.search(value);
			}
		}else {
			if(this.right == null) {
				return null;
			}else {
				return this.right.search(value);
			}
		}
	}
	/**
	 * 查找目标值的父节点
	 * 实现:判断当前节点的左右子节点是否是要查找的节点,如果是直接返回
	 * 如果不是,则判断当前节点值与要查找的值的大小关系
	 * 如果  要查找的值<当前值 判断左子节点是否为空,不为空则往左边查找
	 * 如果  要查找的值>当前值 判断右子节点是否为空,不为空则往右边查找
	 * 
	 * @param value 要删除节点的值
	 * @return 返回目标值的父节点
	 */
	public TreeNode searchParent(int value) {
		if( (this.left != null && this.left.value == value) ||
				(this.right != null && this.right.value == value) ) {
			return this;
		}else {
			if(value < this.value && this.left != null) {
				return this.left.searchParent(value);
			}else if(value > this.value && this.left != null) {
				 return this.right.searchParent(value);
			}else {
				return null;
			}
		}
	}
}

二叉排序树

public class BinarySortTree {
	private TreeNode root;
	//添加节点
	public void add(TreeNode node) {
		if(this.root == null) {
			this.root = node;
		}else {
			this.root.add(node);
		}
	}
	//中序遍历
	public void midOrder() {
		if(this.root == null) {
			System.out.println("二叉排序树为空!");
		}else {
			this.root.midOrder();
		}
	}
	//查找节点
	public TreeNode search(int value) {
		if(this.root == null) {
			System.out.println("二叉排序树为空!");
			return null;
		}else {
			return this.root.search(value);
		}
	}
	//查找目标节点的父节点
	public TreeNode searchParent(int value) {
		if(this.root == null) {
			System.out.println("二叉排序树为空!");
			return null;
		}else {
			return this.root.searchParent(value);
		}
	}
	/**
	 * 先查找目标节点的父节点,如果找到,则可以同时得到目标节点
	 * 如果找不到,则判断是否目标节点是否是根节点,如果不是,则没有目标节点,直接返回
	 * 找到目标节点后:
	 * 1.判断该节点是否是叶子节点,如果是,则直接通过父节点删除,如果是根节点,则直接把根节点赋值为null
	 * 2.判断该节点后面是否只有一颗子树,也就是左子节点或者右子节点其中一个为null,则直接把让目标节点的父节点指向目标节点的子节点
	 * 如果是根节点,则让根节点等于它的左子节点或者右子节点(非空的那个节点)
	 * 3.如果该节点后面有两颗子树,也就是做左右子节点都不为null,
	 * 则找到以左子节点为根的子树中最大的数保存起来,删除该节点,然后把值赋值给要目标节点
	 * 或者找到以右子节点为根的子树中最小的数保存起来,删除该节点,然后把值赋值给要删除的节点  (两者选其一)
	 * 
	 * @param value 要删除的节点值
	 */
	public void removeNode(int value) {
		if(this.root == null) {
			return;
		}else {
			//找到目标节点的父节点
			TreeNode parentNode = searchParent(value);
			TreeNode target = null;  
			if(parentNode == null) { 
				if(root.value == value) { //查找一下根节点是否是目标节点
					target = root;
				}else {
					return;
				}
			}else if(parentNode.left != null && parentNode.left.value == value){
				target = parentNode.left;
			}else if(parentNode.right != null && parentNode.right.value == value){
				target = parentNode.right;
			}
			//如果要删除的节点为叶子节点
			if(target.left == null && target.right == null) {
				if(parentNode == null) { //根节点
					this.root = null;
					return;
				}
				//判断目标节点是父节点的左子节点还是右子节点
				if(parentNode.left != null && parentNode.left.value == value) { //左子节点
					parentNode.left = null;
					return;
				}
				if(parentNode.right != null && parentNode.right.value == value) { //右子节点
					parentNode.right = null;
					return;
				}
			}else if(target.left != null && target.right != null){//如果要删除的节点左右子节点都不为空
				//找到左子节点为根的子树中最大的数保存起来,删除该节点,然后把值赋值给要删除的节点
				//或者找到右子节点为根的子树中最小的数保存起来,删除该节点,然后把值赋值给要删除的节点
				int rightMinValue = removeRightMin(target.right); //我这里删除右子节点为根的子树最小的节点
				target.value = rightMinValue;
				
			}else {//如果要删除的节点为左右节点有一个为空
				if(target.left != null) { //左子节点不为空,则让它的左子节点代替它的位置
					if(parentNode == null) { //根节点
						root = target.left;
						return ;
					}
					if(parentNode.left.value == value) {
						parentNode.left = target.left;
					}else {
						parentNode.right = target.left;
					}
				}else {//右子节点不为空,则让它的右子节点代替它的位置
					if(parentNode == null) { //根节点
						root = target.right;
						return ;
					}
					if(parentNode.left.value == value) {
						parentNode.left = target.right;
					}else {
						parentNode.right = target.right;
					}
				}
			}
		}
	}
	/**
	 * 删除二叉排序子树中节点值最小的节点
	 * @param node 该子树的根节点
	 * @return 返回删除节点的值
	 */
	public int removeRightMin(TreeNode node) {
		TreeNode temp = node;
		while(temp.left != null) {
			temp = temp.left;
		}
		int rightMinValue = temp.value;
		removeNode(rightMinValue);
		return rightMinValue;
	}
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值