二叉搜索树

32 篇文章 0 订阅

一、定义

二叉搜索树:二叉搜索树(Binary Search Tree),它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树

二、具体操作

1、查找。

2、插入。

3、删除。具体分析如下图所示

4.一般不建议修改。因为对于二叉搜索树来说,修改操作不能针对key修改,最多修改value。如果实在要修改key,可以先删key,再插入一个新的key

三、特性

1.二叉搜索树的中序遍历是一个有序序列

2.最优情况下平均比较次数:log2N,最差情况下平均比较次数:N/2

3.代码实现的圈复杂度非常高

四、代码实现

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

		@Override
		public String toString() {
			return "Node [key=" + key + ", value=" + value + "]";
		}
	}
	
	//创建一个根节点,初始情况为空树,根节点指向null
	private Node root = null;
	
	//查找
	public Node search(int key) {
		//从root出发,比较key和root中key的大小关系
		//根据这个关系决定接下来在左子树中找还是右子树中找
		//如果遇到null,说明查找结束
		Node cur = root;
		while(cur != null) {
			if(key == cur.key) {
				//找到了
				return cur;
			}else if (key < cur.key) {
				//左子树找
				cur = cur.left;
			}else {
				//右子树找
				cur = cur.right;
			}
		}
		//没找到
		return null;
	}
	
	//插入
	//1.先找到合适位置
	//2.把新节点放入该位置
	//插入失败约定方式:
	//(1)如果当前key已存在,则插入失败(TreeSet)
	//(2)如果当前key存在,直接修改value(TreeMap)
	public boolean insert(int key,int value) {
		//1.如果当前为空树,直接用root指向新节点
		if(root == null) {
			root = new Node(key, value);
			return true;
		}
		//2.非空树,先找合适的位置,查找过程中随时记录当前节点的父节点
		Node cur = root;
		//parent一直指向cur的父节点
		Node parent = null;
		while(cur != null) {
			if(key == cur.key) {
				//找到了,按照约定方式一解决
				return false;
			}else if (key < cur.key) {
				//左子树中找
				parent = cur;
				cur = cur.left;
			}else {
				//右子树中找
				parent = cur;
				cur = cur.right;
			}
		}
		//循环结束,cur一定是null,新节点应当插入到parent下方
		//循环操作的关键就在于:找到parent是谁
		Node newNode = new Node(key, value);
		if(key < parent.key) {
			//插入到左子树的位置
			parent.left = newNode;
		}else {
			//插入到右子树的位置
			parent.right = newNode;
		}
		return true;
	}
	
	//删除
	public boolean remove(int key) {
		Node cur = root;
		Node parent = null;
		//查找要删除的元素的位置
		while(cur!=null) {
			if(key == cur.key) {
				//找到了
				removeNode(parent,cur);
				return true;
			}else if (key < cur.key) {
				//向左找
				parent = cur;
				cur = cur.left;
			}else {
				//向右找
				parent = cur;
				cur = cur.right;
			}
		}
		//未找到对应节点
		return false;
	}
	//辅助删除函数
	private void removeNode(Node parent,Node cur) {
		//1.没有左子树
		if(cur.left == null) {
			if(cur == root) {
				//1.1 直接让root指向cur.right
				root = cur.right;
			}else if (cur==parent.left) {
				//1.2 直接让parent的left指向cur的right
				parent.left = cur.right;
			}else {
				//1.3 直接让parent的right指向cur的right
				parent.right = cur.right;
			}
		}else if (cur.right == null) {
			//2.没有右子树
			if(cur == root) {
				//2.1 直接让root指向cur.left
				root = cur.left;
			}else if (cur==parent.left) {
				//2.2 直接让parent的left指向cur的left
				parent.left = cur.left;
			}else {
				//1.3 直接让parent的right指向cur的left
				parent.right = cur.left;
			}
		}else {
			//3.左右子树都不为空
			Node scapeGoat = cur.right;
			Node goatParentNode = cur;
			//3.1 去待删除节点的右子树找最左侧元素
			while(scapeGoat.left!=null) {
				goatParentNode = scapeGoat;
				scapeGoat = scapeGoat.left;
			}
			//循环结束,scapeGoat就是替罪羊结点
			//3.2 把替罪羊的key、value赋给待删除节点
			cur.key = scapeGoat.key;
			cur.value = scapeGoat.value;
			//3.3 删除替罪羊结点,它一定没有左子树
			//  还需根据替罪羊是父节点左还是右,进一步判断如何删除
			if(scapeGoat == goatParentNode.left) {
				//替罪羊节点是父亲的左子树
				goatParentNode.left = scapeGoat.right;
			}else{
				//当前替罪羊节点正好是cur.right
				goatParentNode.right = scapeGoat.right;
			}
		}
	}
	
	public static void main(String[] args) {
		BinarySearchTree tree = new BinarySearchTree();
		int[] arr = {9,5,2,7,3,6,8};
		for (int x : arr) {
			tree.insert(x,0);
		}
		tree.remove(5);
		preOrder(tree.root);
		System.out.println();
		inOrder(tree.root);
		System.out.println();
		System.out.println(tree.search(9));
	}
	
	public static void preOrder(Node root) {
		if(root == null) {
			return;
		}
		System.out.print(root.key+" ");
		preOrder(root.left);
		preOrder(root.right);
	}
	
	public static void inOrder(Node root) {
		if(root == null) {
			return;
		}
		inOrder(root.left);
		System.out.print(root.key+" ");
		inOrder(root.right);
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值