二叉搜索树及其实现与应用

首先什么是二叉搜索树?

二叉搜索树又称为二叉排序树,它是一个空树或者具有以下性质:
1)若它的左子树不空,则左子树上的所有节点的值都小于根节点的值
2) 若它的右子树不空,则右子树上的所有节点的值都大于根节点的值
3)它的左右子树也分别为二叉搜索树
由二叉树的定义可以看出它是递归定义的,下面是一些二叉树的基本操作的递归实现
typedef int DataType;
typedef struct BSTreeNode
{
	struct BSTreeNode *pLeft;
	struct BSTreeNode *pRight;
	DataType _data;
}BSTreeNode;

//插入结点递归
void InsertBSTree(BSTreeNode **pRoot, DataType data)
{
	assert(pRoot);
	if (NULL == *pRoot)
		*pRoot = BuyBSTNode(data);
	else
	{
		//若根节点的值大于插入结点的值,就插入到左子树中
		if ((*pRoot)->_data > data)
			InsertBSTree(&(*pRoot)->pLeft, data);

		//若根节点的值小于插入结点的值,就插入到右子树中
		else if ((*pRoot)->_data < data)
			InsertBSTree(&(*pRoot)->pRight, data);
		else
			return;
	}
}


//删除结点---递归
void DeleteBSTree(BSTreeNode **pRoot, DataType data)
{
	assert(pRoot);
	if (NULL == *pRoot)
		return;
	//在左子树中删除
	if ((*pRoot)->_data > data)
		DeleteBSTree(&(*pRoot)->pLeft, data);
	//在右子树中删除
	else if ((*pRoot)->_data < data)
		DeleteBSTree(&(*pRoot)->pRight, data);
	//删除根节点
	else
	{
		BSTreeNode *pDel = *pRoot;
		//待删除结点有右子树或者为叶子结点
		if (NULL == pDel->pLeft)
		{
			*pRoot = pDel->pRight;
			free(pDel);
		}
		//待删除结点只有左子树
		else if (NULL == pDel->pRight)
		{
			*pRoot = pDel->pLeft;
			free(pDel);
		}
		//待删除结点左右子树都有
		else
		{
			//找右子树中最左边的结点
			pDel = (*pRoot)->pRight;
			while (pDel->pLeft)
				pDel = pDel->pLeft;

			(*pRoot)->_data = pDel->_data;
			DeleteBSTree(&(*pRoot)->pRight, pDel->_data);
		}
	}
}

//找树中是否有此结点
//递归
int FindBSTNode(BSTreeNode *pRoot, DataType data)
{
	if (NULL == pRoot)
		return 0;

	if (pRoot->_data > data)
		return FindBSTNode(pRoot->pLeft, data);
	else if (pRoot->_data < data)
		return FindBSTNode(pRoot->pRight, data);
	else
		return 1;
}

//销毁二叉搜索树
void DestroyBSTree(BSTreeNode **pRoot)
{
	assert(pRoot);
	if (*pRoot)
	{
		DestroyBSTree(&(*pRoot)->pLeft);
		DestroyBSTree(&(*pRoot)->pRight);
		free(*pRoot);
		*pRoot = NULL;
	}
}

对于删除结点,插入结点和在二叉搜索树中查找结点也有非递归的实现,如下:


//插入结点
//非递归
void InsertBSTreeNor(BSTreeNode **pRoot, DataType data)
{
	assert(pRoot);

	if (NULL == *pRoot)
		*pRoot = BuyBSTNode(data);

	//找插入结点的位置
	BSTreeNode* pCur = *pRoot;
	BSTreeNode* pParent=NULL;
	while (pCur)
	{
		if (pCur->_data > data)
		{
			pParent = pCur;
			pCur = pCur->pLeft;
		}		
		else if (pCur->_data < data)
		{
			pParent = pCur;
			pCur = pCur->pRight;
		}
		else
			return;
	}

	//进行插入
	pCur = BuyBSTNode(data);
	if (pParent->_data > pCur->_data)
		pParent->pLeft = pCur;
	else
		pParent->pRight = pCur;
}


