算法导论 第十四章:区间树

区间树是一种对动态集合进行维护的红黑树,具体设计如下:

step1:基础数据结构

我们选择的基础数据结构式红黑树,其中每个节点x包含一个区间域x.int,x的关键字为区间的低端点 x.int.low.

step2:附加信息

每个节点x除了区间信息外,还包含一个值x.max,即以x为根的的子树中所有区间的断点的最大值

step3:对信息维护

必须验证对含有n个节点的区间树的插入和删除都能在O(lgn)时间内完成,给定区间x.int 和 x.max 则有:x.max = max(x.int.high,x.left.max,x.right.max)

step4:设计新的操作

我们唯一需要的新操作是INTERVAL-SEARCH(T,i),用以找出树T中覆盖区间i的那个节点。伪代码如下:

运行时间:O(lgn).

构建的区间树可以表示成如下:

完整代码如下:

#include<iostream>
#include<iomanip>
using namespace std;
#define BLACK 0
#define RED 1

typedef struct interval{
	int low;
	int high;
	}interval;

typedef struct IntervalTNode{
	int key;
	bool color;
	IntervalTNode *parent;
	IntervalTNode *left;
	IntervalTNode *right;

	interval inte;  //additional information
	int max;        //additional information

	}IntervalTNode;

typedef struct IntervalTree{
	IntervalTNode *root;
	}IntervalTree;

//init sentine NIL
interval interval0={-1,-1};
IntervalTNode NILL={-1,BLACK,NULL,NULL,NULL,interval0,-1};
IntervalTNode *NIL=&NILL;          

/*-----------------------------------------------------------------------*/
int Max(int a,int b,int c)
{
	if(a>b)
		return a>c ? a:c;
	else
		return b>c ? b:c;
	}
bool Overlap(interval a,interval b)
{
	if(a.high < b.low || a.low > b.high)     // a & b do not overlap
		return 0;
	return 1;
	}
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;
}
/*-----------------------------------------------------------------------*/

void IntervalT_InorderWalk(IntervalTNode *x)
{
	if(x!=NIL)
 	 {
		IntervalT_InorderWalk(x->left);
		cout<<"["<<setw(3)<<x->inte.low<<setw(3)<<x->inte.high<<"  ]";
		if(x->color==1)
			cout<<"     Red       "<<x->max<<endl;
		else
			cout<<"     Black     "<<x->max<<endl;

		IntervalT_InorderWalk(x->right);
 		} 

	}

IntervalTNode *IntervalT_Minimum(IntervalTNode *x)
{
	while(x->left != NIL)
		x=x->left;
	return 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;    //set y

	x->right=y->left;       //turn y's left subtree into x's right subtree
	if(y->left!=NIL)
		y->left->parent=x;

	y->parent=x->parent;     //link x's parent to y;
	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;               //put x on y's left
	x->parent=y;

	//maitaining additional information
	y->max=x->max;
	x->max=Max(x->inte.high,x->left->max,x->right->max);
	}

void Right_Rotate(IntervalTree *T,IntervalTNode *x)
{
	IntervalTNode *y=x->left;      //set y

	x->left=y->right;   //link x's left tree into y's right subtree;
	if(y->right !=NIL)
		y->right->parent=x;

	y->parent=x->parent;    //link x's parent to y
	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;         //put x on y's right
	x->parent=y;

	//Maintaining additional information
	y->max=x->max;
	x->max=Max(x->inte.high,x->left->max,x->right->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)
			{
				z->parent->color=BLACK;            //case 1
				y->color=BLACK;                    //case 1
				z->parent->parent->color=RED;      //case 1
				z=z->parent->parent;               //case 1
				}
			else
			{
			   	if(z==z->parent->right)
				{
					z=z->parent;                    //case 2
					Left_Rotate(T,z);               //case 2
				 	}
				z->parent->color=BLACK;             //case 3
				z->parent->parent->color=RED;       //case 3
				Right_Rotate(T,z->parent->parent);  //case 3
		 		}
		 	}
		else
		{//a me as then clause with "right" and "left" exchanged
			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;      //turn the root to BLACK
	}
