数据结构(四):二叉查找树简介及Java实现

二叉查找树中,每个节点的左子树中的所有节点都小于该节点,而其右子树中的所有节点都大于该节点。通常情况下,二叉树的平均深度都约为C*log(N),C为常数。所以其读取、插入删除的复杂度都为log(N)。但是在极端情况下二叉查找树会退化为一条链表,比如将一系列已经排好序的节点插入一棵树中时。

二叉查找树的Java实现如下。

public class BinarySearchTree<Key extends Comparable<Key>, Value> {
	
	private Node root;
	
	private class Node {
		private Key k;
		private Value v;
		private Node left;
		private Node right;
		private int size;
		
		public Node(Key k, Value v, int size) {
			this.k = k;
			this.v = v;
			this.size = size;
		}
	}
	
	/**
	 * 在树中插入一键值对,先查询键存不存在,若存在,就更新对应的值
	 * 若不存在,就创建一个新的结点
	 * 若v值为null,就删除相应的键
	 * @param k 需要插入的键
	 * @param v 对应的需要插入的值
	 */
	public void put(Key k, Value v) {
		if(k == null) {
			throw new IllegalArgumentException("k can not be null");
		}
		if(v == null) {
			delete(k);
		}
		root = put(k, v, root);
	}
	
	/**
	 * @param k 需要插入的键
	 * @param v 对应的需要插入的值
	 * @param node 在以node为根结点的子树中插入
	 * @return 插入该键值对之后的子树的根结点
	 */
	private Node put(Key k, Value v, Node node) {
		if(node == null) {
			return new Node(k, v, 1);
		}
		int cmp = k.compareTo(node.k);
		if(cmp < 0) {
			node.left = put(k, v, node.left);
		} else if(cmp > 0) {
			node.right = put(k, v, node.right);
		} else {
			node.v = v;
		}
		node.size = size(node.left) + size(node.right) + 1;
		return node;
	}
	
	/**
	 * 如果键k为空,抛异常
	 * @param k 需要查找的键
	 * @return 与键相对应的值,如果树中不存在键k,返回null
	 */
	public Value get(Key k) {
		if(k == null) {
			throw new IllegalArgumentException("k can not be null");
		}
		return get(k, root);
	}
	
	/**
	 * @param k 需要查找的键
	 * @param node 在以node为根结点的子树中查找
	 * @return 子树中与键对应的值,若子树中不存在,返回null
	 */
	private Value get(Key k, Node node) {
		if(node == null) {
			return null;
		}
		int cmp = k.compareTo(node.k);
		if(cmp == 0) {
			return node.v;
		} else if(cmp < 0) {
			return get(k, node.left);
		} else {
			return get(k, node.right);
		}
	}
	
	public void delete(Key k) {
		if(k == null) {
			throw new IllegalArgumentException("k can not be null");
		}
		root = delete(k, root);			
	}
	
	private Node delete(Key k, Node node) {
		if(node == null) {
			return null;
		}
		int cmp = k.compareTo(node.k);
		if(cmp < 0) {
			node.left = delete(k, node.left);
		} else if(cmp > 0) {
			node.right = delete(k, node.right);
		} else {
			if(node.left == null) return node.right;
			if(node.right == null) return node.left;						
			Node temp = node;
			node = min(temp.right);
			node.left = temp.left;
			node.right = deleteMin(temp.right);
		}
		node.size = size(node.left) + size(node.right) + 1;
		return node;
		
	}

	/**
	 * @return 二叉树中的最小键
	 */
	public Key min() {
		Node n = min(root);
		if(n == null) return null;
		return n.k;
	}
	
	/**
	 * @param node 子树的根结点
	 * @return 以node为根结点的子树中最小键对应的结点
	 */
	private Node min(Node node) {
		if(node == null || node.left == null) {
			return node;
		}
		return min(node.left);
		/*
		if(node == null)
			return node;
		Node n = node;
		while(n.left != null) {
			n = n.left;
		}
		return n;
		*/
	}
	
	/**
	 * @return 二叉树中的最大键
	 */
	public Key max() {
		Node n =  max(root);
		if(n == null) return null;
		return n.k;
	}
	
	/**
	 * @param node 子树的根结点
	 * @return 以node为根结点的子树中最大键对应的结点
	 */
	private Node max(Node node) {
		if(node == null || node.right == null) {
			return node;
		}
		return max(node.right);
		/*
		if(node == null) {
			return node;
		}
		Node n = node;
		while(n.right != null) {
			n = n.right;
		}
		return n;
		*/
	}
	
