二叉搜索树的基本操作

二叉搜索树基本概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
(1)若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
(2)若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
(3)它的左右子树也分别为二叉搜索树

二叉搜索树查找、删除、插入等操作的时间复杂度:

给定值的比较次数等于给定值节点在二叉排序树中的层数。如果二叉排序树是平衡的,则n个节点的二叉排序树的高度为Log2n+1,其查找效率为O(Log2n),近似于折半查找。如果二叉排序树完全不平衡,则其深度可达到n,查找效率为O(n),退化为顺序查找。一般的,二叉排序树的查找性能在O(Log2n)到O(n)之间。因此,为了获得较好的查找性能,就要构造一棵平衡的二叉排序树。

基本操作具体代码实现如下:
测试环境:vs2013

BinSearchTree.h

#pragma once

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>





typedef int DataType;

typedef struct BinSearchTree
{
    DataType _data;
    struct BinSearchTree* _pLeft;
    struct BinSearchTree* _pRight;
}BSTree, *PBSTree;



//初始化
void BSTreeInit(PBSTree* pRoot);

//创建新节点
PBSTree BuyNewNode(DataType data);

//插入元素
void BSTreeInsert(PBSTree* pRoot, DataType data);

//二叉树中序遍历
void InOrder(PBSTree pRoot);

//查找元素
PBSTree BSTreeFind(PBSTree pRoot, DataType data);

//二叉搜索树删除
void BSTreeDelete(PBSTree* pRoot, DataType data);

//销毁--中序递归
void BSTreeDestory(PBSTree* pRoot);

BinSearchTree.c

#include "BinSearchTree.h"


//初始化
void BSTreeInit(PBSTree* pRoot)
{
    assert(pRoot);

    *pRoot = NULL;
}

//创建新节点
PBSTree BuyNewNode(DataType data)
{
    PBSTree ptr = NULL;
    ptr = (PBSTree)malloc(sizeof(BSTree));
    if (NULL == ptr)
    {
        assert(0);
        return NULL;
    }

    ptr->_data = data;
    ptr->_pLeft = NULL;
    ptr->_pRight = NULL;

    return ptr;
}


//插入,查找,删除非递归

//插入元素
void BSTreeInsert(PBSTree* pRoot, DataType data)
{
    PBSTree pCur = *pRoot;
    PBSTree pParent = NULL;
    assert(pRoot);

    //先判断是否为空树
    if (NULL == *pRoot)
    {
        *pRoot = BuyNewNode(data);
        return;
    }

    //找到插入位置,并保存插入位置的双亲结点
    while (pCur)
    {
        //插到左边
        if (pCur->_data > data)
        {
            pParent = pCur;
            pCur = pCur->_pLeft;
        }

        //插到右边
        else if (pCur->_data < data)
        {
            pParent = pCur;
            pCur = pCur->_pRight;
        }

        //数据相等
        else
            return;
    }

    if (data > pParent->_data)
        pParent->_pRight = BuyNewNode(data);

    if (data < pParent->_data)
        pParent->_pLeft = BuyNewNode(data);


}

//查找元素
PBSTree BSTreeFind(PBSTree pRoot, DataType data)
{
    PBSTree pCur = pRoot;

    if (pRoot == NULL)
    {
        printf("树已空,操作失败!\n");
        return NULL;
    }

    while (pCur)
    {
        if (pCur->_data == data)
            return pCur;

        else if (data > pCur->_data)
            pCur = pCur->_pRight;

        else
            pCur = pCur->_pLeft;
    }

    printf("没有该节点!\n");
    return NULL;
}


//二叉搜索树删除
void BSTreeDelete(PBSTree* pRoot, DataType data)
{
    PBSTree pCur = *pRoot;
    PBSTree pParent = NULL;
    assert(pRoot);

    //如果为空树,直接返回
    if (NULL == pRoot)
        return;

    //查找值为data的节点
    while (pCur)
    {
        if (pCur->_data == data)
            break;

        else if (data > pCur->_data)
        {
            pParent = pCur;
            pCur = pCur->_pRight;
        }

        else
        {
            pParent = pCur;
            pCur = pCur->_pLeft;
        }
    }

    //如果pCur为空,说明树中没有该节点
    if (NULL == pCur)
        return;

    else
    {
        //如果待删节点没有右子树或左右子树都没有
        //直接删
        if (!pCur->_pRight)
        {
            //判断待删节点是其双亲节点的什么节点
            if (pCur->_data > pParent->_data)//右
                pParent->_pRight = pCur->_pLeft;

            else
                pParent->_pLeft = pCur->_pLeft;

        }

        //如果待删节点没有左子树
        //直接删
        else if (!pCur->_pLeft)
        {
            if (pCur->_data > pParent->_data)//右
                pParent->_pRight = pCur->_pRight;

            else
                pParent->_pLeft = pCur->_pRight;

        }

        //如果待删节点左右子树都存在
        //不能直接删
        else
        {
            //先在待删节点左子树或右子树找代替节点
            //右子树--找最小节点--即最左节点
            //左子树--找最大节点--即最右节点

            //在右子树找最小节点来替换,走之前先将双亲节点挪过来
            PBSTree ptr = pCur;//用来保存待删节点
            pParent = pCur;//用来保存代替节点的双亲
            pCur = pCur->_pRight;

            while (pCur->_pLeft)
            {
                pParent = pCur;
                pCur = pCur->_pLeft;
            }

            //先将待删节点data与代替节点data交换
            ptr->_data = pCur->_data;

            //判断代替节点是其双亲的什么节点
            if(pCur == pParent->_pLeft)//左
                pParent->_pLeft = pCur->_pRight;//因为代替节点是右子树最小的,所以一定没有左子树

            else
                pParent->_pRight = pCur->_pRight;

        }
    }

    free(pCur);
}