void IntervalT_Insert(IntervalTree *T,interval inte)
{
	IntervalTNode *z=new IntervalTNode();
	z->key=inte.low;
	z->max=inte.high;
	z->inte=inte;
	z->color =RED;
	z->parent=NIL;
	z->left=NIL;
	z->right=NIL;

	IntervalTNode *y=NIL;        //y is the parent of x
	IntervalTNode *x=T->root;
	while(x != NIL)
	{
		x->max=max(x->max,z->max);     //Maintaining the max value of each node from z up to root
		y=x;
		if(z->key < x->key)
			x=x->left;
		else
			x=x->right;
		}
	z->parent=y;   //link new node's parent node to y(y's child is NIL)
	if(y==NIL)
		T->root=z;
	else if(z->key < y->key)
		y->left=z;
	else
		y->right =z;
	IntervalT_InsertFixup(T,z);
	}

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;  //set w to x's sibling
			if(w->color==RED)      //case 1:x's sibling w is 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)
			{ //case 2:x's sibling w is black and both of w's children are black
				w->color=RED;
				x=x->parent;
				}
			else
			{
				if(w->right->color==BLACK)
				{//case 3:x's sibling w is black,w's left child is red, and w's right child is black
					w->left->color=BLACK;
					w->color=RED;
					Right_Rotate(T,w);
					w=x->parent->right;
			 		}
				w->color=x->parent->color;      //case 4: x's sibling w is black,and w's right child is red
				x->parent->color=BLACK;         //.
				w->right->color=BLACK;         // .
				Left_Rotate(T,x->parent);      // .
				x=T->root;                     //case 4
				}
			}
		else
		{//Same as then clause with "right" and "left" exchanged
			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;
	}
void IntervalT_Delete(IntervalTree *T,IntervalTNode *z)
{
	IntervalTNode *x=NULL,*y=NULL,*g=NULL;

	if(z->left == NIL || z->right==NIL)
		y=z;
	else
		y=IntervalT_Successor(z);

	//maintaining additional information
	g=y->parent;
	g->max=g->inte.high;
	g=g->parent;
	while(g->max==y->max)
	{
		g->max=Max(g->max,g->left->max,g->right->max);
		g=g->parent;
		}
	//delete y node
	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;

	if(y->color==BLACK)
		IntervalT_DeleteFixup(T,x);
	}

int main()
{
	interval A[]={{16,21},{8,9},{25,30},{5,8},{15,23},{17,19},{26,26},{0,3},{6,10},{19,20}};
	int n=sizeof(A)/sizeof(interval);

	cout<<"/*---------------------Create Interval Tree-------------------*/"<<endl;
	IntervalTree *T=new IntervalTree();
	T->root=NIL;
	for(int i=0;i<n;i++)
		IntervalT_Insert(T,A[i]);
	cout<<"The interval tree is:"<<endl;
	IntervalT_InorderWalk(T->root);
	cout<<"The root of the tree is:"<<T->root->inte.low<<"   "<<T->root->inte.high<<endl;
	cout<<"/*-------------------------------------------------------------*/"<<endl;

	cout<<"/*--------------------Searching Interval Tree------------------*/"<<endl;
	interval sInt;
	cout<<"Please input the searching interval:";
	cin>>sInt.low>>sInt.high;
	IntervalTNode *sITNode=NIL;
	sITNode=IntervalT_Search(T,sInt);
	if(sITNode==NIL)
		cout<<"The searching interval doesn't exist in the tree."<<endl;
	else{
		cout<<"The overlap interval is:"<<endl;
		cout<<"["<<sITNode->inte.low<<"  "<<sITNode->inte.high<<"]";
		if(sITNode->color==0)
			cout<<"   color:RED     ";
		else
			cout<<"   color:BLACK   ";
		cout<<"Max:"<<sITNode->max<<endl;
		}
	cout<<"/*------------------Deleting INterval Tree--------------------*/"<<endl;
	interval dInt;
	cout<<"Please input the deleting interval:";
	cin>>dInt.low>>dInt.high;
	IntervalTNode  *dITNode=NIL;
	dITNode=IntervalT_Search(T,dInt);
	if(dITNode==NIL)
		cout<<"The deleting interval doesn't exist in the tree."<<endl;
	else
	{
		IntervalT_Delete(T,dITNode);
		cout<<"After deleting ,the interval tree is:"<<endl;
		IntervalT_InorderWalk(T->root);
		cout<<"The root of the tree is:"<<T->root->inte.low<<"   "<<T->root->inte.high<<endl;
		}
	cout<<"/*------------------------------------------------------------*/"<<endl;

	return 0;
	}

运行结果:

【注:若有错误,请指正~~~】

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-03 23:57:07

算法导论 第十四章:区间树的相关文章

算法导论 第十四章:数据结构的扩张

对一种数据结构的扩张过程可分为四步骤: 1)选择基础数据结构 2)确定要在基础数据结构中添加哪些信息 3)验证可用基础数据结构上的基本修改操作来维护这些新添加的信息 4)设计新的操作 动态顺序统计 动态顺序统计在红黑树的基础上添加x.size域,满足:x.size = x.left.size+x.right.size+1,扩张的结构如下: 操作: 1)检索具有给定秩的元素 下面伪代码返回一个指向以x为根的子树中包含第i小关键字的节点指针 2)确定元素的秩 伪代码如下: 3)插入 插入操作会破坏红

算法导论第十二章__二叉搜索数

package I第12章__二叉搜索树; //普通二叉树 public class BinaryTree<T> { // -----------------------数据结构--------------------------------- private int height = 0; private Node<T> rootNode; class Node<T> { T t; int key; Node left; Node right; public Node

