二分查找和二叉查找树

1  二分查找

算法思想:

二分查找要求元素排列有序。首先,假设表中元素是按升序排列,将数组中间位置的元素与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将数组分成前、后两个子数组,如果中间位置记录的元素大于查找关键字,则进一步查找前一子数组,否则进一步查找后一子数组。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

二分查找的时间复杂度为O(logN)

算法实现:

递归算法:

//递归算法
public int rank(Key key, int lo, int hi) {
	if(hi<lo)	return lo;
	int mid = lo + (hi-lo)/2;
	int cmp = key.compareTo(keys[mid]);
	if(cmp<0)	return rank(key,lo,hi-1);
	if(cmp>0)	return rank(key,mid+1,hi);
	else return mid;
}

非递归算法:

//非递归算法
public int rank(Key key) {
	int lo = 0, hi = N-1;
	while(lo<=hi) {
		int mid = lo + (hi-lo)/2;
		int cmp = key.compareTo(keys[mid]);
		if(cmp<0)	hi = mid-1;
		if(cmp>0)	lo = mid+1;
		else return mid;
	}
	return lo;
}

2  二叉查找树

定义:

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树

  • 若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
  • 若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
  • 左、右子树也分别为二叉排序树;

步骤:

若根结点的关键字值等于查找的关键字,成功。否则,若小于根结点的关键字值,递归查左子树。若大于根结点的关键字值,递归查右子树。若子树为空,查找不成功。

二叉查找树的时间复杂度为O(logN)

算法实现:

结点类:
private class Node{
	private Key key;
	private Value val;
	private Node left,right;
	private int N;
	
	public Node(Key key,Value val, int N) {	this.key = key; this.val = val; this.N = N; }
}

其中N为以该节点为根的子树的节点总数,计算方法如下:

size(x) = size(x.left) + size(x.right) + 1

 查找方法:

递归查找,如果小于当前结点,递归去左子树查找;如果大于当前结点,递归去右子树查找。

public Value get(Key key) {
	return get(root,key);
}
public Value get(Node x,Key key) {
	if(x==null)return null;
	int cmp = key.compareTo(x.key);
	if(cmp<0)	return get(x.left,key);
	if(cmp>0)	return get(x.right,key);
	else return x.val;
}
插入方法:

先查找,如果树中已经存在相应的键,只需更新值;如果查询无果,指针也已经指向了应该插入的位置,用要插入的键值对新创结点并插入到相关位置。

public void put(Key key,Value val) {
	root = put(root,key,val);
}
private Node put(Node x,Key key,Value val) {
	if(x == null) return new Node(key,val,1);
	int cmp = key.compareTo(x.key);
	if(cmp<0)	x.left = put(x.left,key,val);//插入左子树
	if(cmp>0)	x.right = put(x.right,key,val);//插入右子树
	else x.val = val;//更新值
	x.N = size(x.left) + size(x.right)+1;
	return x;
}
删除方法:
  1. 即将被删除的节点记为t
  2. x指向它的后继节点min(t.right)
  3. 将x的右链接链接到x的父节点的左链接上(即替换掉原x的位置)
  4. 用x节点替换t节点(将t.left和t.right设为x.left和x.right)
public void delete(Key key) {
	root = delete(root,key);
}
private Node delete(Node x,Key key) {
	if(x == null)	return null;
	int cmp = key.compareTo(x.key);
	if(cmp<0)	x.left = delete(x.left,key);
	if(cmp>0)	x.right = delete(x.right,key);
	else {
		if(x.right == null)		return x.left;
		if(x.left == null)		return x.right;
		Node t = x;
		x = min(t.right);
		x.right = deleteMin(t.right);
		x.left = t.left;
	}
    x.N = size(x.left)+size(x.right)+1;
	return x;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值