//查找、插入、删除递归


//插入元素
void BSTreeInsert(PBSTree* pRoot, DataType data)
{
    assert(pRoot);

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

    else
    {
        if (data > (*pRoot)->_data)
            BSTreeInsert(&(*pRoot)->_pRight, data);

        else if (data < (*pRoot)->_data)
            BSTreeInsert(&(*pRoot)->_pLeft, data);

        //不处理二叉树已经有data的情况
        else
            return;

    }
}

//查找元素
PBSTree BSTreeFind(PBSTree pRoot, DataType data)
{

    if (NULL == pRoot)
        return NULL;

    else
    {
        //如果data小于pRoot的data,就到t它左子树找
        if (data < pRoot->_data)
            return BSTreeFind(pRoot->_pLeft, data);

        //如果data大于pRoot的data,就到t它右子树找
        else if (data > pRoot->_data)
            return BSTreeFind(pRoot->_pRight, data);

        //等于,直接返回节点
        else
            return pRoot;
    }
}

//二叉搜索树删除
void BSTreeDelete(PBSTree* pRoot, DataType data)
{
    assert(pRoot);

    //空树直接返回
    if (NULL == *pRoot)
        return;

    else
    {   
        //先找到待删除节点
        //如果小,到左子树找
        if (data < (*pRoot)->_data)
            BSTreeDelete(&(*pRoot)->_pLeft, data);

        //如果大,到右子树找
        else if (data >(*pRoot)->_data)
            BSTreeDelete(&(*pRoot)->_pRight, data);

        //说明找到了
        else
        {
            //如果没有右子树或者左右子树都没有
            //直接删
            PBSTree pDel = *pRoot;
            if (!(*pRoot)->_pRight)
            {
                *pRoot = pDel->_pLeft;
                free(pDel);
            }

            //如果没有左子树,也直接删
            else if (!(*pRoot)->_pLeft)
            {
                *pRoot = pDel->_pRight;
                free(pDel);
            }

            //如果左右子树都存在
            else
            {
                //到*pRoot右子树找最小节点--最左边
                pDel = (*pRoot)->_pRight;

                while (pDel->_pLeft)
                    pDel = pDel->_pLeft;

                //将代替节点的值交给*pRoot
                (*pRoot)->_data = pDel->_data;

                //在*pRoot的右子树删除值为pDel->data的节点
                BSTreeDelete(&(*pRoot)->_pRight, pDel->_data);

            }
        }
    }
}




//二叉树中序遍历
void InOrder(PBSTree pRoot)
{
    if (pRoot)
    {
        InOrder(pRoot->_pLeft);
        printf("%d ", pRoot->_data);
        InOrder(pRoot->_pRight);
    }
}

//销毁--中序递归
void BSTreeDestory(PBSTree* pRoot)
{
    assert(pRoot);

    if (*pRoot)
    {
        //先销毁左子树
        BSTreeDestory(&(*pRoot)->_pLeft);

        //再销毁右子树
        BSTreeDestory(&(*pRoot)->_pRight);

        //销毁跟节点
        free(*pRoot);
        *pRoot = NULL;
    }

}

test.c

#include "BinSearchTree.h"


void Test1()
{
    int i = 0;
    int arr[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
    int size = sizeof(arr) / sizeof(arr[0]);
    PBSTree pRoot;

    BSTreeInit(&pRoot);
    for (; i < size; i++)
        BSTreeInsert(&pRoot, arr[i]);
    InOrder(pRoot);

    printf("\n");
    BSTreeDelete(&pRoot, 5);
    InOrder(pRoot);

    BSTreeDelete(&pRoot, 8);
    printf("\n");
    InOrder(pRoot);

    BSTreeDelete(&pRoot, 2);
    printf("\n");
    InOrder(pRoot);
}

int main()
{
    Test1();//测试二叉搜索树
}

猜你喜欢

转载自blog.csdn.net/virgofarm/article/details/80315962