interval_tree.cpp
/*
区间树(interval tree)是一种对动态集合进行维护的扩张红黑树,因此可在实验二红黑树的基础上进行扩张。
*/
#include <iostream>
#include <deque>
#include <iomanip>
#include <sstream>
#include <time.h>
#include <sys/time.h>
#define SENTINEL -100000 //哨兵,作为nil结点的key,方便树状输出时临界点判断
using namespace std;
#define MAX_TREE_NODE 30000
enum Color{RED=0,BLACK=1}; //定义枚举类型,即红黑树结点颜色类型,0表示红色,1表示黑色
typedef struct Interval //定义一个表示区间范围的结构体
{
int low; //区间的低端点(low endpoint)
int high; //区间的高端点(high endpoint)
}Interval;
typedef struct Node //声明红黑树结点
{
Color color; //红黑树结点的颜色类型,
struct Node *parent; //父节点
struct Node *left; //左孩子
struct Node *right; //右孩子
Interval interval; //区间
int max; //附加信息,记录以该节点为根的子树中所有区间端点的最大值
}Node;
typedef struct RBTree //定义一个红黑树
{
Node *root; //根节点
Node *nil; //哨兵结点,避免讨论结点的边界情况
}RBTree;
//选择显示
void Display()
{
cout<<"************************************************************************\n";
cout<<"**** 请选择您要的红黑树操作!! ****\n";
cout<<"**** I:插入区间 D:区间树当前状态 S:查找区间 E:退出 ****\n";
cout<<"**** Insert Display Search Exit ****\n";
cout<<"************************************************************************\n";
}
//求三个参数中的最大值
int GetMax(int high,int leftMax,int rightMax)
{
int temp=(leftMax>rightMax)?leftMax:rightMax;
return (high>temp)?high:temp;
}
//左旋,结点x原来的右子树y旋转成x的父母
void LeftRotate(RBTree * rbTree,Node *x)
{
if(x->right!=rbTree->nil)
{
Node *y=x->right;
x->right=y->left;
if(y->left!=rbTree->nil)
{
y->left->parent=x;
}
y->parent=x->parent;
if(x->parent==rbTree->nil) //空树,将y设为根
{
rbTree->root=y;
}
else if(x==x->parent->left) //x为左子树,将y放在x父节点的左子树
{
x->parent->left=y;
}
else
{
x->parent->right=y;
}
y->left=x;
x->parent=y;
//以下为区间树与红黑树左旋调整的差异,即要调整结点max的大小,
//且必须先计算x的max,在计算y的max
x->max=GetMax(x->interval.high,x->left->max,x->right->max);
y->max=GetMax(y->interval.high,y->left->max,y->right->max);
}
else
{
cout<<"Error: can't left rotate,because no rigth child!"<<endl;
}
}
//右旋,结点x原来的左子树y旋转成x的父母
void RightRotate(RBTree * rbTree,Node *x)
{
if(x->left!=rbTree->nil)
{
Node *y=x->left;
x->left=y->right;
if(y->right!=rbTree->nil)
{
y->right->parent=x;
}
y->parent=x->parent;
if(x->parent==rbTree->nil)
{
rbTree->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,在计算y的max
x->max=GetMax(x->interval.high,x->left->max,x->right->max);
y->max=GetMax(y->interval.high,y->left->max,y->right->max);
}
else
{
cout<<"Error: can't right rotate,because no left child!"<<endl;
}
}
//插入结点
void RBInsert(RBTree *rbTree,Interval interval)
{
void RBInsertFixUp(RBTree *rbTree,Node *z);
if(rbTree->root==NULL)
{//当根为空时,单独处理,直接插入到根结点中
rbTree->root=new Node;
rbTree->nil=new Node;
rbTree->root->left=rbTree->nil;
rbTree->root->right=rbTree->nil;
rbTree->root->parent=rbTree->nil;
rbTree->root->interval.low=interval.low; //设置区间低端点
rbTree->root->interval.high=interval.high; //设置区间高端点
rbTree->root->max=interval.high; //初始根的max设为自己的high
rbTree->root->color=BLACK; //根节点color设为黑
rbTree->nil->parent=rbTree->root;
rbTree->nil->left=rbTree->root;
rbTree->nil->right=rbTree->root;
rbTree->nil->interval.low=rbTree->nil->interval.high=SENTINEL; //将nil的区间设为哨兵
rbTree->nil->color=BLACK; //nil结color也设为黑
rbTree->root->max=0; //nil节点的max设为0,便于其他节点max的维护
}
else
{//如果树不为空,那么从根节点开始,从上往下查找插入点
Node *y=rbTree->nil; //y用于当前扫描结点x的父节点
Node *x=rbTree->root; //从根节点开始扫描
while(x!=rbTree->nil) //查找插入位置,以低端点为排序键值
{
if(interval.low==x->interval.low && interval.high < x->interval.high)
{
cout<<"键值重复,请输入不同的键值!!"<<endl;
return;
}
y=x;
x=interval.low<x->interval.low ? x->left : x->right;
}
Node *z=new Node; //new一个Node结点空间
z->color=RED; //新插入的color设为红色
z->interval.low=interval.low;
z->interval.high=interval.high;
z->left=z->right=rbTree->nil;
z->max=GetMax(interval.high,z->left->max,z->right->max);
z->parent=y;
if(interval.low<y->interval.low)
y->left=z;
else
y->right=z;
RBInsertFixUp(rbTree,z); //插入后对树进行调整
}
}
//插入后调整树,以维持红黑树的5条性质
void RBInsertFixUp(RBTree *rbTree,Node *z)
{
Node *y; //用于记录z的叔叔结点
while(z->parent->color==RED) //因为插入的结点是红色的,所以只可能违背性质4,即假如父结点也是红色的,要做调整
{
if(z->parent->parent->left==z->parent) //如果要插入的结点z是其父结点的左子树
{
y=z->parent->parent->right; // y设置为z的叔父结点
if(y->color==RED) //case 1: y的颜色为红色
{
z->parent->parent->color=RED;
y->color=BLACK;
z->parent->color=BLACK;
z=z->parent->parent;
}
else
{
if(z==z->parent->right) //case 2: y的颜色为黑色,并且z是z的父母的右结点,则z左旋转
{
z=z->parent;
LeftRotate(rbTree,z);
}
z->parent->parent->color=RED; //case 3: 如果y的颜色为黑色,并且z是z的父母的左结点
z->parent->color=BLACK;
RightRotate(rbTree,z->parent->parent);
}
}
else //与前一种情况对称,要插入的结点z是其父结点的右子树,注释略去
{
y=z->parent->parent->left;
if(y->color==RED)
{
z->parent->parent->color=RED;
y->color=BLACK;
z->parent->color=BLACK;
z=z->parent->parent;
}
else
{
if(z->parent->left==z)
{
z=z->parent;
RightRotate(rbTree,z);
}
z->parent->parent->color=RED;
z->parent->color=BLACK;
LeftRotate(rbTree,z->parent->parent);
}
}
}
rbTree->root->color=BLACK; //最后如果上升为rbTree的根的话,把根的颜色设为黑色
}
//查找与给定区间重叠的区间
Node* IntervalSearch(RBTree * rbTree,Interval interval)
{
Node *x=rbTree->root; //从根开始查找
while(x!=rbTree->nil&&!(interval.low<=x->interval.high&&interval.high>=x->interval.low))
{//若x不等于nil节点且x与interval不重叠,则进行判断
if(x->left!=rbTree->nil&&x->left->max>=interval.low)
x=x->left; //到x的左子树中继续查找
else
x=x->right; //左子树必查不到,到右子树查
}
return x; //x=nil或者x与interval重叠
}
递归在z的左右子树中查找与interval重叠的具有最小低端点的区间
//Node* IntervalSearchMin(RBTree* rbTree,Node* z,Interval interval)
//{
// Node *x = z, *y;
// //先从左子树上找
// if(x->left && x->left->max >= interval.low)
// {
// y = IntervalSearchMin(rbTree,x->left, interval);
// if(y != rbTree->nil)
// return y;
// }
// //如果x与i相交,就不需要找左子树了
// if(interval.low<=x->interval.high&&interval.high>=x->interval.low)
// return x;
// //最后在右子树上找
// if(x->right)
// return IntervalSearchMin(rbTree,x->right, interval);
// //如果找不到,返回nil
// return rbTree->nil;
//}
//求树高
//int MaxHeight(Node * root,Node *nil)
//{
// if(root==nil)return 0;
// int leftHeight=MaxHeight(root->left,nil);
// int rightHeight=MaxHeight(root->right,nil);
// return (leftHeight>rightHeight)?leftHeight+1:rightHeight+1;
//}
// convert an integer value to string
//string IntToString(int val)
//{
// ostringstream ss;
// ss << val;
// return ss.str();
//}
// Print the arm branches (eg, / \ ) on a line
//void PrintBranches(int branchLen, int nodeSpaceLen, int startLen, int nodesInThisLevel, const deque<Node*>& nodesQueue)
//{
// deque<Node*>::const_iterator iter = nodesQueue.begin();
// for (int i = 0; i < nodesInThisLevel / 2; i++)
// {
// cout << ((i == 0) ? setw(startLen-1) : setw(nodeSpaceLen-2)) << "" << ((*iter&&(*iter)->interval.low!=SENTINEL) ? "/" : " ");
// *iter++;
// cout << setw(2*(branchLen+1)+7) << "" << ((*iter&&(*iter)->interval.low!=SENTINEL) ? "\\" : " ");
// //setw(2*branchLen+4)改为setw(2*branchLen+5)
// *iter++;
// }
// cout << endl;
//}
Print the branches and node (eg, ___10___ )
//void PrintNodes(int branchLen, int nodeSpaceLen, int startLen, int nodesInThisLevel, const deque<Node*>& nodesQueue)
//{
// deque<Node*>::const_iterator iter = nodesQueue.begin();
// for (int i = 0; i < nodesInThisLevel; i++, iter++)
// {
// cout << ((i == 0) ? setw(startLen) : setw(nodeSpaceLen)) << "" << ((*iter && (*iter)->interval.low!=SENTINEL && (*iter)->left->interval.low!=SENTINEL ) ? setfill('_') : setfill(' '));
// if(*iter&&(*iter)->interval.low!=SENTINEL)
// {
// cout<<setw(branchLen+2)<<"["<<IntToString((*iter)->interval.low)<<","<<IntToString((*iter)->interval.high)<<"]";
// //cout<<(((*iter)->color==RED) ? "红":"黑");
// }
// else
// {
// cout << setw(branchLen+1)<<"";
// //cout << setw(branchLen+2)<<"";
// }
// cout << ((*iter && (*iter)->interval.low!=SENTINEL && (*iter)->right->interval.low!=SENTINEL ) ? setfill('_') : setfill(' ')) << setw(branchLen+1) << "" << setfill(' ');
// //setw(branchLen)改为setw(branchLen+1)
// }
// cout << endl;
//}
//
在控制台树形输出红黑树
//void PrintPretty(RBTree * tree, int level, int indentSpace)
//{
// int h = MaxHeight(tree->root,tree->nil);
// int nodesInThisLevel = 1;
//
// int branchLen = 2*((int)pow(2.0,h)-1) - (3-level)*(int)pow(2.0,h-1);
// int nodeSpaceLen = 5 + (level+1)*(int)pow(2.0,h);
// int startLen = branchLen + (3-level) + indentSpace;
//
// deque<Node*> nodesQueue;
// nodesQueue.push_back(tree->root);
// for (int r = 1; r <= h; r++) {
// PrintBranches(branchLen, nodeSpaceLen, startLen, nodesInThisLevel, nodesQueue);
// branchLen = branchLen/2 - 1;
// nodeSpaceLen = nodeSpaceLen/2 + 1;
// startLen = branchLen + (3-level) + indentSpace;
// PrintNodes(branchLen, nodeSpaceLen, startLen, nodesInThisLevel, nodesQueue);
//
// for (int i = 0; i < nodesInThisLevel; i++) {
// Node *currNode = nodesQueue.front();
// nodesQueue.pop_front();
// if (currNode&&currNode!=tree->nil) {
// nodesQueue.push_back(currNode->left);
// nodesQueue.push_back(currNode->right);
// } else {
// nodesQueue.push_back(NULL);
// nodesQueue.push_back(NULL);
// }
// }
// nodesInThisLevel *= 2;
// }
//}
int main()
{
struct timeval tv;
RBTree tree;
tree.root=tree.nil=NULL;
//char choose;
Interval interval[MAX_TREE_NODE];
time_t t;
int A[MAX_TREE_NODE],i,temp;
srand((unsigned)time(&t));
for(i = 0;i < MAX_TREE_NODE;i++)
{
A[i] = rand() % 20;
}
for(i=0;i<MAX_TREE_NODE;i++)
{
interval[i].low = A[i];
interval[i].high = A[i]+5;
}
gettimeofday(&tv, NULL);
printf("%d\t%d\n", tv.tv_usec, tv.tv_sec);
for(i=0;i<MAX_TREE_NODE;i++)
{
RBInsert(&tree,interval[i]);
}
temp=rand()%20;
printf("search:[%d,%d]\n",temp,temp);
Interval tmp;
tmp.high = temp;
tmp.low = temp;
gettimeofday(&tv, NULL);
printf("%d\t%d\n", tv.tv_usec, tv.tv_sec);
Node* x = IntervalSearch(&tree,tmp);
if(x!=tree.nil)
printf("OK:x=[%d,%d]\n",x->interval.low,x->interval.high);
else printf("NOK\n");
gettimeofday(&tv, NULL);
printf("%d\t%d\n", tv.tv_usec, tv.tv_sec);
#if 0
while(true)
{
Display();
cin>>choose;
switch(choose)
{
case 'E':exit(0);break; //选择0则跳出系统
case 'I':
{//选择1则插入结点
cout<<"请输入区间的左右两个端点,中间以空格隔开:";
cin>>interval.low>>interval.high;
RBInsert(&tree,interval);
cout<<endl;
break;
}
//case 'D':
// {//选择2则在控制台以树的形式显示红黑树
// cout<<endl<<"此时红黑树状态如下:"<<endl;
// PrintPretty(&tree,2,3);
// cout<<endl;
// break;
// }
case 'S':
{//显示查找重叠区间的结果
cout<<"请输入待查找的区间:";
cin>>interval.low>>interval.high;
Node* x=IntervalSearch(&tree,interval);
if(x!=tree.nil)
{
//Node* min_x=IntervalSearchMin(&tree,tree.root,interval);
cout<<"Output:最先找到的重叠区间为:"<<"["<<x->interval.low<<","<<x->interval.high<<"]"<<endl;
//cout<<" 具有最小低端点的重叠区间为:"<<"["<<min_x->interval.low<<","<<min_x->interval.high<<"]"<<endl<<endl;
}
else
cout<<"Output:无重叠区间!"<<endl<<endl;
}
}
}
#endif
return 0;
}
[root@gnos-x64-dev ~]# g++ -g interval_tree.cpp -o interval_tree
[root@gnos-x64-dev ~]# ./interval_tree
813816 1475997819
search:[12,12]
824964 1475997819
OK:x=[11,16]
824967 1475997819
[root@gnos-x64-dev ~]# expr 824964 - 813816
11148
[root@gnos-x64-dev ~]# expr 824967 - 824964
3
[root@gnos-x64-dev ~]#
插入时间11148us
查找时间3us
[root@gnos-x64-dev ~]# g++ -pg interval_tree.cpp -o interval_tree
[root@gnos-x64-dev ~]# gprof interval_tree gmon.out -p
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ns/call ns/call name
100.32 0.01 0.01 30000 334.41 334.41 RBInsert(RBTree*, Interval)
0.00 0.01 0.00 95479 0.00 0.00 GetMax(int, int, int)
0.00 0.01 0.00 29999 0.00 0.00 RBInsertFixUp(RBTree*, Node*)
0.00 0.01 0.00 29652 0.00 0.00 LeftRotate(RBTree*, Node*)
0.00 0.01 0.00 3088 0.00 0.00 RightRotate(RBTree*, Node*)
0.00 0.01 0.00 1 0.00 0.00 global constructors keyed to _Z7Displayv
0.00 0.01 0.00 1 0.00 0.00 IntervalSearch(RBTree*, Interval)
0.00 0.01 0.00 1 0.00 0.00 __static_initialization_and_destruction_0(int, int)
% the percentage of the total running time of the
time program used by this function.
cumulative a running sum of the number of seconds accounted
seconds for by this function and those listed above it.
self the number of seconds accounted for by this
seconds function alone. This is the major sort for this
listing.
calls the number of times this function was invoked, if
this function is profiled, else blank.
self the average number of milliseconds spent in this
ms/call function per call, if this function is profiled,
else blank.
total the average number of milliseconds spent in this
ms/call function and its descendents per call, if this
function is profiled, else blank.
name the name of the function. This is the minor sort
for this listing. The index shows the location of
the function in the gprof listing. If the index is
in parenthesis it shows where it would appear in
the gprof listing if it were to be printed.
http://hujw0710.blog.163.com/blog/static/8797282200952324755785/