zoukankan      html  css  js  c++  java
  • 不带父结点的红黑树实现

          因为仅仅看到13.3节,所以临时仅仅实现旋转插入函数。

    思考:假设不带父结点,那么在须要訪问z的父结点时,我们能够借助查找函数从根结点到待查找结点z的路径上必定能找到z的父结点和祖父结点,所以由此可訪问父结点。只是这样的方法使得旋转函数时间添加到O(lgn),而插入函数也对应的添加到O(lgnlgn)。节省了空间上的内存,同一时候添加了执行时间。

    详细代码例如以下:

    #include <iostream>
    using namespace std;
    #define BLACK 0
    #define RED 1
    #define Nil -1
    #define LEN sizeof(struct Tree)
    struct Tree
    {
       struct Tree*left;
       struct Tree*right;
       int key;
       int color;
    };
    struct Tree*root=NULL;
    struct Tree*nil=NULL;
    //非递归版本号的二叉查找树查找函数
    struct Tree*ITERATIVE_TREE_SEARCH(struct Tree*x,int k,struct Tree*&p1,struct Tree*&p2)
    {//
    	while (x!=nil&&k!=x->key)
    	{
    		p1=x;
    		if (k<x->key)
    		{
    			x=x->left;
    		}
    		else x=x->right;
    		if(k!=x->key)//假设没找到了待查找值,那么继续记录其祖父和父结点值。
    		{
                p2=p1;
    			p1=x;
    		}
    	}
    	return x;
    }
    void LEFT_ROTATE(struct Tree*T,struct Tree*x)
    {//左旋转:分三个步骤①②③来叙述旋转代码的。
    	struct Tree*p1=nil,*p2=nil; 
    	struct Tree*y=x->right;//设置y结点。
    	x->right=y->left;//本行代码以及以下的if结构表达的是“y的左孩子成为x的右孩子”。① 
    	ITERATIVE_TREE_SEARCH(root,x->key,p1,p2);
    	if(p1==nil)//本行代码以及以下的if-else结构表达的过程是“y成为该子树新的根”。②
    	{
           root=y;
    	}
    	else if(x==p1->left)
    	{
           p1->left=y;
    	}
    	else p1->right=y;
    	y->left=x;//本行代码以及以下一行都表达了“x成为y的左孩子”。③
    }
    void RIGHT_ROTATE(struct Tree*T,struct Tree*x)
    {//右旋转
    	struct Tree*p1=nil,*p2=nil; 
    	struct Tree*y=x->left;
    	x->left=y->right; 
    	ITERATIVE_TREE_SEARCH(root,x->key,p1,p2);
    	if(p1==nil)
    	{
    		root=y;
    	}
    	else if(x==p1->right)
    	{
    		p1->right=y;
    	}
    	else p1->left=y;
    	y->right=x;
    }
    void RB_INSERT_INSERT_FIXUP(struct Tree*T,struct Tree*z)
    {
       struct Tree*p1=nil,*p2=nil;  
       ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);//p1=z->parent,p2=z->parent->parent
       while (1)
       {
    	   ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);//p1是父结点 p2是祖父结点
    	   if (p1->color!=RED)
    	   {
    		   break;
    	   }
    	   if (p1==p2->left)
    	   {
    		   struct Tree*y=p2->right;//叔结点
    		   if (y->color==RED)//情况一:叔结点为红色
    		   {//给p1,y,p2着色以保持性质5。而且攻克了z的父结点和z都是红色结点问题
    			   p1->color=BLACK;
    			   y->color=BLACK;
    			   p2->color=RED;
    			   z=p2;//把z的祖父结点当成新结点z进入下一次循环
    		   } 
    		   else 
    		   {
    			   if (z==p1->right)//情况二:检查z是否是一个右孩子且叔结点为黑色,前提是p1结点不是叶子结点
    			   {//使用一个左旋让情况2转变为情况3
    				   z=p1;
    				   LEFT_ROTATE(T,z);//因为进入if语句后可知旋转结点不可能是叶子结点,这样就不用推断z是否是叶子结点了。
    			    ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);//p1=z->parent,p2=z->parent->parent
    			   } 
                   p1->color=BLACK;//情况三:是z是一个左孩子且叔结点为黑色,改变z的父和祖父结点颜色并做一次右旋,以保持性质5。
    			   p2->color=RED;
    			   if(p2!=nil) RIGHT_ROTATE(T,p2);//因为p2可能是叶子结点,所以不妨用一个if推断
    		   }
    	   } 
    	   else//以下else分支相似于上面
    	   {
    		   struct Tree*y=p2->left;
    		   if (y->color==RED)
    		   {
    			   p1->color=BLACK;
    			   y->color=BLACK;
    			   p2->color=RED;
    			   z=p2;
    		   } 
    		   else 
    		   {
    			   if (z==p1->left)
    			   {
    				   z=p1;
    				   RIGHT_ROTATE(T,z);
    				   ITERATIVE_TREE_SEARCH(root,z->key,p1,p2);
    			   } 
                   p1->color=BLACK;
    			   p2->color=RED;
    			   if(p2!=nil) LEFT_ROTATE(T,p2);
    		   }
    	   }
       }
       root->color=BLACK;//最后给根结点着为黑色。
    }
    void RB_INSERT(struct Tree*T,struct Tree*z)
    {
    	struct Tree*y=nil;
    	struct Tree*x=root;
    	while (x!=nil)
    	{
    		y=x;
    		if (z->key<x->key)
    		{
    			x=x->left;
    		}
    		else x=x->right;
    	}
    	if (y==nil)
    	{
    		root=z;
    	} 
    	else if(z->key<y->key)
    	{
    		y->left=z;
    	}
    	else y->right=z;
    	z->left=nil;
    	z->right=nil;
    	z->color=RED;
    	RB_INSERT_INSERT_FIXUP(T,z);
    }
    //中序遍历
    void InOderTraverse(struct Tree *p)
    {
        if (p!=nil)
    	{		
    		InOderTraverse(p->left);
    		cout<<p->key<<" "<<p->color<<" "<<endl;
    		InOderTraverse(p->right);
    	}
    }
    void main()
    {
    	nil=new struct Tree[LEN];
    	nil->key=Nil;nil->color=BLACK;
    	root=nil;
    	int i=0;
    	struct Tree*ROOT=new struct Tree[LEN];
    	cin>>ROOT->key;
    	RB_INSERT(nil,ROOT);
    	root=ROOT;
        while (i!=12)
        {
    		struct Tree*z=new struct Tree[LEN];
    		cin>>z->key;
    		RB_INSERT(root,z);
    		i++;
        }
    	InOderTraverse(root);
    }

    
  • 相关阅读:
    oracle中 char,varchar,varchar2的区别
    .net + oracle + win2003部署遇到的问题集合
    Oracle下如何获得随机数,如何保留小数,如何取整数
    Oracle 函数大全(字符串函数,数学函数,日期函数,逻辑运算函数,其他函数)
    Service和广播联合更新UI的例子
    [python] 类常用的内置方法
    android textview 换行 "\r\n"
    java操作excel
    项目指导原则
    SVN与bugzilla整合
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4083401.html
Copyright © 2011-2022 走看看