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

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

二叉排序树(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");
}

运行结果如下:

时间: 2024-10-10 21:36:41

从二叉排序树到平衡二叉树再到红黑树系列1的相关文章

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

这篇博客主要讲解B树及其插入删除操作,并给出操作的流程图以达到清晰易懂的目的,尽管标题是从二叉排序树到平衡二叉树再到红黑树系列3,没有B树二字,但他们都是动态查找树,所以我将他们归为一个系列. B树是为磁盘或其他直接存取的辅助存储设备而设计的一种平衡搜索树.它以一种很自然的方式推广了二叉搜索树,B树与红黑树的不同之处在于B树结点的孩子不限于最多为2,而是可以有数个到数千个不定.因为结点的分支更多,因而相比红黑树,高度更小. B树的定义有如下两种,但殊途同归. 定义形式一(以度 t 定义): 一棵

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

上篇博客主要讲述了二叉排序树的基本概念和插入删除操作,必须再次说明的是:在一棵高度为h的二叉排序树上,实现动态集合操作查询,插入和删除的运行时间均为O(h). 可见二叉树的基本操作效率取决于树的形态,当然树的高度越低越好,显然树分布越均匀,高度越低.那么,问题来了?对于给定的关键字序列,如何构造一棵形态匀称的二叉排序树.这种匀称的二叉排序树就称为平衡二叉树. 平衡二叉树定义:平衡二叉树或为空树,或其上任意一个节点,节点的左右子树高度差不超过1.     通常将二叉树上所有结点的左右子树的高度之差

数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)

树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: BST树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中: 如果BST树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么B树 的搜索性能逼近二分查找:但它比连续内存空间的二分查找的优点是,改变BST树结构 插入与删除结点)不需要移动大段的内存数据,甚至通常是常数开销: 如:

从二叉树到2-3-4树再到红黑树

直接进入正题: 一.如何从数组生成一个二叉树 假设数组为:{ 30, 13, 7, 43, 23, 12, 9, 33, 42, 21, 18, 6, 3, 50 },我们不对数组排序,直接生成二叉树. 创建流程: 1.将第一数作为根节点: 2.插入13,13小于30,放在30的左边子节点. 3.插入7,7小于30,7小于13,放在13的左边子节点. 4.插入43,43大于30,放在30的右边子节点. 5.放入23,23小于30,23大于13,放入13的右边子节点. 6.放入12,12小于30,

再论红黑树

红黑树: 红黑树(Red Black Tree) 是一种自平衡二叉查找树 : l 每个节点或者是黑色,或者是红色. l 根节点是黑色. l 每个叶子节点是黑色. l 如果一个节点是红色的,则它的子节点必须是黑色的. l 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点. 红黑树的各种操作的时间复杂度是O(log2N). 红黑树 vs AVL 红黑树的查询性能略微逊色于AVL树,因为他比avl树会稍微不平衡最多一层,也就是说红黑树的查询性能只比相同内容的avl树最多多一次比较,但是,红

为什么要有红黑树?什么是红黑树?画了20张图,看完这篇你就明白了

为什么要有红黑树 想必大家对二叉树搜索树都不陌生,首先看一下二叉搜索树的定义: 二叉搜索树(Binary Search Tree),或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉排序树. 从理论上来说,二叉搜索树的查询.插入和删除一个节点的时间复杂度均为O(log(n)),已经完全可以满足我们的要求了,那么为什么还要有红黑树呢? 我们来看一个例

红黑树之添加节点和创建

红黑树之插入节点 红黑树的性质 红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色.在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求: 节点是红色或黑色. 根节点是黑色. 每个叶节点(这里的叶节点是指NULL节点,在<算法导论>中这个节点叫哨兵节点,除了颜色属性外,其他属性值都为任意.为了和以前的叶子节点做区分,原来的叶子节点还叫叶子节点,这个节点就叫他NULL节点吧)是黑色的. 每个红色节点的两个子节点都是黑色.(从每个叶子到根的所有路径上不能有两个连续的

为什么红黑树的效率比较高

红黑树属于平衡二叉树.它不严格是因为它不是严格控制左.右子树高度或节点数之差小于等于1,但红黑树高度依然是平均log(n),且最坏情况高度不会超过2log(n). 红黑树(red-black tree) 是一棵满足下述性质的二叉查找树: 1. 每一个结点要么是红色,要么是黑色. 2. 根结点是黑色的. 3. 所有叶子结点都是黑色的(实际上都是Null指针,下图用NIL表示).叶子结点不包含任何关键字信息,所有查询关键字都在非终结点上. 4. 每个红色结点的两个子节点必须是黑色的.换句话说:从每个

数据结构系列(5)之 红黑树

本文将主要讲述平衡二叉树中的红黑树,红黑树是一种我们经常使用的树,相较于 AVL 树他无论是增加还是删除节点,其结构的变化都能控制在常树次:在 JDK 中的 TreeMap 同样也是使用红黑树实现的: 一.结构概述 红黑树是在AVL 树平衡条件的基础上,进一步放宽条件,从而使得红黑树在动态变化的时候,其结构的变化在常数次:其标准大致可以表示为: 任一节点左.右子树的高度,相差不得超过两倍. 同他的名字,红黑树的节点是有颜色的,如图所示: 其性质如下: 树根始终为黑色 外部节点均为黑色(图中的 l