二叉搜索树


Binary Search Tree, 简称 BST,也称二叉排序树或二叉查找树。

特点:

  • 任一结点 > 其左子树的所有结点,
    并且< 其右子树的所有结点;

  • 结点的左、右子树,也是二叉排序树;

  • 每个结点键值唯一(不能重复)

重要性质:

  • 中序遍历二叉排序树得到递增序列

所以判断1棵二叉树是否是二叉排序树?
只要中序遍历,得到递增序列才是。

插入

  • 若当前树为空,则新结点为根
  • 若当前树不空,
    将待插入x与根比较;
    • 若x等于根,不用插入
    • 若x大于根,则去右子树(找位置);
    • 若x小于根,则去左子树(找位置);

可以总结为:

插入之前,先查找:

  • 若找到,不用插入
  • 若找不到,则在到达的空位置处,放入x;

所以最新插入的结点,一定是叶子;

void insert(int k){	
	Node *x=root; 	//已有树的根结点 
	Node *y=NULL;	//x的父结点 
	
	Node *z;	//z为左右子树空的实参,键值为 k 
	z=(Node *)malloc(sizeof(Node));
	z->key=k;
	z->l=z->r=NULL;
	
	while (x!=NULL) {
		y=x;
		if (z->key<x->key) x=x->l;
		else x=x->r;
	}
	
	z->p=y;
	if (y==NULL) root=z;	//空树,直接加 
	else {
		if (z->key<y->key) y->l=z;
		else y->r=z;
	}
}

查找

  • 从根结点开始,如果树为空,则返回 NULL
  • 如果非空,从根结点开始,比较待检索的键值
    • 若相等,则成功;

    • 若小于根,
      则去根的左子树;

    • 若大于根,
      则去根的右子树,

Node * find(Node *u, int k){
	while (u!=NULL && k!=u->key){
		if (k<u->key) u=u->l;
		else u=u->r;
	}
	return u;
} 

删除

考虑三种情况:

  • ①要删除叶子结点
    直接删除,并将父结点指针置为 NULL
  • ② 删除只有1个孩子的结点
    将父结点指针指向要删除结点的孩子结点
  • ③ 删除有左右子树的结点
    用另一个结点替代删除的结点:
    • 右子树的最小元素 或者 左子树的最大元素
Node * minNode(Node *u){
	while (u->l!=NULL) u=u->l;
	return u;
}
//确定删除的结点,这里选择 u的后继:大于 u.key的最小key的结点。 
Node * deleteNode(Node *u){ 
	if (u->l==NULL || u->r==NULL) return u;		//没有子结点或者只有1个 
	if (u->r!=NULL) return minNode(u->r);		//2个子结点,如果右子树不空,那么后继选择右子树最小值 
	//如果右子树空,那么后继一定为 u最底层的祖先,并且后继的左孩子也是u的一个祖先 
	//在后继节点处,如果节点是整棵树的根节点的右边,并且这个节点没有右子树,则这个节点的后继节点为null。 
	Node *y=u->p;
	while (y!=NULL && u==y->r){
		u=y;
		y=y->p;
	}
	return y;	
}

void Delete(Node *u){
	Node *y=deleteNode(u);
	Node *x;	//y的子结点
	
	if (y->l!=NULL) x=y->l; //y有左子结点,x为 y的左子结点 
	else x=y->r;	//y有右子结点,x为 y的右子结点
	
	if (x!=NULL) x->p=y->p; //从父结点上,x替代 y
	
	if (y->p==NULL) root=x;	//如果y是根,那么x替代 y成为根 
	else {	 
		if (y==y->p->l) y->p->l=x;	//y为左子结点,x替代为左子结点 
		else y->p->r=x; 	//y为右子结点,x替代为右子结点 
	}
	
	if (y!=u) u->key=y->key; 	//将 y的 key复制到 u中 
	free(y);
}

平均检索长度 ASL

比较次数:不大于树的深度

最坏平均查找长度ASL:(n+1)/2

最好ASL:log2(n) (参考二分查找)

所有操作的复杂度都是 O(logn)

完整代码

所有操作的复杂度都是 O(logn)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;

struct Node{
	int key;
	Node *r,*l,*p; 
};

Node *root;

void insert(int k){	
	Node *x=root; 	
	Node *y=NULL;	
	
	Node *z;	
	z=(Node *)malloc(sizeof(Node));
	z->key=k;
	z->l=z->r=NULL;
	
	while (x!=NULL) {
		y=x;
		if (z->key<x->key) x=x->l;
		else x=x->r;
	}
	
	z->p=y;
	if (y==NULL) root=z;
	else {
		if (z->key<y->key) y->l=z;
		else y->r=z;
	}
}

Node * find(Node *u, int k){
	while (u!=NULL && k!=u->key){
		if (k<u->key) u=u->l;
		else u=u->r;
	}
	return u;
} 

Node * minNode(Node *u){
	while (u->l!=NULL) u=u->l;
	return u;
}

Node * deleteNode(Node *u){ 
	if (u->l==NULL || u->r==NULL) return u;		
	if (u->r!=NULL) return minNode(u->r);	 

	Node *y=u->p;
	while (y!=NULL && u==y->r){
		u=y;
		y=y->p;
	}
	return y;	
}

void Delete(Node *u){
	Node *y=deleteNode(u);
	Node *x;	
	
	if (y->l!=NULL) x=y->l; 
	else x=y->r;	
	
	if (x!=NULL) x->p=y->p; 
	
	if (y->p==NULL) root=x;	
	else {	 
		if (y==y->p->l) y->p->l=x;	
		else y->p->r=x; 	
	}
	
	if (y!=u) u->key=y->key; 	
	free(y);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值