区间树上重叠区间的查找

实验内容

对红黑树进行修改,使其成为一颗区间数,并实现区间树上的重叠区间查找算法。程序输入:
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;
}

时间复杂度分析:

  1. 如果node为空节点(即指向T->nil),则直接返回空的结果数组result。时间复杂度为O(1)。

  2. 如果node与查询区间query重叠(使用Overlap()函数判断),则将node->inte添加到结果数组result中。时间复杂度为O(1)。

  3. 如果node的左子节点不为空且其最大值大于等于查询区间的最小值query.low,则递归调用IntervalsSearch()函数在左子树中搜索重叠的区间,并将结果添加到结果数组result中。递归调用的次数取决于树的高度,因此时间复杂度为O(log n),其中n是树中节点的数量。

  4. 如果node的右子节点不为空且其最大值大于等于查询区间的最小值query.low且其最小值小于等于查询区间的最大值query.high,则递归调用IntervalsSearch()函数在右子树中搜索重叠的区间,并将结果添加到结果数组result中。递归调用的次数取决于树的高度,因此时间复杂度为O(log n),其中n是树中节点的数量。

  5. 在最坏的情况下,如果树是一个完全平衡的二叉搜索树,并且查询区间与树中的所有区间都重叠,那么函数的时间复杂度将是O(n),其中n是树中节点的数量。这是因为在这种情况下,函数将递归地访问树中的每个节点,并将其区间添加到结果数组中。

综上所述,整个函数的时间复杂度为O(log n),其中n是树中节点的数量,满足实验要求O(min(n,klogn))。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值