一、基础知识储备:
建议学一下红黑树,因为本文的区间树构建是在红黑树的基础上构建的;
推荐红黑树学习链接:https://blog.csdn.net/cy973071263/article/details/122543826
二、区间树解决了什么问题
解决区间这种信息的存储和动态更新以及重叠区间查询
三、区间之间存在的关系
我们可以把一个区间[t1, t2]表示成一个对象 i ,其中属性i.low=t1为低端点(low endpoint),属性i.high=t2为高端点(high endpoint)。我们称区间 i 和 i’ 重叠(overlap),如果 i ∩ i’ ≠ Ø,即如果i.low < i’.high且i’.low < i.high 。如图下所示,任何两个区间 i 和i’ 满足区间三分律(interval trichotomy),即下面三条性质之一成立:
a.i和i′重叠。(i.low<=i′.high且i′.low<=i.high).b.i在i′的左边(也就是i.high<i′.low).c.i在i′的右边(也就是i’.high<i.low). a. i和i'重叠。(i.low<=i'.high且i'.low<=i.high).\\ b.i在i'的左边(也就是i.high<i'.low).\\ c.i在i'的右边(也就是i’.high<i.low). a.i和i′重叠。(i.low<=i′.high且i′.low<=i.high).b.i在i′的左边(也就是i.high<i′.low).c.i在i′的右边(也就是i’.high<i.low).

四、构建区间树
任何一种新数据结构的提出,都是在基础数据结构上进行拓张来的,其基本思想(步骤):
1.基础数据结构选择
因为红黑树具有较好的平衡树特征,插入、删除、搜索等操作都是在O(logn)时间内完成,我们以区间左端点为关键字,构建区间树。本质简化为红黑树构建,按照区间左端点来构建
2.添加附加信息(类似于面向对象编程语言的继承思想)
每个结点 x 除了区间信息以外,这里还设置了 x.max 值,含义是:以 x 为根的子树中所有区间的端点最大值,目的是为了剪枝优化,加快搜索
3.对信息进行维护
前面我们设置了max值附加信息,这个时候要考虑维护这个附加信息,会不会对我们的插入、删除等操作有影响。答案:不会影响
证明:
给定区间 x.int 和结点 x 的子节点的max值,可以确定 x.max值:
x.max=max(x.int.high,x.left.max,x.right.max)
x.max = max(x.int.high, x.left.max,x.right.max)
x.max=max(x.int.high,x.left.max,x.right.max)
就是一个简单比大小的过程,所以,更新max值属性只需要O(1)时间。
4.设计新的操作
在红黑树的基础上,我们唯一需要设计的新操作就是查询重叠(我们上面提到了区间重叠是什么)区间:
伪代码表示算法:

核心就是: 查询过程中沿着单一路径进行查询,时间复杂度为O(logn),缺点是当我们有多个重叠区间时,只会返回查到的第一个。
所以我们有什么办法可以查询所有重叠区间呢?
思路一: 我们是不是可以将每一次查询到的区间进行存储,然后将这个结点删除,这个时候我们重新执行上面的算法过程,再次查找;当我们有k个重叠区间时,可见查询过程执行了k趟,所以此时的时间复杂度是O(k logn)。
思路二: 上面这种算法的局限性就是,找到第一个重叠区间,算法就会停止,复杂度为O(log n),所以我们能不能考虑在找到第一个重叠区间后,算法继续搜索左、右子树的其他可能的重叠区间。
伪代码如下:
INTERVAL`在这里插入代码片`-SEARCH-ALL(T, i)
1. create an empty list (or array) result
2. INTERVAL-SEARCH-ALL-HELPER(T.root, i, result)
3. return result
INTERVAL-SEARCH-ALL-HELPER(x, i, result)
1. if x = T.nil
2. return // 递归基:空节点直接返回
3.
4. // 如果左子树可能存在与 i 重叠的区间,则递归搜索左子树
5. if x.left ≠ T.nil and x.left.max ≥ i.low
6. INTERVAL-SEARCH-ALL-HELPER(x.left, i, result)
7.
8. // 检查当前节点与 i 是否重叠,若重叠则加入结果
9. if i overlaps x.int
10. add x to result
11.
12. // 如果右子树可能存在与 i 重叠的区间,则递归搜索右子树
13. if x.right ≠ T.nil and x.key ≤ i.high
14. INTERVAL-SEARCH-ALL-HELPER(x.right, i, result)
五、代码(c++实现)
#include <iostream>
#include <iomanip>
#include <string>
#include <vector> // 新增:用于存储重叠区间结点
using namespace std;
#define BLACK 0
#define RED 1
// 区间结构体
struct interval {
int low;
int high;
};
// 区间树结点
struct IntervalTNode {
int key; // 用区间的 low 值作为 key
bool color; // 红黑树颜色
IntervalTNode* parent; // 父节点
IntervalTNode* left; // 左孩子
IntervalTNode* right; // 右孩子
interval inte; // 存储的区间信息
int max; // 以该结点为根的子树中所有区间 high 的最大值
};
// 区间树结构体
struct IntervalTree {
IntervalTNode* root;
};
// 定义哨兵结点 NIL
interval interval0 = { -1, -1 };
IntervalTNode NILL_NODE = { -1, BLACK, nullptr, nullptr, nullptr, interval0, -1 };
IntervalTNode* NIL = &NILL_NODE;
// 返回三个整数中的最大值
int Max(int a, int b, int c) {
int m = (a > b ? a : b);
return (m > c ? m : c);
}
// 判断两个区间是否重叠
bool Overlap(interval a, interval b) {
return !(a.high < b.low || a.low > b.high);
}
// 修改部分:新增递归辅助函数,用于搜索所有与区间 i 重叠的结点
void IntervalT_SearchAll_Helper(IntervalTNode* node, interval i, vector<IntervalTNode*>& result) {
if (node == NIL)
return;
// 若左子树可能存在重叠结点,则递归搜索左子树
if (node->left != NIL && node->left->max >= i.low)
IntervalT_SearchAll_Helper(node->left, i, result);
// 检查当前结点是否重叠
if (Overlap(i, node->inte))
result.push_back(node);
// 若当前结点的 key 小于等于查询区间的 high,则右子树可能存在重叠结点,递归搜索右子树
if (node->right != NIL && node->key <= i.high)
IntervalT_SearchAll_Helper(node->right, i, result);
}
// 修改部分:新增接口,返回所有与区间 i 重叠的结点集合
vector<IntervalTNode*> IntervalT_SearchAll(IntervalTree* T, interval i) {
vector<IntervalTNode*> result;
IntervalT_SearchAll_Helper(T->root, i, result);
return result;
}
// 仅返回第一个与给定区间有重叠的结点(原有函数)
IntervalTNode* IntervalT_Search(IntervalTree* T, interval i) {
IntervalTNode* x = T->root;
while (x != NIL && !Overlap(i, x->inte)) {
if (x->left != NIL && x->left->max >= i.low)
x = x->left;
else
x = x->right;
}
return x;
}
// 精确查找:只有当区间的 low 和 high 都完全匹配时才返回结点
IntervalTNode* IntervalT_SearchExact(IntervalTree* T, interval i) {
IntervalTNode* x = T->root;
while (x != NIL) {
if (x->inte.low == i.low && x->inte.high == i.high)
return x;
if (i.low < x->key)
x = x->left;
else
x = x->right;
}
return NIL;
}
// 中序遍历区间树并打印每个结点的信息
void IntervalT_InorderWalk(IntervalTNode* x) {
if (x != NIL) {
IntervalT_InorderWalk(x->left);
cout << "[" << setw(3) << x->inte.low << ", " << setw(3) << x->inte.high << "] ";
cout << (x->color == RED ? "Red " : "Black ");
cout << "Max:" << x->max << endl;
IntervalT_InorderWalk(x->right);
}
}
// 使用类似 "├──"、"└──" 的符号打印树结构,直观区分左右子树
void printBT(const string& prefix, const IntervalTNode* node, bool isLeft) {
if (node == NIL) {
cout << prefix;
cout << (isLeft ? "├──" : "└──");
cout << "NIL" << endl;
return;
}
cout << prefix;
cout << (isLeft ? "├──" : "└──");
cout << (node->color == RED ? "R" : "B");
cout << "[" << node->inte.low << "," << node->inte.high << "](max:" << node->max << ")" << endl;
printBT(prefix + (isLeft ? "│ " : " "), node->left, true);
printBT(prefix + (isLeft ? "│ " : " "), node->right, false);
}
// 返回以 x 为根的子树中最小的结点
IntervalTNode* IntervalT_Minimum(IntervalTNode* x) {
while (x->left != NIL)
x = x->left;
return x;
}
// 返回结点 x 的后继结点
IntervalTNode* IntervalT_Successor(IntervalTNode* x) {
if (x->right != NIL)
return IntervalT_Minimum(x->right);
IntervalTNode* y = x->parent;
while (y != NIL && x == y->right) {
x = y;
y = y->parent;
}
return y;
}
// 左旋操作
void Left_Rotate(IntervalTree* T, IntervalTNode* x) {
IntervalTNode* y = x->right;
x->right = y->left;
if (y->left != NIL)
y->left->parent = x;
y->parent = x->parent;
if (x->parent == NIL)
T->root = y;
else if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
y->left = x;
x->parent = y;
// 更新 max 值
x->max = Max(x->inte.high, x->left->max, x->right->max);
y->max = Max(y->inte.high, x->max, y->right->max);
}
// 右旋操作
void Right_Rotate(IntervalTree* T, IntervalTNode* x) {
IntervalTNode* y = x->left;
x->left = y->right;
if (y->right != NIL)
y->right->parent = x;
y->parent = x->parent;
if (x->parent == NIL)
T->root = y;
else if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
y->right = x;
x->parent = y;
// 更新 max 值
x->max = Max(x->inte.high, x->left->max, x->right->max);
y->max = Max(y->inte.high, y->left->max, x->max);
}
// 插入修正:维护红黑树性质
void IntervalT_InsertFixup(IntervalTree* T, IntervalTNode* z) {
while (z->parent->color == RED) {
if (z->parent == z->parent->parent->left) {
IntervalTNode* y = z->parent->parent->right;
if (y->color == RED) {
// 情形1
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}
else {
if (z == z->parent->right) {
// 情形2
z = z->parent;
Left_Rotate(T, z);
}
// 情形3
z->parent->color = BLACK;
z->parent->parent->color = RED;
Right_Rotate(T, z->parent->parent);
}
}
else { // 对称情况
IntervalTNode* y = z->parent->parent->left;
if (y->color == RED) {
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}
else {
if (z == z->parent->left) {
z = z->parent;
Right_Rotate(T, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
Left_Rotate(T, z->parent->parent);
}
}
}
T->root->color = BLACK;
}
// 插入一个新的区间到区间树中
void IntervalT_Insert(IntervalTree* T, interval inte) {
IntervalTNode* z = new IntervalTNode();
z->key = inte.low;
z->inte = inte;
z->max = inte.high;
z->color = RED;
z->parent = NIL;
z->left = NIL;
z->right = NIL;
IntervalTNode* y = NIL;
IntervalTNode* x = T->root;
while (x != NIL) {
// 沿途更新 max 值
if (z->max > x->max)
x->max = z->max;
y = x;
if (z->key < x->key)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y == NIL)
T->root = z;
else if (z->key < y->key)
y->left = z;
else
y->right = z;
IntervalT_InsertFixup(T, z);
}
// 后序遍历重新计算整棵树每个结点的 max 值(用于删除后更新)
int computeMax(IntervalTNode* node) {
if (node == NIL) return -1;
int leftMax = computeMax(node->left);
int rightMax = computeMax(node->right);
node->max = Max(node->inte.high, leftMax, rightMax);
return node->max;
}
// 删除修正:维护红黑树性质
void IntervalT_DeleteFixup(IntervalTree* T, IntervalTNode* x) {
IntervalTNode* w;
while (x != T->root && x->color == BLACK) {
if (x == x->parent->left) {
w = x->parent->right;
if (w->color == RED) {
w->color = BLACK;
x->parent->color = RED;
Left_Rotate(T, x->parent);
w = x->parent->right;
}
if (w->left->color == BLACK && w->right->color == BLACK) {
w->color = RED;
x = x->parent;
}
else {
if (w->right->color == BLACK) {
w->left->color = BLACK;
w->color = RED;
Right_Rotate(T, w);
w = x->parent->right;
}
w->color = x->parent->color;
x->parent->color = BLACK;
w->right->color = BLACK;
Left_Rotate(T, x->parent);
x = T->root;
}
}
else {
w = x->parent->left;
if (w->color == RED) {
w->color = BLACK;
x->parent->color = RED;
Right_Rotate(T, x->parent);
w = x->parent->left;
}
if (w->left->color == BLACK && w->right->color == BLACK) {
w->color = RED;
x = x->parent;
}
else {
if (w->left->color == BLACK) {
w->right->color = BLACK;
w->color = RED;
Left_Rotate(T, w);
w = x->parent->left;
}
w->color = x->parent->color;
x->parent->color = BLACK;
w->left->color = BLACK;
Right_Rotate(T, x->parent);
x = T->root;
}
}
}
x->color = BLACK;
}
// 删除区间树中的结点 z
void IntervalT_Delete(IntervalTree* T, IntervalTNode* z) {
IntervalTNode* y = z;
IntervalTNode* x;
bool yOriginalColor = y->color;
if (z->left == NIL || z->right == NIL)
y = z;
else {
y = IntervalT_Successor(z);
yOriginalColor = y->color;
}
if (y->left != NIL)
x = y->left;
else
x = y->right;
x->parent = y->parent;
if (y->parent == NIL)
T->root = x;
else if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
if (y != z) {
z->key = y->key;
z->inte = y->inte;
}
if (yOriginalColor == BLACK)
IntervalT_DeleteFixup(T, x);
computeMax(T->root);
delete y;
}
void printMenu() {
cout << "\n===== Interval Tree 操作菜单 =====" << endl;
cout << "1. 插入区间" << endl;
cout << "2. 搜索与区间重叠的结点(返回所有重叠区间)" << endl;
cout << "3. 删除精确匹配区间" << endl;
cout << "4. 打印中序遍历" << endl;
cout << "5. 打印树结构" << endl;
cout << "6. 退出" << endl;
cout << "请选择操作(1-6): ";
}
int main() {
IntervalTree* T = new IntervalTree();
T->root = NIL;
// 初始构造一组测试区间(可选)
interval initIntervals[] = { {16,21}, {8,9}, {25,30}, {5,8}, {15,23},
{17,19}, {26,26}, {0,3}, {6,10}, {19,20} };
int n = sizeof(initIntervals) / sizeof(interval);
for (int i = 0; i < n; i++)
IntervalT_Insert(T, initIntervals[i]);
int op;
while (true) {
printMenu();
cin >> op;
if (op == 1) { // 插入区间
interval newInt;
cout << "请输入要插入的区间 (low high): ";
cin >> newInt.low >> newInt.high;
IntervalT_Insert(T, newInt);
cout << "插入成功!" << endl;
}
else if (op == 2) { // 搜索重叠区间(改进部分:返回所有重叠区间)
interval sInt;
cout << "请输入搜索区间 (low high): ";
cin >> sInt.low >> sInt.high;
vector<IntervalTNode*> nodes = IntervalT_SearchAll(T, sInt);
if (nodes.empty())
cout << "未找到与该区间重叠的结点。" << endl;
else {
cout << "找到与该区间重叠的结点:" << endl;
for (auto node : nodes) {
cout << "[" << node->inte.low << ", " << node->inte.high << "] ";
cout << (node->color == RED ? "Red " : "Black ");
cout << "Max:" << node->max << endl;
}
}
}
else if (op == 3) { // 删除精确匹配区间
interval dInt;
cout << "请输入待删除的区间 (low high): ";
cin >> dInt.low >> dInt.high;
IntervalTNode* node = IntervalT_SearchExact(T, dInt);
if (node == NIL)
cout << "未找到该精确区间结点。" << endl;
else {
IntervalT_Delete(T, node);
cout << "删除成功!" << endl;
}
}
else if (op == 4) { // 中序遍历打印
cout << "\n当前 Interval Tree (中序遍历):" << endl;
IntervalT_InorderWalk(T->root);
}
else if (op == 5) { // 打印直观树结构
cout << "\n当前 Interval Tree 结构:" << endl;
printBT("", T->root, false);
}
else if (op == 6) { // 退出
break;
}
else {
cout << "无效的选项,请重新选择!" << endl;
}
}
return 0;
}
六、总结
| operation | brute | interval search tree | best in theory |
|---|---|---|---|
| insert interval | 1 | log N | log N |
| find inerval | N | log N | log N |
| delete interval | N | log N | log N |
| find any one interval that intersects(low,high) | N | log N | log N |
| find all intervals that intersects(low, high) | N | K log N | K+log N |
7378

被折叠的 条评论
为什么被折叠?



