《数据结构与算法分析——C语言描述》ADT实现(NO.03) : 二叉搜索树/二叉查找树(Binary Search Tree)

二叉搜索树(Binary Search Tree),又名二叉查找树、二叉排序树,是一种简单的二叉树。它的特点是每一个结点的左(右)子树各结点的元素一定小于(大于)该结点的元素。将该树用于查找时,由于二叉树的性质,查找操作的时间复杂度可以由线性降低到O(logN)。

当然,这一复杂度只是描述了平均的情况,事实上,具体到每一棵二叉搜索树,查找操作的复杂度与树本身的结构有关。如果二叉树的结点全部偏向一个方向,那么与线性查找将毫无区别。这就牵扯到二叉树的平衡问题,暂时不做考虑。

下面给出二叉搜索树的实现。其中,个别可以递归实现的函数,笔者采用了循环的方式。由于递归方法通常较为简洁易懂,在此便不再补充给出。

// BinarySearchTree.h

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

struct _TreeNode;
typedef struct _TreeNode TreeNode;
typedef TreeNode *Position;
typedef TreeNode *SearchTree;

SearchTree MakeEmpty(SearchTree T);
Position Find(ElementType X, SearchTree T);
Position FindMin(SearchTree T);
Position FindMax(SearchTree T);
SearchTree Insert(ElementType X, SearchTree T);
SearchTree Delete(ElementType X, SearchTree T);
ElementType Retrieve(Position P);

  

// BinarySearchTree.c

#include "BinarySearchTree.h"

struct _TreeNode
{
    ElementType Element;
    SearchTree Left;
    SearchTree Right;
    int Count;
};

SearchTree MakeEmpty(SearchTree T)
{
    if (T != NULL)
    {
        MakeEmpty(T->Left);
        MakeEmpty(T->Right);
        free(T);
    }
    return NULL;
}

Position Find(ElementType X, SearchTree T)
{
    while (T != NULL)
    {
        if (T->Element < X)
            T = T->Right;
        else if (T->Element > X)
            T = T->Left;
        else
            return T;
    }
    printf("Not found! \n");
    return NULL;
}

// I write FindMin and FindMax in two different forms. The latter is more clean while the former is more understandable.
Position FindMin(SearchTree T)
{
    if (T == NULL)
        return NULL;
    while (T->Left != NULL)
    {
        T = T->Left;
    }
    return T;
}

Position FindMax(SearchTree T)
{
    if (T != NULL)
        while (T->Right != NULL)
            T = T->Right;
    return T;
}

Position CreateNode(ElementType X)
{
    Position p;
    p = (Position)malloc(sizeof(TreeNode));
    if (p == NULL)
    {
        printf("Error! Out of memory! \n");
        return NULL;
    }
    p->Left = p->Right = NULL;
    p->Element = X;
    p->Count = 1;
    return p;
}

// I do this without recursion, so the code is a bit long.
SearchTree Insert(ElementType X, SearchTree T)
{
    Position t = CreateNode(X);
    Position p = T;
    if (T == NULL)
        return t;
    while (1)
    {
        if (p->Element < X)
        {
            if (p->Right != NULL)
                p = p->Right;
            else
            {
                p->Right = t;
                return T;
            }
        }
        else if (p->Element > X)
        {
            if (p->Left != NULL)
                p = p->Left;
            else
            {
                p->Left = t;
                return T;
            }
        }
        else
        {
            p->Count++;
            return T;
        }
    }
}

SearchTree Delete(ElementType X, SearchTree T)
{
    Position temp;
    int t;
    if(T == NULL)
    {
        printf("Error! The tree is empty! \n");
        return NULL;
    }
    if(T->Element < X)
        T->Right = Delete(X, T->Right);
    else if(T->Element > X)
        T->Left = Delete(X, T->Left);
    else  
    {
        if(T->Count > 1)
            T->Count--;
        else  
        {
            if(T->Left && T->Right)
            {
                temp = FindMin(T);
                t = FindMin(T->Right)->Element;
                T->Count = temp->Count;
                temp->Count = 1;
                Delete(t, T);
                T->Element = t;
                return T;
            }
            else if(T->Left)
            {
                temp = T->Left;
                free(T);
                return temp;
            }
            else if(T->Right)
            {
                temp = T->Right;
                free(T);
                return temp;
            }
            else 
            {
                free(T);
                return NULL;
            }
        }
    }
}

ElementType Retrieve(Position P)
{
    return P->Element;
}

  

至于ADT正确性的测试,可以通过插入、删除结点后设置断点,观察各结点的左右子树元素值,从而与实际插入、删除的情况进行分析比较,判断其是否一致。

如果使用的编程环境进行此操作不甚方便,也可以通过二叉树的前/中/后序遍历序列来对照。

posted @ 2019-08-08 09:55  DrChuan  阅读(320)  评论(0编辑  收藏  举报