【二叉搜索树】-手撕加图解

定义

二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。 [1] 

 时间复杂度

不论哪一种操作,所花的时间都和树的高度成正比。因此,如果共有n个元素,那么平均每次操作需要O(logn)的时间。

实现

1、定义树

 class Node {
   public int value ;
   public Node left ;
   public Node right;
	
   public Node(int value ) {
	    this.value=value;
		this.left=null;
		this.right=null;
   }
   public Node(int value,Node left,Node right ) {
	   this.value = value;
	   this.left = left;
	   this.right = right;
   }
}

1.1、常用方法(查找树最大/小节点,是否包含指定值)

//查找最小节点
	public Node findMin(Node root){
		if(root == null) { return null;}
		while(root.left != null) {
			root = root.left;
		}
		return root;
	}
	//查找最大节点
	public Node findMax(Node root){
		if(root == null) { return null;}
		while(root.right != null) {
			root = root.right;
		}
		return root;
	}
	//是否存在值x
	public boolean isContains(int x){
		Node current = root;
		if(root == null) { return false;}
		while(current.value != x && current != null) {
			if(x < current.value) {current = current.left;}
			if(x > current.value) {current = current.right;}
			if(current == null){return false;}
		}
		if(current.value == x) {return true;}
		return false;
	}

2、插入

        插入比较简单,保证当前节点的左节点的值均小于当前节点的值,右节点则均大于当前节点的值,下面的实现代码Java

	public Node insert (int x) {
		Node current = root;
		if(root == null) { root = new Node(x); return root;}
		while(current != null) {
			if(x < current.value) {
				if(current.left == null) {
					return  current.left =  new Node(x);
				}else {
					current = current.left;
				}
			}
			if(x > current.value) {
				if(current.right == null) {
					return  current.right =  new Node(x);
				}else {
					current = current.right;
				}
			}
		}
		return current;
	}

3、删除

删除相比较插入复杂一点,但也是有规律的。可以分3种情况!

1.待删除节点, 左右支都为null,此时直接删除该节点即可

2.待删除节点只有一个节点, 左支/右支,  拿左支或右支替换即可。

3.待删除节点,左右支都有值。 【可以找到左支的最大值,或右支最小值 替换】

3.1、递归方式实现

// 递归 删除节点   ,  使用左节点最大值,替换
	public Node removeByLeftMax(int x ,Node t) {
		if(t == null) {
			return null;
		}
		if(x < t.value) {
			// 递归左节点
			t.left = removeByLeftMax(x,t.left);
		}else if(x > t.value) {
			//递归右节点
			t.right = removeByLeftMax(x,t.right);
		}else {
			if( t.left != null && t.right != null) {
				// 使用左侧最大值替换当前节点
				t.value = findMax(t.left).value;
				// 删除替换的值(删除原待删除节点就变为删除替换的值所在的节点)
				t.left = removeByLeftMax(t.value, t.left);
			}else {
				if (t.left == null && t.right == null) {
					 t = null;
				}else if (t.right != null) {
					 t = t.right;
				}else if (t.left != null) {
					 t = t.left;
				}
			}
		}
		return t;
	}

3.2、非递归实现

// 删除 非递归形式
	public boolean Delete(int x) {
		
		Node current = root ;
		if(root == null) {
			return false;
		}
		Node parent = null ;  // 父节点
		int flag = 0 ;  // 替换节点是父节点的  1 左节点  2 右节点
		while(current != null && current.value != x) {
			if( x < current.value ) {
				if ( current.left != null && current.left.value == x   ) {
					parent = current;
					flag = 1;
				}
				if(current.right != null  && current.right.value == x    ) {
					parent = current;
					flag = 2;
				}
				
				current = current.left;
			} 
			if( x > current.value ) {
				if( current.left != null  && current.left.value == x  ) {
					parent = current;
					flag = 1;
				}
				if(   current.right != null  && current.right.value == x  ) {
					parent = current;
					flag = 2;
				}
				current = current.right;
			} 
		}
		if(current != null && current.value == x) {
			//1、待删除节点, 左右支都为null.  
			// 找到  待删除节点的父节点, 然后删除父节点对应的左/右值,即删除当前节点。
			if(current.left == null && current.right == null) {
				if(flag == 1 ) {
					parent.left = null;
				}
				if(flag == 2 ) {
					parent.right = null;
				}
				return true;
//				current = null;
//				return true;
			// 2、待删除节点,左右支都有值。 【可以找到左支的最大值,或右支最小值 替换】
			}else if(current.left != null && current.right != null) {
				Node findMax = findMax(current.left);  
				Node right = current.right;  
				current.value = findMax.value;  // 当前节点值,替换为 找到的左支最大值
				current.left = findMax.left; // 左节点已经变味 找到左支最大的值的左节点
				current.right = right;// 右节点还是当前节点的右节点
				return true;
			}else{
				//  3、待删除节点只有一个节点, 左支/右支,  拿左支或右支替换即可。
				Node tmp ;
				if(current.left != null) {
					tmp = current.left;
					current.value = tmp.value;
					current.left = tmp.left;
					current.right = tmp.right;
				}else if(current.right != null) {
					tmp  = current.right;
					current.value = tmp.value;
					current.left = tmp.left;
					current.right = tmp.right;
				}
				return true;
			}
		}
		return false;
	}

4、测试验证

public static void main(String[] args) {
		 BinarySortTree treeTest = new BinarySortTree();
		 // 插入测试
		 Node node = treeTest.insert(15);
		 treeTest.insert(6);
		 treeTest.insert(23);
		 treeTest.insert(4);
		 treeTest.insert(7);
		 treeTest.insert(5);
		 treeTest.insert(19);
		 treeTest.insert(17);
//		 treeTest.insert(21);
		 treeTest.insert(71);
		 treeTest.insert(50);
		 treeTest.insert(75);
		 List<Integer> list = new ArrayList<Integer>();
		 //删除6前 前序遍历  [15, 6, 4, 5, 7, 23, 19, 17, 71, 50, 75]
//		 System.out.println(treeTest.MiddleSearch(node,list,1));
		 System.out.println(treeTest.removeByLeftMax(5, node)); 
        // 删除6后 前序遍历[15, 5, 4, 7, 23, 19, 17, 71, 50, 75]
		 System.out.println(treeTest.MiddleSearch(node,list,1));
		
		 
	}

总结 

以上就是二叉搜索树的思路及代码,需要讨论或笔者有遗漏的麻烦评论区留言哦,接下来手撕AVL,红黑树等,敬请期待!码字不易双击点赞哦。。

备注

文章思路参考big Sai博主,再次基础上添加了非递归实现思路。大家有更好的想法一起交流哦!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值