📜  间隔树

📅  最后修改于: 2021-04-17 11:58:06             🧑  作者: Mango

考虑以下情况:我们有一组间隔,并且需要有效地执行以下操作。
1)添加一个间隔
2)删除间隔
3)给定间隔x,找出x是否与任何现有间隔重叠。

间隔树:想法是增加自平衡二叉搜索树(BST),例如红黑树,AVL树等,以维护间隔集,以便所有操作都可以在O(Logn)时间内完成。

间隔树的每个节点都存储以下信息。
a) i :表示为一对[低,高]的间隔
b) max :以该节点为根的子树中的最大高值。

间隔的低值用作维持BST中顺序的关键。插入和删除操作与使用的自平衡BST中的插入和删除相同。

间隔搜索树

主要操作是搜索重叠间隔。以下是在以root为根的间隔树中搜索重叠间隔x的算法。

Interval overlappingIntervalSearch(root, x)
1) If x overlaps with root's interval, return the root's interval.

2) If left child of root is not empty and the max  in left child 
is greater than x's low value, recur for left child

3) Else recur for right child.

上述算法如何工作?
令要搜索的间隔为x。在以下两种情况下,我们需要证明这一点。

情况1:当我们转到右侧子树时,以下条件之一必须为真。
a)右子树中有一个重叠:这很好,因为我们需要返回一个重叠间隔。
b)在任何一个子树中都没有重叠:仅当left中的任何一个为NULL或left中的最大值小于x.low时,我们才进入right子树。因此,间隔不能出现在左子树中。

情况2:当我们转到左子树时,以下条件之一必须为真。
a)左子树中有一个重叠:这很好,因为我们需要返回一个重叠间隔。
b)在任何一个子树中都没有重叠:这是最重要的部分。我们需要考虑以下事实。
…我们去了左子树,因为左子树中的x.low <= max
…。左子树中的max是其中一个间隔中的最大值,让我们说左子树中的[a,max]。
…。由于x不与左子树中的任何节点重叠,因此x.low必须小于’ a ‘。
…。 BST中的所有节点都按低值排序,因此右子树中的所有节点必须具有大于’ a ‘的低值。
…。从以上两个事实,我们可以说右子树中的所有间隔的低值都大于x.low 。因此, x不能与右子树中的任何间隔重叠。

间隔树的实现:
以下是间隔树的C++实现。该实现使用BST的基本插入操作来使事情保持简单。理想情况下,它应该是插入AVL树或插入红黑树。从BST删除作为练习。

#include 
using namespace std;
  
// Structure to represent an interval
struct Interval
{
    int low, high;
};
  
// Structure to represent a node in Interval Search Tree
struct ITNode
{
    Interval *i;  // 'i' could also be a normal variable
    int max;
    ITNode *left, *right;
};
  
// A utility function to create a new Interval Search Tree Node
ITNode * newNode(Interval i)
{
    ITNode *temp = new ITNode;
    temp->i = new Interval(i);
    temp->max = i.high;
    temp->left = temp->right = NULL;
    return temp;
};
  
// A utility function to insert a new Interval Search Tree Node
// This is similar to BST Insert.  Here the low value of interval
// is used tomaintain BST property
ITNode *insert(ITNode *root, Interval i)
{
    // Base case: Tree is empty, new node becomes root
    if (root == NULL)
        return newNode(i);
  
    // Get low value of interval at root
    int l = root->i->low;
  
    // If root's low value is smaller, then new interval goes to
    // left subtree
    if (i.low < l)
        root->left = insert(root->left, i);
  
    // Else, new node goes to right subtree.
    else
        root->right = insert(root->right, i);
  
    // Update the max value of this ancestor if needed
    if (root->max < i.high)
        root->max = i.high;
  
    return root;
}
  
// A utility function to check if given two intervals overlap
bool doOVerlap(Interval i1, Interval i2)
{
    if (i1.low <= i2.high && i2.low <= i1.high)
        return true;
    return false;
}
  
// The main function that searches a given interval i in a given
// Interval Tree.
Interval *overlapSearch(ITNode *root, Interval i)
{
    // Base Case, tree is empty
    if (root == NULL) return NULL;
  
    // If given interval overlaps with root
    if (doOVerlap(*(root->i), i))
        return root->i;
  
    // If left child of root is present and max of left child is
    // greater than or equal to given interval, then i may
    // overlap with an interval is left subtree
    if (root->left != NULL && root->left->max >= i.low)
        return overlapSearch(root->left, i);
  
    // Else interval can only overlap with right subtree
    return overlapSearch(root->right, i);
}
  
void inorder(ITNode *root)
{
    if (root == NULL) return;
  
    inorder(root->left);
  
    cout << "[" << root->i->low << ", " << root->i->high << "]"
         << " max = " << root->max << endl;
  
    inorder(root->right);
}
  
// Driver program to test above functions
int main()
{
    // Let us create interval tree shown in above figure
    Interval ints[] = {{15, 20}, {10, 30}, {17, 19},
        {5, 20}, {12, 15}, {30, 40}
    };
    int n = sizeof(ints)/sizeof(ints[0]);
    ITNode *root = NULL;
    for (int i = 0; i < n; i++)
        root = insert(root, ints[i]);
  
    cout << "Inorder traversal of constructed Interval Tree is\n";
    inorder(root);
  
    Interval x = {6, 7};
  
    cout << "\nSearching for interval [" << x.low << "," << x.high << "]";
    Interval *res = overlapSearch(root, x);
    if (res == NULL)
        cout << "\nNo Overlapping Interval";
    else
        cout << "\nOverlaps with [" << res->low << ", " << res->high << "]";
    return 0;
}

输出:

Inorder traversal of constructed Interval Tree is
[5, 20] max = 20
[10, 30] max = 30
[12, 15] max = 15
[15, 20] max = 40
[17, 19] max = 40
[30, 40] max = 40

Searching for interval [6,7]
Overlaps with [5, 20]

间隔树的应用:
间隔树主要是一种几何数据结构,通常用于窗口查询,例如,在矩形视口内的计算机化地图上查找所有道路,或在三维场景中查找所有可见元素(来源Wiki)。

间隔树与段树
段树和间隔树都存储间隔。段树主要针对给定点的查询进行优化,间隔树主要针对给定间隔的重叠查询进行优化。

锻炼:
1)对间隔树执行删除操作。
2)扩展intervalSearch()以打印所有重叠的间隔,而不是仅打印一个。

http://en.wikipedia.org/wiki/Interval_tree
http://www.cse.unr.edu/~mgunes/cs302/IntervalTrees.pptx
算法入门第三版,作者:Clifford Stein,Thomas H. Cormen,Charles E. Leiserson,Ronald L. Rivest
https://www.youtube.com/watch?v=dQF0zyaym8A