【摘要】 本人看的是《算法》这本书,所以红黑树的理解是一下这样的: 个人认为这样比结点标红黑更好理解。很好下面是红黑树的定义: 1、红黑树其实是2-3结点树的二叉平衡表示形式。 2、红链接均为左连接(左倾红黑树) 3、没有任何结点同时连接着两条红链 4、红黑树是完美平衡的,也就是任何空连接(NULL)到根节点经过的黑色分支数量是相等的 其中2、...
本人看的是《算法》这本书,所以红黑树的理解是一下这样的:
个人认为这样比结点标红黑更好理解。很好下面是红黑树的定义:
1、红黑树其实是2-3结点树的二叉平衡表示形式。
2、红链接均为左连接(左倾红黑树)
3、没有任何结点同时连接着两条红链
4、红黑树是完美平衡的,也就是任何空连接(NULL)到根节点经过的黑色分支数量是相等的
其中2、3都是为了维持是2-3树的二叉平衡形式,4、是为了对树高进行一个很好的限制,因为我们知道二叉搜索树的时间复杂度是由树高决定的,所以如果一棵二叉树越平衡那么搜索的性能就约好。
为什么要引进红黑树?直接2-3树不是更好?
这里我们要知道一个问题,2-3树的插入和删除的分类情况是非常多的,而且插入和删除后为了维持树的绝对平衡性,会带来许多的操作,这样就会对树的运行效率带来极大的挑战,也许此时额外的负担已经超过维持平衡后所带来的收益了。而我们反观红黑树,单从树的角度来看并不是完美平衡的,但是我们有条件4的限制,那么会出现一个有趣的效果,那就是最长的结点高度不会高于任意结点高度的两倍,并且红黑树的插入和删除情况少,维护的代价低。那么我们可以看出下面一个收益:
TotalCost = BalanceCost + SearchCost + InsertCost + DeleteCost。所以我们可以把红黑树看成是一种2-3树的变体(在插入,删除过多的情况下),也就是在某些情况下TotalCost会更加小的特殊情况。
下面是对红黑树的实现:
数据结构:
#define Red true; #define Black false; typedef struct treeNode{	KeyType Key;	ValType val;	struct treeNode *left;	struct treeNode *right;	bool color; }RBTree,*PRBTree;
1、插入:
//插入函数 PRBTree insertKey(PRBTree root,char key,int val) {	//空就生成新结点	if(!root)	{	CreateNode(&root,key,val);	return root;	}	if(root->Key > key)	root->left = insertKey(root->left,key,val);	else if(root->Keyright = insertKey(root->right,key,val);	else	root->val = val;	if(isRed(root->left) && isRed(root->right))	colorFlip(root);	if(isRed(root->left) && isRed(root->left->left))	{	root = rightRotate(root);	colorFlip(root);	}	if(isRed(root->right))	root = leftRotate(root);	return root; }
2、删除函数
//删除任意结点 void deleteNode(PRBTree *root,char key) {	//----------------------------------策略是利用删除最大和最小函数-------------------------------------	PRBTree T;	if(!(*root))	return;	//在左子树	if((*root)->Key > key)	{	if(isRed((*root)->left) || isRed((*root)->left->left));	else if(!isRed((*root)->left) && !isRed((*root)->right)) borrowKeyMin(root);	deleteNode(&(*root)->left,key);	}	else if((*root)->Keyleft)) *root = rightRotate(*root);	else if((*root)->right)	{ if(isRed((*root)->right->left)) (*root)->right = rightRotate((*root)->right); else if(!isRed((*root)->left) && !isRed((*root)->right)) borrowKeyMax(root);	}	deleteNode(&(*root)->right,key);	}	else	{	//存在左子树,那么用左子树的最大值来代替并且删除	if((*root)->left)	{ PRBTree T = DeleteMax(&(*root)->left); (*root)->Key = T->Key; (*root)->val = T->val;	}	//存在右子树,用右子树的最小值代替并且删除	else if((*root)->right)	{ T = DeleteMin(&(*root)->right); (*root)->Key = T->Key; (*root)->val = T->val;	}	//叶子结点,因为前面每一步都是经过变换的,所以可以直接删除	else (*root) = NULL;	}	*root = fixUp(*root); }
3、插入删除的辅助函数
//判断结点的颜色 bool isRed(PRBTree Node); //颜色反转函数 void colorFlip(PRBTree Node); //插入函数 PRBTree insertKey(PRBTree root,char key,int val); //插入函数,需要刷新一下根节点 PRBTree insert(PRBTree root,char key,int val); //生成一个新的结点 void CreateNode(char key,int val); //右旋转 PRBTree rightRotate(PRBTree Node); //左旋转 PRBTree leftRotate(PRBTree Node); //展示红黑树 void Display(PRBTree root); //利用插入函数直接创建一个红黑树 PRBTree CreateRBTree(char *key,int *val,int keySize); //删除最小键 PRBTree deleteMin(PRBTree *root); //删除最小键的直接调用函数,需要重置根 PRBTree DeleteMin(PRBTree *root); //删除最大键 PRBTree deleteMax(PRBTree *root); //删除最大键的直接调用函数,需要重置根 PRBTree DeleteMax(PRBTree *root); //借键的情况Max void borrowKeyMax(PRBTree *Node); //借键的情况Min void borrowKeyMin(PRBTree *Node); //修复红黑树 PRBTree fixUp(PRBTree root); //删除任意结点 void deleteNode(PRBTree *root,char key); //删除任意结点,直接调用函数 PRBTree DeleteNode(PRBTree *root,char key); //查找函数 bool SearchKey(PRBTree root,char key,PRBTree *find);
4、关键的辅助函数的实现:
//颜色反转函数 void colorFlip(PRBTree Node) {	if(isRed(Node))	{	Node->color = Black;	}	else	Node->color = Red;	if(Node->left)	{	if(isRed(Node->left))	{ Node->left->color = Black;	}	else Node->left->color = Red;	}	if(Node->right)	{	if(isRed(Node->right))	{ Node->right->color = Black;	}	else Node->right->color = Red;	} } //右旋转 PRBTree rightRotate(PRBTree Node) {	PRBTree Temp = Node->left;	Node->left = Temp->right;	Temp->right = Node;	Temp->color = Node->color;	Node->color = Red;	return Temp; } //左旋转 PRBTree leftRotate(PRBTree Node) {	PRBTree Temp = Node->right;	Node->right = Temp->left;	Temp->left = Node;	Temp->color = Node->color;	Node->color = Red;	return Temp; }//修复红黑树 PRBTree fixUp(PRBTree root) {	if(!root)	return NULL;	if(isRed(root->right) && !isRed(root->left))	root = leftRotate(root);	if(isRed(root->left) && isRed(root->left->left))	root = rightRotate(root);	if(isRed(root->left) && isRed(root->right))	colorFlip(root);	return root; } //借键的情况 void borrowKeyMin(PRBTree *Node) {	colorFlip(*Node);	if((*Node)->right)	{	if(isRed((*Node)->right->left))	{ (*Node)->right = rightRotate((*Node)->right); (*Node) = leftRotate((*Node)); colorFlip((*Node));	}	} } //借键的情况Max void borrowKeyMax(PRBTree *Node) {	colorFlip(*Node);	if((*Node)->left)	{	if(isRed((*Node)->left->left))	{ (*Node) = rightRotate((*Node)); colorFlip((*Node));	}	} } //删除最小键 PRBTree deleteMin(PRBTree *root) {	//-------------------------------目的是确保需要删除的结点的上一个节点不是2结点,这样就可以直接删除