码迷,mamicode.com
首页 > 编程语言 > 详细

从二叉排序树到平衡二叉树再到红黑树系列1

时间:2015-05-13 22:00:17      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:二叉查找树   二叉排序树   节点删除   插入   

最近想写一些关于红黑树的博客,既想写的全面,又直观,但是又不知道从哪里入手。斟酌再三,还是从最简单的二叉排序树开始写。

二叉排序树(Binary Sort Tree)又叫二叉查找树。它是一种特殊结构的二叉树。其或为空树,或具备下列性质:

(1)若它的左子树不为空,则左子树上所有结点的值均小于它的根节点的值。

(2)若它的右子树不为空,则左子树上所有结点的值均大于它的根节点的值。

显然,它的中序遍历就是一个递增的有序序列。

定理:在一棵高度为h的二叉搜索树上,动态集合上的操作serach,minmum,maxmum,successor,predecessor可以在O(h)时间内完成。

即查找给定结点,查找最大值最小值,以及给定结点的前驱后继,他们均可以在O(h)时间内完成。具体见算法导论第三版第12章


插入和删除

为了保持二叉排序树的有序性质,插入和删除操作会引起二叉排序树的动态变化,由于插入的结点总是成为叶子节点,而删除的结点还要修改其左右子树的指向,所以插入一个结点相比删除一个结点的处理相对复杂。


插入:首先要查找要插入节点的位置,然后插入即可。

删除:删除一个结点node要考虑三种情况:

1 node没有左右孩子节点,这种情况最为简单,直接删除它,再将父节点原来指向node的指针置NULL就行。

2 node只有一个孩子,那么将这个孩子提升到node的位置上,并修改node的父节点即可。

3 node有两个孩子。那么寻找node的后继y(中序遍历的下一个元素),让y占据node的位置。同时node原来的右子树部分称为y的新的右子树,

node的左子树称为y的新的左子树。简单点说:就是交换要删除的node节点与node节点右子树的最左边节点位置。这样满足中序遍历递增性质。

  时刻记住二叉排序树中序是递增的,当删除一个结点时,该结点的位置就要被其后继,也就是要删除节点右子树的中序遍历第一个节点(同时也是右子树的最左节点)

下面举例说明,如图所示:

技术分享

技术分享

下面直接贴代码:

#include<stdio.h>
#include<stdlib.h>
#define error -1
#define OK 1
typedef struct BSTNode
{
	struct BSTNode *lchild,*rchild;
	int data;
}BSTNode,*BSTree;
/**
*@auther:jungege 2015 5.13
**/
//插入元素到二叉排序树中
BSTree InsertBST(BSTree bst,int key)
{
	BSTree node,parent,new_node;
	if(bst == NULL)//为空树,创建根节点
	{
		bst = (BSTree)malloc(sizeof(BSTNode));
		bst->data = key;
		bst->lchild = NULL;
		bst->rchild = NULL;
		return bst;
	}

	node = bst;//找到插入位置,保存bst
	while(node != NULL)
	{
		if(node->data == key)
			return bst;
		else
		{
			parent = node;//记录父节点,最后保存的是插入节点的父节点
			if(node->data < key)
				node = node->rchild;
			else
				node = node->lchild;
		}
	}
	//创建节点,将新key插入到指定位置,插入的节点一定是叶子节点
	new_node = (BSTree) malloc (sizeof(BSTNode));
	if(parent->data < key)//插入到parent右孩子
		parent->rchild = new_node;
	else
		parent->lchild = new_node;
	new_node->data = key;
	new_node->lchild = NULL;
	new_node->rchild = NULL;

	return bst;
}
//删除二叉排序树中元素
int deleteBST(BSTree bst, int key)
{
	BSTree node=bst,pre=NULL,nearestkey,nearest_pre;
	
	if(bst == NULL)
		return -1;//空树
	
	//寻找删除节点位置
	while(node != NULL && node->data != key)
	{
		pre = node;//保存父结点
		if(node->data > key)
			node = node->lchild;
		else
			node = node->rchild;
	}
	if(node == NULL)
		return 0;//没有要删除的节点
	
	//找到要删除的节点node和其父节点pre
	if((node->lchild != NULL) && (node->rchild !=NULL))//***要删除节点有左右孩子
	{
		nearestkey = node->rchild;
		nearest_pre = node;
		while(nearestkey->lchild != NULL)
		{
			nearest_pre = nearestkey;//pre指向被nearestkey节点的父节点
			nearestkey = nearestkey->lchild;
		}
		node->data = nearestkey->data;//直接赋值,避免交换节点
		//处理nearestkey节点的子节点,显然其为最左节点,所以不存在左子树,只需处理其右子树
		nearest_pre->lchild = nearestkey->rchild;
		free(nearestkey);
	}
	else if(node->lchild == NULL && node->rchild !=NULL)//***要删除节点只有右孩子
	{
		if(pre->rchild == node)// node是其父节点的右子树
			pre->rchild = node->rchild;
		else 
			pre->lchild = node->rchild;
		free(node);//释放节点
	}
	else if(node->lchild != NULL && node->rchild ==NULL)//***要删除节点只有左孩子
	{
		if(pre->rchild == node)// node是其父节点的右子树
			pre->rchild = node->lchild;
		else 
			pre->lchild = node->lchild;
		free(node);//释放节点
	}
	else//***被删除节点没有子树
	{
		if(pre->lchild == node)
			pre->lchild = NULL;
		if(pre->rchild == node)
			pre->rchild = NULL;
		free(node);
	}
	return 1;//删除成功
}

//查找
int SearchBST(BSTree bst,int key)
{
	printf("%d ",bst->data);
	if(bst==NULL)
		return error;
	if(bst->data == key)
		return OK;
	else if(key < bst->data)
		SearchBST(bst->lchild,key);
	else
		SearchBST(bst->rchild,key);
}

//中序遍历
void inorder(BSTree root)
{
	if(root)
	{
		inorder(root->lchild);
		printf("%d ",root->data);
		inorder(root->rchild);
	}
}


void main()
{

	int a[10]={3,2,6,5,1,9,7,7,10,8};
	int i;
	BSTree root=NULL;//初始化非常重要,不然插入时就无法判断树空
	//按数组构建二叉排序树
	for(i=0;i<10;i++)
		root = InsertBST(root,a[i]);
	//中序遍历
	inorder(root);
	printf("\n删除节点6:");
	deleteBST(root,6);
	printf("\n删除节点6后中序遍历:");
	inorder(root);
	printf("\n");
}


运行结果如下:

技术分享


从二叉排序树到平衡二叉树再到红黑树系列1

标签:二叉查找树   二叉排序树   节点删除   插入   

原文地址:http://blog.csdn.net/u010498696/article/details/45695377

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!