二叉查找树

156 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情


二叉树的特殊性质可以让查找方式更加迅速

一、基本概念

1.二叉查找树
指二叉树中的每一个结点的键值都大于其左子树中所有结点的键值,同时都小于其右子树中所有结点的键值
2.性质
(1)没有键值相等的结点
(2)以每一个结点为根结点所构成的子树都是二叉查找树
(3)对二叉查找树进行中根遍历,得到一个单调递增的序列
3.类型定义

typedef struct bstNode {
	int key;
	bstNode* lc, * rc;
	bstNode():lc(NULL),rc(NULL){}
}*bstTree;

二、二叉查找树的操作

1.查找操作

1.算法1-1:基于二叉查找树的查找
功能
在给定二叉树t中查找键值为k的结点
算法步骤
(1)如果t为空,则不存在值为k的结点,查找结束;否则根据根结点的键值k1k_1与k的比较结果分三种情况
(2)如果k=k1k=k_1,则找到结点,查找结束
(3)如果k<k1k<k_1,则在t的左子树中查找,进入第一步
(4)如果k>k1k>k_1,则在t的右子树中查找,进入第一步
代码

//在二叉查找树t中查找键值为k的结点,查找结果作为返回值
bstNode* bst_search(bstTree t, int k) {
	if (t == NULL)return NULL;
	if (k < t->key)return bst_search(t->lc, k);//转入左子树查找
	else if (k > t->key)return bst_search(t->rc, k);//转入右子树查找
	else return t;
}

2.插入操作

1.算法1-2:在二叉查找树中插入一个结点
功能
在二叉查找树t中插入一个键值为k的结点
算法步骤
(1)如果t为空,创建t,并令其键值为k,结束;否则进入第二步
(2)比较k与树t的根结点键值k1k_1,如果k<k1k<k_1,则进入第三步;如果k>k1k>k_1,进入第四步;如果k=k1k=k_1,表明t中已存在键值为k的结点,插入失败,结束
(3)考虑t的左子树,进入第一步
(4)考虑t的右子树,进入第一步
代码

//在二叉查找树t中插入一个键值为k的结点。插入成功返回true,否则返回false
bool bst_insert(bstTree& t, int k) {
	if (t == NULL) {//空结点,创建结点,指定键值为k
		t = new bstNode;
		t->key = k;
		return true;
	}
	if (k < t->key)return bst_insert(t->lc, k);
	else if (k > t->key)return bst_insert(t->rc, k);
	return false;//如果t中已存在键值为k的结点,插入失败
}

3.删除操作

1.算法1-3:删除二叉查找数中给定键值的结点
功能
在二叉查找树t中删除键值为k的结点
算法步骤
(1)确定键值为k的结点t1t_1,如果t1t_1为空树,删除失败;否则分为以下情况
(2)如果t1t_1为叶结点,可直接删除t1t_1
(3)如果t1t_1的右子树为空,则用t1t_1的左孩子的键值取代t1t_1的键值,转化为情况(2)、(3)或(4)删除t1t_1的孩子
(4)如果t1t_1的右子树不空,求t1t_1的中根序列的直接后继t2t_2(t1t_1的右子树的最左结点),用t2t_2的键值取代t1t_1的键值,转化为情形(2)或情形(4)删除t2t_2
代码

//删除二叉查找树的t中键值为k的结点。删除成功,返回true,否则返回false
bool bst_delete(bstTree& t, int k) {
	bstNode* tmp;
	if (t == NULL)return false;//不存在键值为k的结点,删除失败
	else if (k < t->key)return bst_delete(t->lc, k);//进入左子树
	else if (k > t->key)return bst_delete(t->rc, k);//进入右子树
	else {//t的键值为k,删除结点t
		if (t->lc == NULL && t->rc == NULL) {//结点为叶结点
			delete t;
			t = NULL;
		}
		else if (t->rc == NULL) {//右结点为空
			tmp = t->lc;
			int k1 = tmp->key;
			bst_delete(t, k1);//删除t的左孩子
			t->key = k1;//用t的左孩子的键值取代t的键值
		}
		else {//右子树不为空
			tmp = t->rc;
			while (tmp->lc)tmp = tmp->lc;//获取t的直接后继tmp
			int k1 = tmp->key;
			bst_delete(t, k1);//删除tmp
			t->key = k1;//用tmp的键值取代t的键值
		}
		return true;
	}
}