开启掘金成长之旅!这是我参与「掘金日新计划 · 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的结点,查找结束;否则根据根结点的键值与k的比较结果分三种情况
(2)如果,则找到结点,查找结束
(3)如果,则在t的左子树中查找,进入第一步
(4)如果,则在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的根结点键值,如果,则进入第三步;如果,进入第四步;如果,表明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的结点,如果为空树,删除失败;否则分为以下情况
(2)如果为叶结点,可直接删除
(3)如果的右子树为空,则用的左孩子的键值取代的键值,转化为情况(2)、(3)或(4)删除的孩子
(4)如果的右子树不空,求的中根序列的直接后继(的右子树的最左结点),用的键值取代的键值,转化为情形(2)或情形(4)删除
代码
//删除二叉查找树的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;
}
}