搜索结构之二叉搜索树

搜索结构之二叉搜索树:


二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树

      若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

      若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

      它的左右子树也分别为二叉搜索树

二叉搜索树的实现递归和非递归:

BSTree.h

#pragma once
//二叉搜索树---左子树比根节点小,右子树比根节点大,中序遍历时可得到升序序列
typedef int DataType;
typedef struct BSTreeNode{
	struct BSTreeNode* _pLeft;
	struct BSTreeNode* _pRight;
	DataType _data;
}BSTreeNode;
void InitBSTree(BSTreeNode**pRoot);
void InsertBSTree(BSTreeNode**pRoot, DataType data);
int FindBSTree(BSTreeNode*pRoot, DataType data);
void DeleteBSTree(BSTreeNode**pRoot, DataType data);
void PreOrder(BSTreeNode* pRoot);
void DestroyBSTree(BSTreeNode**pRoot);
int DG_FindBSTree(BSTreeNode*pRoot, DataType data);
void DG_InsertBSTree(BSTreeNode**pRoot, DataType data);
void DG_DeleteBSTree(BSTreeNode**pRoot, DataType data);

BSTree.c

#include "BSTree.h"
#include<assert.h>
#include<stdlib.h>
#include<stdio.h>
#include<malloc.h>
void InitBSTree(BSTreeNode**pRoot){
	assert(pRoot);
	*pRoot = NULL;
}
BSTreeNode*  BuyBSTreeNode(DataType data){
	BSTreeNode * NewNode = (BSTreeNode *)malloc(sizeof(BSTreeNode));
	if (NewNode == NULL)
		return NULL;
	NewNode->_data = data;
	NewNode->_pLeft = NULL;
	NewNode->_pRight = NULL;
	return NewNode;
}
void InsertBSTree(BSTreeNode**pRoot, DataType data){
	BSTreeNode *pcur=NULL;
	BSTreeNode *parent=NULL;
	assert(pRoot);
	if (*pRoot == NULL)
	{
		*pRoot = BuyBSTreeNode(data);
		return;
	}
	//查找待插节点的位置
	pcur = *pRoot;
	while (pcur)
	{
		if (data>pcur->_data)
		{
			parent = pcur;
			pcur = pcur->_pRight;
		}
		else if (data < pcur->_data){
			parent = pcur;
			pcur = pcur->_pLeft;
		}
		else
			return;
	}
	//插入新节点
	pcur = BuyBSTreeNode(data);
	if (data<(parent->_data))
	   parent->_pLeft=pcur;
	else 
	   parent->_pRight = pcur;
}
int FindBSTree(BSTreeNode*pRoot, DataType data){
	BSTreeNode *pcur = pRoot;
	while (pcur)
	{
		if (data == pcur->_data)
			return 1;
		else if (data<pcur->_data)
			pcur = pcur->_pLeft;
		else pcur = pcur->_pRight;
	}
	return 0;
}
void DeleteBSTree(BSTreeNode**pRoot, DataType data){
	BSTreeNode *pcur = NULL;
	BSTreeNode *parent = NULL;
	assert(pRoot);
	if (0 == FindBSTree(*pRoot,data))
		return;
	pcur = (*pRoot);
	while (pcur)
		{
			if (data>pcur->_data)
			{
				parent = pcur;
				pcur = pcur->_pRight;
			}
			else if (data < pcur->_data)
			{
				parent = pcur;
				pcur = pcur->_pLeft;
			}
			else break;
	   }
	//待删元素不在树中
	if (pcur == NULL)
		return;
	//找到该节点
	if (pcur->_pLeft==NULL)//该节点是叶子节点或者是只有右子树
	{
		if (pcur == (*pRoot))
			*pRoot = pcur->_pRight;
		else
		{
			if (pcur == parent->_pLeft)
				parent->_pLeft = pcur->_pRight;
			else parent->_pRight = pcur->_pRight;
		}
	
	}
	else if (pcur->_pRight==NULL)//该节点是叶子节点或者是只有左子树
	{
		if (pcur == (*pRoot))
			*pRoot = pcur->_pLeft;
		else
		{
			if (pcur == parent->_pLeft)
				parent->_pLeft = pcur->_pLeft;
			else parent->_pRight = pcur->_pLeft;
		}
		free(pcur);
	}
	else//	左右孩子都有,在左子树中寻找最大节点或者在右子树中寻找最小的节点,替换待删节点,然后删除
	{
		BSTreeNode *pDel = pcur->_pRight;
		parent = pDel;
		while (pDel->_pLeft)
		{
			parent = pDel;
			pDel = pDel->_pLeft;
		}
		pcur->_data = pDel->_data;
		if (pDel = parent->_pLeft)
			parent->_pLeft = pDel->_pRight;
		if (pDel = parent->_pRight)
			parent->_pRight = pDel->_pRight;
	}  

	free(pcur);
}
void PreOrder(BSTreeNode* pRoot){
	if (pRoot)
	{
		PreOrder(pRoot->_pLeft);
		printf("%d ", pRoot->_data);
		PreOrder(pRoot->_pRight);
	}
}
void DestroyBSTree(BSTreeNode**pRoot){
	assert(pRoot);
	if (*pRoot)
	{
		DestroyBSTree(&(*pRoot)->_pLeft);
		DestroyBSTree(&(*pRoot)->_pRight);
		free(*pRoot);
		*pRoot = NULL;
    }
}
//递归
int DG_FindBSTree(BSTreeNode*pRoot, DataType data){
	if (NULL == pRoot)
		return 0;
	if (data == pRoot->_data)
		return 1;
	else if(data < pRoot->_data)
		return DG_FindBSTree(pRoot->_pLeft,data);
	else 
		return DG_FindBSTree(pRoot->_pRight,data);
}
void DG_InsertBSTree(BSTreeNode**pRoot, DataType data){
	assert(pRoot);
	if (*pRoot == NULL)
	{
		*pRoot = BuyBSTreeNode(data);
		return;
	}
	else
	{
		if (data < (*pRoot)->_data)
			return DG_InsertBSTree(&(*pRoot)->_pLeft, data);
		else if (data > (*pRoot)->_data)
			return DG_InsertBSTree(&(*pRoot)->_pRight, data);
		else
			return;
		
	}
}
void DG_DeleteBSTree(BSTreeNode**pRoot, DataType data){
	assert(pRoot);
	if (*pRoot == NULL)
	{
		return;
	}
	if (data < (*pRoot)->_data)
		return DG_DeleteBSTree(&(*pRoot)->_pLeft, data);
	else if (data >(*pRoot)->_data)
		return DG_DeleteBSTree(&(*pRoot)->_pRight, data);
	else {
		BSTreeNode *pDel = *pRoot;
		if (pDel->_pLeft == NULL){
			*pRoot = pDel->_pRight;
			free(pDel);
		}
		else if (pDel->_pRight == NULL){
			*pRoot = pDel->_pLeft;
			free(pDel);
		}
		else{
			BSTreeNode *pDel = (*pRoot)->_pRight;
			while (pDel->_pLeft)
				pDel = pDel->_pLeft;
			(*pRoot)->_data = pDel->_data;
			return DG_DeleteBSTree(&(*pRoot)->_pRight, data);
		}
	}
}

二叉搜索树的性能分析:

  二叉搜索树的插入和删除都必须先查找,查找的效率代表了二叉搜索树中各个操作的性能.

  对于有n个节点的二叉搜索树,最优情况下,二叉树为完全二叉树,其平均比较的次数就是lgN.最差情况下,二叉树为单支树,其平均比较的次数就是N/2.

  如果退化成单枝树,二叉搜索树的性能就消失了,为了使性能更加,需要进行改进!!!

平衡树(解决单支问题):

二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下.因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度.

AVL树

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:

     它的左右子树都是AVL树

     左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在O(lgn),平均搜索时间复杂度O(lg(n))

红黑树
红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是red或者black,通过对任何一条从根节点到叶子结点简单路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似平衡,而且在实际应用中发现红黑树性能确实比AVL树性能高
红黑树性质
1. 每个结点不是红色就是黑色
2. 根节点是黑色的
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

猜你喜欢

转载自blog.csdn.net/sx2448826571/article/details/80331007