实验内容
对红黑树进行修改,使其成为一颗区间数,并实现区间树上的重叠区间查找算法。程序输入:
1、生成区间树
文件名: insert.txt
文件格式:第一行为待插入数据的个数,第二行之后每一行表示一个区间
注:
1)初始时树应为空。
2)按顺序插入。
2、待查询区间应由控制台输入,且由控制台直接打印查找结果(可支持多次查询):
若存在结果,输出对应节点区间: [x, y]
若无结果,输出: nil
实验目的
将实验三中实现的红黑树插入算法改编为区间树插入算法,并实现重叠区间的查找算法:给定一棵区间树T和一个区间i,在O(min(n, klogn))时间内列出T中所有与i重叠的区间,其中k为重叠的区间数。
区间树的数据结构
对原有的红黑树的数据结构进行修改,区间树的数据结构如下:
struct interval
{
int low;
int high;
};
struct Node
{
interval inte;
int max; // 存储以该节点为根的子树中的最大值
Color color;
Node* parent;
Node* left;
Node* right;
};
struct Tree
{
Node* root;
Node* nil;
};
在结点即“Node”中增加了一个新定义的结构体“interval”即区间,还增加了一个int型变量“max”,用于存储以该结点为根的子树中的最大值。删除了变量“key”。
源码及注释
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
enum Color { RED, BLACK };
int NIL=0;
struct interval
{
int low;
int high;
};
struct Node
{
Node(interval inte){
this->inte=inte;
}
interval inte;
int max; // 存储以该节点为根的子树中的最大值
Color color;
Node* parent;
Node* left;
Node* right;
};
struct Tree
{
Node* root;
Node* nil;
};
void LEFT_ROTATE(Tree* &T, Node* x)
{
Node* y = x->right;
x->right = y->left;
if (y->left != T->nil)
y->left->parent = x;
y->parent = x->parent;
if (x->parent == T->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;
// 更新节点的最大值
x->max = max(max(x->left->max, x->right->max), x->inte.high);
y->max = max(max(y->left->max, y->right->max), y->inte.high);
}
void RIGHT_ROTATE(Tree* &T, Node* x)
{
Node* y = x->left;
x->left = y->right;
if (y->right != T->nil)
y->right->parent = x;
y->parent = x->parent;
if (x->parent == T->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;
// 更新节点的最大值
x->max = max(max(x->left->max, x->right->max), x->inte.high);
y->max = max(max(y->left->max, y->right->max), y->inte.high);
}
void RB_INSERT_FIXUP(Tree* &T, Node* z)
{
while (z->parent->color == RED)
{
if (z->parent == z->parent->parent->left)
{
Node* y = z->parent->parent->right;
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->right)
{
z = z->parent;
LEFT_ROTATE(T, z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
RIGHT_ROTATE(T, z->parent->parent);
}
}
else
{
Node* 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 RB_INSERT(Tree* &T, Node* z)
{
Node* y = T->nil;
Node* x = T->root;
while (x != T->nil)
{
y = x;
if (z->inte.low < x->inte.low)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y == T->nil)
T->root = z;
else if (z->inte.low < y->inte.low)
y->left = z;
else
y->right = z;
z->left = T->nil;
z->right = T->nil;
z->color = RED;
// 更新节点的最大值
z->max = z->inte.high;
Node* p = z->parent;
while (p != T->nil)
{
p->max = max(max(p->left->max, p->right->max), p->inte.high);
p = p->parent;
}
RB_INSERT_FIXUP(T, z);
}
// 中序遍历
void InOrder(Node* x, Tree* T)
{
if (x != T->nil)
{
InOrder(x->left, T);
cout << "[" << x->inte.low << "," << x->inte.high << "] ";
InOrder(x->right, T);
}
}
// 更新节点的最大值
void UPDATE_MAX(Node* x)
{
if (x->left != nullptr && x->right != nullptr)
x->max = max(max(x->left->max, x->right->max), x->inte.high);
else if (x->left != nullptr)
x->max = max(x->left->max, x->inte.high);
else if (x->right != nullptr)
x->max = max(x->right->max, x->inte.high);
else
x->max = x->inte.high;
}
// 更新节点的最大值(递归)
void UPDATE_MAX_RECURSIVE(Node* x)
{
if (x == nullptr)
return;
UPDATE_MAX_RECURSIVE(x->left);
UPDATE_MAX_RECURSIVE(x->right);
UPDATE_MAX(x);
}
bool Overlap(interval a, interval b)
{
return (a.low <= b.high && b.low <= a.high);
}
vector<interval> IntervalsSearch(Node* node, Tree* T, interval query)
{
vector<interval> result;
if (node == T->nil)
return result;
if (Overlap(node->inte, query)){
NIL = 1;
result.push_back(node->inte);
}
if (node->left != T->nil && node->left->max >= query.low)
{
vector<interval> leftResult = IntervalsSearch(node->left, T, query);
result.insert(result.end(), leftResult.begin(), leftResult.end());
}
if (node->right != T->nil && node->right->max >= query.low && node->inte.low <= query.high)
{
vector<interval> rightResult = IntervalsSearch(node->right, T, query);
result.insert(result.end(), rightResult.begin(), rightResult.end());
}
return result;
}
int main()
{
Tree* T = new Tree;
interval ii;
ii.high = 0;
ii.low = 0;
T->nil = new Node(ii);
T->nil->color = BLACK;
T->nil->left = nullptr;
T->nil->right = nullptr;
T->root = T->nil;
/*
int num;
cout << "请输入区间数目:";
cin >> num;
vector<vector<int>> arr(num, vector<int>(2));
for (int i = 0; i < num; i++)
{
cout << "请输入第" << i + 1 << "个区间的起始值和结束值:";
cin >> arr[i][0] >> arr[i][1];
}
*/
ifstream file("insert.txt");
int num;
file >> num;
Node* z[num];
vector<vector<int>> arr(num, vector<int>(2));
for (int i = 0; i < num; i++)
{
file >> arr[i][0] >> arr[i][1];
}
file.close();
for (int i = 0; i < num; i++)
{
interval inter;
inter.low = arr[i][0];
inter.high = arr[i][1];
z[i]=new Node(inter);
RB_INSERT(T, z[i]);
//INTERVAL_INSERT(T, inte);
}
cout << "中序遍历:" << endl;
InOrder(T->root, T);
cout << endl;
char continue_flag = 'y';
while(continue_flag == 'y' || continue_flag == 'Y'){
interval query;
cout << "请输入要查询的区间的起始值和结束值:";
cin >> query.low >> query.high;
cout << "与查询区间重叠的区间:" << endl;
vector<interval> result = IntervalsSearch(T->root, T, query);
for (const auto& interval : result)
{
cout << "[" << interval.low << "," << interval.high << "]" << endl;
}
if(NIL == 0) printf("NIL\n");
NIL = 0;
continue_flag = ' ';
while(continue_flag != 'y' && continue_flag != 'Y'&& continue_flag != 'n'&& continue_flag != 'N'){
cout << "是否继续查询?[y/n]"<<endl;
cin >> continue_flag;
}
}
// 释放内存
delete T->nil;
delete T;
return 0;
}
时间复杂度分析
搜索的核心代码如下:
vector<interval> IntervalsSearch(Node* node, Tree* T, interval query)
{
vector<interval> result;
if (node == T->nil)
return result;
if (Overlap(node->inte, query)){
NIL = 1;
result.push_back(node->inte);
}
if (node->left != T->nil && node->left->max >= query.low)
{
vector<interval> leftResult = IntervalsSearch(node->left, T, query);
result.insert(result.end(), leftResult.begin(), leftResult.end());
}
if (node->right != T->nil && node->right->max >= query.low && node->inte.low <= query.high)
{
vector<interval> rightResult = IntervalsSearch(node->right, T, query);
result.insert(result.end(), rightResult.begin(), rightResult.end());
}
return result;
}
时间复杂度分析:
-
如果
node
为空节点(即指向T->nil
),则直接返回空的结果数组result
。时间复杂度为O(1)。 -
如果
node
与查询区间query
重叠(使用Overlap()
函数判断),则将node->inte
添加到结果数组result
中。时间复杂度为O(1)。 -
如果
node
的左子节点不为空且其最大值大于等于查询区间的最小值query.low
,则递归调用IntervalsSearch()
函数在左子树中搜索重叠的区间,并将结果添加到结果数组result
中。递归调用的次数取决于树的高度,因此时间复杂度为O(log n),其中n是树中节点的数量。 -
如果
node
的右子节点不为空且其最大值大于等于查询区间的最小值query.low
且其最小值小于等于查询区间的最大值query.high
,则递归调用IntervalsSearch()
函数在右子树中搜索重叠的区间,并将结果添加到结果数组result
中。递归调用的次数取决于树的高度,因此时间复杂度为O(log n),其中n是树中节点的数量。 -
在最坏的情况下,如果树是一个完全平衡的二叉搜索树,并且查询区间与树中的所有区间都重叠,那么函数的时间复杂度将是O(n),其中n是树中节点的数量。这是因为在这种情况下,函数将递归地访问树中的每个节点,并将其区间添加到结果数组中。
综上所述,整个函数的时间复杂度为O(log n),其中n是树中节点的数量,满足实验要求O(min(n,klogn))。