	/**
	 * 向下取整
	 * @param k 查找的键
	 * @return 小于等于键k的最大键
	 */
	public Key floor(Key k) {
		if(k == null) {
			throw new IllegalArgumentException("k can not be null");
		}
		Node n = floor(k, root);
		if(n == null)
			return null;
		return n.k;
	}
	
	/**
	 * 向下取整所对应的键的结点
	 * @param k 查找的键
	 * @param node 子树的根结点
	 * @return 以node为根结点的子树中,小于等于键k的最大键所对应的结点
	 */
	private Node floor(Key k, Node node) {
		if(node == null)
			return null;
		int cmp = k.compareTo(node.k);
		if(cmp == 0) {
			return node;
		} else if(cmp < 0) {
			return floor(k, node.left);
		} else {
			Node temp = floor(k, node.right);
			if(temp == null)
				return node;
			return temp;
		}
	}
	
	/**
	 * 向上取整
	 * @param k 查找的键
	 * @return 大于等于键k的最小键
	 */
	public Key celling(Key k) {
		if(k == null) {
			throw new IllegalArgumentException("k can not be null");
		}
		Node n = celling(k, root);
		if(n == null)
			return null;
		return n.k;
	}
	
	/**
	 * 向上取整所对应的键的结点
	 * @param k 查找的键
	 * @param node 子树的根结点
	 * @return 以node为根结点的子树中,大于等于键k的最小键所对应的结点
	 */
	private Node celling(Key k, Node node) {
		if(node == null)
			return null;
		int cmp = k.compareTo(node.k);
		if(cmp == 0) {
			return node;
		} else if(cmp > 0) {
			return celling(k, node.right);
		} else {
			Node temp = celling(k, node.left);
			if(temp == null)
				return node;
			return temp;
		}
	}
	
	/**
	 * @return 二叉树的结点总数
	 */
	public int size() {
		return size(root);
	}

	/**
	 * @param node 需要求结点总数的子树的根结点
	 * @return 以该结点为根的子树中结点的总数
	 */
	private int size(Node node) {
		if(node == null) 
			return 0;
		else
			return node.size;
	}
	
	/**
	 * 查询秩为k的键,以0开始计数(即树中从小到大第k+1个键)
	 * @param k 秩数
	 * @return 树中秩为k的键
	 */
	public Key select(int k) {
		Node n = select(k, root);
		if(n == null)
			return null;
		return n.k;
	}
	
	/**
	 * 查询秩为k的键
	 * @param k 序数
	 * @param node 子树的根结点
	 * @return 以node为根结点的子树中秩为k的键对应的结点
	 */
	private Node select(int k, Node node) {
		if(node == null)
			return null;
		int t = size(node.left);
		if(k == t)
			return node;
		else if(k < t)
			return select(k, node.left);
		else
			return select(k-t-1,node.right);
	}
	
	/**
	 * 查询小于键K的个数
	 * @param k 待查询的键k
	 * @return 树中小于键k的节点数
	 */
	public int rank(Key k) {
		return rank(k, root);
	}
	
	/**
	 * 在以node为根结点的子树中查询小于键K的个数
	 * @param k 待查询的键
	 * @param node 子树的根结点
	 * @return 树中小于键k的节点数
	 */
	private int rank(Key k, Node node) {
		if(node == null)
			return 0;
		int cmp = k.compareTo(node.k);
		if(cmp < 0) 
			return rank(k, node.left);
		else if(cmp > 0)
			return rank(k, node.right) + size(node.left) + 1;
		else
			return size(node.left);
	}
	
	public void deleteMin() {
		root = deleteMin(root);
	}
	
	private Node deleteMin(Node node) {
		if(node == null)
			return null;
		if(node.left == null)
			return node.right;
		node.left = deleteMin(node.left);
		node.size = size(node.left) + size(node.right) + 1;
		return node;				
	}
	
	public void deleteMax() {
		root = deleteMax(root);
	}
	
	private Node deleteMax(Node node) {
		if(node == null)
			return null;
		if(node.right == null)
			return node.left;
		node.right = deleteMax(node.right);
		node.size = size(node.left) + size(node.right) + 1;
		return node;			
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值