二叉搜索树简介
二叉搜索树简介¶
二叉搜索树是一种二叉树的树形数据结构,其定义如下:
-
空树是二叉搜索树。
-
若二叉搜索树的左子树不为空,则其左子树上所有点的附加权值均小于其根节点的值。
-
若二叉搜索树的右子树不为空,则其右子树上所有点的附加权值均大于其根节点的值。
-
二叉搜索树的左右子树均为二叉搜索树。
二叉搜索树上的基本操作所花费的时间与这棵树的高度成正比。对于一个有
基本操作¶
在接下来的代码块中,我们约定 val[x]
为结点 cnt[x]
为结点 lc[x]
和 rc[x]
分别为结点
遍历二叉搜索树¶
由二叉搜索树的递归定义可得,二叉搜索树的中序遍历权值的序列为非降的序列。时间复杂度为
遍历一棵二叉搜索树的代码如下:
1 2 3 4 5 6 7 | void print(int o) {
// 遍历以 o 为根节点的二叉搜索树
if (!o) return; // 遇到空树,返回
print(lc[o]); // 递归遍历左子树
for (int i = 1; i <= cnt[o]; i++) printf("%d\n", val[o]); // 输出根节点信息
print(rc[o]); // 递归遍历右子树
}
|
查找最小/最大值¶
由二叉搜索树的性质可得,二叉搜索树上的最小值为二叉搜索树左链的顶点,最大值为二叉搜索树右链的顶点。时间复杂度为
findmin 和 findmax 函数分别返回最小值和最大值所对应的结点编号 val[o]
可以获得相应的最小/最大值。
1 2 3 4 5 6 7 8 | int findmin(int o) {
if (!lc[o]) return o;
return findmin(lc[o]); // 一直向左儿子跳
}
int findmax(int o) {
if (!rc[o]) return o;
return findmax(rc[o]); // 一直向右儿子跳
}
|
插入一个元素¶
定义 insert(o,v)
为在以
分类讨论如下:
若
若
若
若
时间复杂度为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void insert(int& o, int v) {
if (!o) {
val[o = ++sum] = v;
cnt[o] = siz[o] = 1;
lc[o] = rc[o] = 0;
return;
}
siz[o]++;
if (val[o] == v) {
cnt[o]++;
return;
}
if (val[o] > v) insert(lc[o], v);
if (val[o] < v) insert(rc[o], v);
}
|
删除一个元素¶
定义 del(o,v)
为在以
先在二叉搜索树中找到权值为
若该节点的附加
若该节点的附加
若
若
若
时间复杂度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | int deletemin(int& o) {
if (!lc[o]) {
int u = o;
o = rc[o];
return u;
} else {
int u = deletemin(lc[o]);
siz[o] -= cnt[u];
return u;
}
}
void del(int& o, int v) {
// 注意 o 有可能会被修改
siz[o]--;
if (val[o] == v) {
if (cnt[o] > 1) {
cnt[o]--;
return;
}
if (lc[o] && rc[o]) o = deletemin(rc[o]);
// 这里以找右子树的最小值为例
else
o = lc[o] + rc[o];
return;
}
if (val[o] > v) del(lc[o], v);
if (val[o] < v) del(rc[o], v);
}
|
求元素的排名¶
排名定义为将数组元素排序后第一个相同元素之前的数的个数加一。
维护每个根节点的子树大小
时间复杂度
1 2 3 4 5 | int queryrnk(int o, int v) {
if (val[o] == v) return siz[lc[o]] + 1;
if (val[o] > v) return queryrnk(lc[o], v);
if (val[o] < v) return queryrnk(rc[o], v) + siz[lc[o]] + cnt[o];
}
|
查找排名为 k 的元素¶
在一棵子树中,根节点的排名取决于其左子树的大小。
若其左子树的大小大于等于
若其左子树的大小在区间
若其左子树的大小小于
时间复杂度
1 2 3 4 5 6 | int querykth(int o, int k) {
if (siz[lc[o]] >= k) return querykth(lc[o], k);
if (siz[lc[o]] < k - cnt[o]) return querykth(rc[o], k - siz[lc[o]] - cnt[o]);
return val[o];
// 如要找排名为 k 的元素所对应的结点,直接 return o 即可
}
|
build本页面最近更新:,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:OI-wiki
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用