二分查找
在有序数组中,要搜索元素x,先把v与中间位置的元素进行比较,如果x较小,那么x必定在数组的前半部分;如果x较大,那么x必定在数组的后半部分。
int arr[];
...
int bsearch(int left,int right, int x) {
if(left>right) return -1;
int mid = 0;
//注意是<=
while (left <= right)
{
mid = (right-left)/2 + left; // 防止溢出
if (arr[mid] == x)
return mid;
else if (arr[mid] < x)
left = mid + 1;
else right = mid - 1;
}
return -1;
}
在一次查找中,无论有没有找到,二分查找使用不超过[lgN]+1次的比较。
二叉搜索树(BST)
定义:二叉搜索树(BST)是一棵二叉树,它的每个内部节点都关联一个关键字,并具有以下性质:任意节点的关键字大于等于该节点左子树中所有节点的关键字,小于等于该节点右子树中所有节点的关键字。
BST的搜索和插入操作的实现为
Item searchR(link h,Key v)
{
Key t=key(h->item);
if(h==z return NULLitem;//z表示空树
if eq(v,t) return h->item;
if less(v,t) return searchR(h->l,v);
else return searchR(h->r,v);
}
Item STsearch(Key v)//此函数递归调用searchR函数
{return searchR(head,v);}//head指向根节点
link insertR(link h,Item item)
{
Key v=key(item),t=key(h->item);
if(h==z) return NEW(item,z,z,1);//NEW是构造新节点的函数。当树为空时,构造根节点,指向左右两个空树,树的大小为1
if(less(v,t)//若待插入元素的关键字小于h的关键字
h->l=insertR(h->l,item);
else h->r=insertR(h->r,item);
(h->N)++;//树的总大小加1
return h;
}
void STinsert(Item item)//递归调用insertR函数
{head=insertR(head,item);}
程序中,搜索函数和二分搜索的思路基本一样。BST的基本特征是插入实现和搜索实现一样简单。递归函数insertR的思路是:如果树为空,就返回包含数据项的一个新节点;如果待插入关键字小于根节点的关键字,把新节点插入到左子树,并使左链接指向它;否则把它插入到右子树,并使右链接指向它。
另外,对BST的排序操作可以用中序遍历实现。
基于旋转操作的BST中的根插入
左旋转:
左旋转把右孩子节点及其右子树提升一层,同时把根节点及其左子树下移一层:把原根节点作为原右孩子节点(新的根节点)的左节点,并把原右孩子节点的左子树作为其新的右子树。
//返回新的根节点,也就是旋转后的原右孩子节点
link rotL(link h)
{
link x=h->r;
h->r=x->l;
x->l=h;
return x;
}
右旋转:
把左孩子节点及其左子树提升一层,同时把根节点及其右子树下移一层:把原根节点作为原左孩子节点(新的根节点)的右节点,并把原左孩子节点的右子树作为原根节点新的左子树。
//返回新的根节点,也就是旋转后的原左孩子节点
link rotR(link h)
{
link x=h->l;
h->l=x->r;
x->r=h;
return x;
}
利用旋转操作,可以在BST中递归地将一个新节点插入到根节点。
link insertT(link h,Item item)
{
Key v=key(item);
if(h==z) return NEW(item,z,z,1);//如果树是空的,直接构造根节点
if(less(v,key(h->item)))
{h->l=insertT(h->l,item);h=rotR(h);}//递归进行插入,并通过旋转把新节点移到根节点的位置
else
{h->r=insertT(h->r,item);h=rotL(h);}
return h;
}
void STinsert(Item item)
{head=insertT(head,item);}