算法导论第十五章动态规划

概述: 1.动态规划是通过组合子问题的解而解决原问题的. 2.动态规划适用于子问题不是独立的情况,也就是各子问题的包含公共的子子问题. 3.动态规划对每个子问题只求解一次,将其结果保存在一张表中. 4.动态规划的设计步骤:a.描述最优解的结构b.递归定义最优解的值c.按自底向上的方式计算最优觖的值d.由计算出的结构构造一个最优解 15.1钢条切割 钢条切割问题:给定定长的钢条和价格表,求切割方案,使得收益最大.如果n英寸的钢条的价格足够大,则不需要切割. 代码如下: //朴素递归求解钢条切割收益

算法导论第十二章 二叉搜索树

一.二叉搜索树概览 二叉搜索树(又名二叉查找树.二叉排序树)是一种可提供良好搜寻效率的树形结构,支持动态集合操作,所谓动态集合操作,就是Search.Maximum.Minimum.Insert.Delete等操作,二叉搜索树可以保证这些操作在对数时间内完成.当然,在最坏情况下,即所有节点形成一种链式树结构,则需要O(n)时间.这就说明,针对这些动态集合操作,二叉搜索树还有改进的空间,即确保最坏情况下所有操作在对数时间内完成.这样的改进结构有AVL(Adelson-Velskii-Landis)

算法导论--动态顺序统计与区间树

本文的基础是红黑树 算法导论–红黑树 通过在基础的数据结构中添加一些附加信息,来扩张一种标准的数据结构,然后编写新的操作来支持所需要的应用.下面是介绍在红黑树的基础上扩张的数据结构. 1.动态顺序统计 动态顺序统计可以在O(lgn)时间内确定任何的顺序统计量(即在n个元素的集合中,能在O(lgn)的时间内确定第i小的元素),同时也可以在O(lgn)的时间内计算一个元素的秩(即它在中序遍历下的位置顺序). 1 添加附加信息 结点x中加入x.size , size的大小为以x为根的子树(包含x本身)

算法导论第十九章 斐波那契堆

<算法导论>第二版中在讨论斐波那契堆之前还讨论了二项堆,但是第三版中已经把这块的内容放到思考题中,究极原因我想大概是二项堆只是个引子,目的是为了引出斐波那契堆,便于理解,而且许多经典的算法实现都是基于斐波那契堆,譬如计算最小生成树问题和寻找单源最短路径问题等,此时再把二项堆单独作为一章来讲显然没有必要.类似的堆结构还有很多,如左倾堆,斜堆,二项堆等,下次我打算开一篇博客来记录下它们的异同点. 一.摊还分析(第十七章) 这些高级的数据结构的性能分析一般是基于一个技术——摊还分析,可以理解成一种时

算法导论 第二十二章:图的搜索

图有两种标准的表示方法,即邻接矩阵和邻接表(通常邻接矩阵用于稠密图,邻接表用于稀疏图).如下: 对于图的搜索有两种方法:深度优先搜索 & 广度优先搜索. 广度优先搜索(Breadth-first search) 广度优先搜索是将已发现和未发现顶点之间的边界沿其广度方向向外扩展.亦即算法首先会发现和s距离为k的所有点,然后才会发现和s距离为k+1的其他顶点. 伪代码: EG: 运行时间:O(V+E). 深度优先遍历(Depth-first search) 在深度优先搜索中,对于最新发现的顶点,如果

算法导论 第十九章:斐波拉契堆

斐波拉契堆是由一组最小堆有序树组成,每棵树遵循最小堆性质,并且每棵树都是有根而无序的.所有树的根通过left和right指针来形成一个环形的双链表,称为该堆的根表. 对于一个给定的斐波拉契堆H ,可以通过指向包含最小关键字的树根指针H.min来访问.堆中每个节点还包含x.mark,x.degree两个域,x.degree表示x的子女表中的子女个数:x.mark表示从x上次成为另一个节点子女以来是否失掉一个孩子. 斐波拉契对的结构如下: 势能函数: 可以利用势能方法来分析斐波拉契堆的性能.其势能函

算法导论 第十二章:二叉查找树(Binary Search Trees)

二叉查找树具有如下性质: x是二叉查找树中的一个节点,如果y是x左子树中的一个节点,则y.key ≤ x.key ; 如果 y 是 x 右子树中的一个节点,则 x.key ≥ y.key. 在二叉树上执行的基本操作的时间与树的高度成正比.当这棵树是完全二叉树时,这些操作的最坏情况运行时间为Θ(lgn);如果该树是含n个节点的线性链,则这些操作的最坏情况的运行时间为Θ(n).我们可以通过随机构造二叉查找树(期望高度:E(h)=O(lgn)),从而使得在这种树上基本动态集操作的平均时间为Θ(lgn)