搜索结构之二叉搜索树:
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树
二叉搜索树的实现递归和非递归:
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. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)