Interval Tree(区间树)

该文章已生成可运行项目,

一、基础知识储备:

	建议学一下红黑树,因为本文的区间树构建是在红黑树的基础上构建的;
    推荐红黑树学习链接: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.ii重叠。(i.low<=i.highi.low<=i.high.b.ii的左边(也就是i.high<i.low.c.ii的右边(也就是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;
}

六、总结

operationbruteinterval
search tree
best
in theory
insert interval1log Nlog N
find inervalNlog Nlog N
delete intervalNlog Nlog N
find any one interval
that intersects(low,high)
Nlog Nlog N
find all intervals that
intersects(low, high)
NK log NK+log N
本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值