//删除结点
//非递归
void DeleteBSTreeNor(BSTreeNode **pRoot, DataType data)
{
	assert(pRoot);
	//1.查找删除结点的位置
	BSTreeNode *pCur = *pRoot;
	BSTreeNode *pParent = *pRoot;
	while (pCur)
	{
		if (pCur->_data > data)
		{
			pParent = pCur;
			pCur = pCur->pLeft;
		}
		else if (pCur->_data < data)
		{
			pParent = pCur;
			pCur = pCur->pRight;
		}
		else
			break;			
	}

	//待删除结点不在树中
	if (pCur == NULL)
		return;
	//待删除结点在树中
	//2.删除
	//(1)待删除结点只有右孩子或者为叶子结点
	if (pCur->pLeft == NULL)
	{
		//1)待删除结点为根
		if (pCur == *pRoot)
			*pRoot = pCur->pRight;
		//2)待删除结点不是根
		else
		{
			//若待删除的结点为左子树,则父结点的左指针指向待删除结点的孩子
			if (pCur == pParent->pLeft)
				pParent->pLeft = pCur->pRight;
			else
				pParent->pRight = pCur->pRight;
		}
	}
	//(2)待删除结点只有左孩子
	else if (pCur->pRight == NULL)
	{
		//1)待删除结点为根
		if (pCur == *pRoot)
			*pRoot = pCur->pLeft;
		//2)待删除结点不是根
		else
		{
			//若待删除的结点为左子树,则父结点的左指针指向待删除结点的孩子
			if (pCur == pParent->pLeft)
				pParent->pLeft = pCur->pLeft;
			else
				pParent->pRight = pCur->pLeft;
		}
	}
	//(3)待删除结点左右孩子都有
	else
	{
		//1)找待删除结点左子树的最右边结点或者右子树的最左边结点
		BSTreeNode *pDel = pCur->pRight;
		pParent = pCur;//若pCur没有左子树,pParent就不会更新
		while (pDel->pLeft)
		{
			pParent = pDel;
			pDel = pDel->pLeft;
		}
		//2)将pDel的值赋给pCur
		pCur->_data = pDel->_data;
		//3)删除pDel,此时pDel只有右子树或者为叶子结点
		if (pDel == pParent->pLeft)
			pParent->pLeft = pDel->pRight;
		else
			pParent->pRight = pDel->pRight;
		pCur = pDel;
	}
	free(pCur);
	pCur = NULL;
}


//找树中是否有此结点
//非递归
int FindBSTNodeNor(BSTreeNode *pRoot, DataType data)
{
	BSTreeNode *pCur = pRoot;
	while (pCur)
	{
		if (pCur->_data == data)
			return 1;
		else if (pCur->_data > data)
			pCur = pCur->pLeft;
		else
			pCur = pCur->pRight;
	}
	return 0;
}

二叉搜索树的性能:
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:logN
最差情况下,二叉搜索树退化为单支数,其平均比较次数为:N/2

因此有AVL树和红黑树:

AVL树:一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:1)它的左右子树都是AVL树 2)左右子树高度之差(平衡因子)的绝对值不超过1(-1、1、0)
AVL树的平均搜索时间为O(logN),避免了二叉搜索树最差的情况。

红黑树:比AVL树性能高,红黑树最长路径不超过最短路径的两倍
红黑树性质:1)每个节点不是红色就是黑色
2)根结点是黑色
3)不可能有连在一起的红色结点
4)对于每个结点,从该结点到其所有后代叶节点的简单路径上,均包含相同数目的黑色结点
5)每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
如图:

猜你喜欢

转载自blog.csdn.net/zimituanzi_/article/details/80627780