树之二叉查找树(二叉搜索树)

目录

  1. 二叉查找树简介
  2. 二叉查找树举例以及详细分析
  3. 代码块
  4. 测试结果以及参考图纸

二叉查找树

二叉树的一个重要的应用是它们在查找中的使用。使二叉树成为查找树的性质是,对于树中的每个结点X,它的左子树中所有关键字值小于X的关键值,而它的右子树中所有关键字大于X的关键值。在图1中,左边的树是二叉查找树,但右边的树则不是(想一想为什么)。
这里写图片描述


二叉查找树举例以及详细分析

二叉查找树定义:又称为是二叉排序树(Binary Sort Tree)或二叉搜索树。二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
  1) 若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  2) 若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
  3) 左、右子树也分别为二叉排序树;
  4) 没有键值相等的节点。
  二叉查找树的性质:对二叉查找树进行中序遍历,即可得到有序的数列。
  二叉查找树的时间复杂度:它和二分查找一样,插入和查找的时间复杂度均为O(logn),但是在最坏的情况下仍然会有O(n)的时间复杂度。原因在于插入和删除元素的时候,树没有保持平衡。我们追求的是在最坏的情况下仍然有较好的时间复杂度,这就是平衡查找树设计的初衷。
  二叉查找树的高度决定了二叉查找树的查找效率。

二叉查找树的插入过程如下:

  1) 若当前的二叉查找树为空,则插入的元素为根节点;

  2) 若插入的元素值小于根节点值,则将元素插入到左子树中;

  3) 若插入的元素值不小于根节点值,则将元素插入到右子树中。

二叉查找树的删除,分三种情况进行处理:
(1) p为叶子节点,直接删除该节点,再修改其父节点的指针(注意分是根节点和不是根节点),如图a;

这里写图片描述

(2) p为单支节点(即只有左子树或右子树)。让p的子树与p的父亲节点相连,删除p即可(注意分是根节点和不是根节点),如图b;

这里写图片描述

(3) p的左子树和右子树均不空。找到p的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替p的值;或者方法二是找到p的前驱x,x一定没有右子树,所以可以删除x,并让x的父亲节点成为y的左子树的父亲节点。如图c。

这里写图片描述


代码块

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


typedef int ElementType;
struct TreeNode;
typedef struct TreeNode *SearchTree;

typedef struct TreeNode
{
    ElementType Element;
    SearchTree Left;
    SearchTree Right;
};

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

void PrintElement(SearchTree T);
void PreOrder(SearchTree T);
void InOrder(SearchTree T);
void PostOrder(SearchTree T);

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

SearchTree
Find(ElementType X, SearchTree T)
{
    if (T == NULL)
        return NULL;
    if (X < T->Element)
        return Find(X, T->Left);
    else
        if (X > T->Element)
            return Find(X, T->Right);
        else
            return T;
}





SearchTree FindMin(SearchTree T)
{
    if (T == NULL)
    {
        return NULL;
    }
    else if (T->Left == NULL)
    {
        return T;
    }
    else
    {
        return FindMin(T->Left);
    }
}

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

SearchTree Insert(ElementType X, SearchTree T)
{
    if (T == NULL)
    {
        //Creat and return a one-node tree
        T = (SearchTree)malloc(sizeof(struct TreeNode));
        if (T == NULL)
        {
            printf("Out of space!!!");
        }
        else
        {
            T->Element = X;
            T->Left = T->Right = NULL;
        }
    }
    else
    {
        if (X < T->Element)
        {
            T->Left = Insert(X, T->Left);
        }
        else if (X > T->Element)
        {
            T->Right = Insert(X, T->Right);
        }
    }
    //Else X is in the tree and we will do nothing;

    return T;//Do mot forget this line!!!
}

SearchTree Delete(ElementType X, SearchTree T)
{
    SearchTree TmpCell;
    if (T == NULL)
    {
        printf("Element not found");
    }
    else if(X < T->Element)
    {
        T->Left = Delete(X, T->Left);
    }
    else if (X > T->Element)
    {
        T->Right = Delete(X,T->Right);
    }
    //Found element to be deleted
    else if (T->Left&&T->Right)//Two children
    {
        //如果找到了要删除的节点,并且节点的的左儿子和右儿子都在;
        //选择右子树中值最大的节点赋给删除节点后的位置,并用递归删除右子树中最大的节点
        TmpCell = FindMin(T->Right);
        T->Element = TmpCell->Element;
        T->Right = Delete(T->Element, T->Right);
    }
    else//One or zero children
    {
        //如果找到要删除的节点,并且节点只有一个左儿子或一个右儿子
        TmpCell = T;
        if(T->Left == NULL)
        {
            T = T->Right;//若只有右儿子,把右儿子赋到删除节点的位置上
        }
        else if (T->Right == NULL)
        {
            T = T->Left;//若只有左儿子,把左儿子赋到删除节点的位置上
        }
        free(TmpCell);//释放掉要删除的节点
    }
    return T;
}

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

void PrintElement(SearchTree T)
{
    printf("%3d", Retrieve(T));
}

void PreOrder(SearchTree T)
{
    if (T != NULL)
    {
        PrintElement(T);
        PreOrder(T->Left);
        PreOrder(T->Right);
    }
}

void InOrder(SearchTree T)
{
    if (T != NULL)
    {
        InOrder(T->Left);
        PrintElement(T);
        InOrder(T->Right);
    }
}

void PostOrder(SearchTree T)
{
    if (T != NULL)
    {
        PostOrder(T->Left);
        PostOrder(T->Right);
        PrintElement(T);
    }
}

int main(void)
{
    SearchTree T = NULL;
    int i, j, m, n, num1, num2;
    ElementType tmp;
    printf("Number of Elements:");
    scanf("%d", &n);
    for (i = 0; i < n; i++)
    {
        printf("Elements %d:", i + 1);
        scanf("%d", &tmp);
        T = Insert(tmp, T);
    }

    printf("\nPreOrder:");
    PreOrder(T);
    printf("\nInOrder:");
    InOrder(T);
    printf("\nPostOrder:");
    PostOrder(T);
    printf("\n");

    printf("\nInput what num you want delete:");
    scanf("%d", &num1);
    Delete(num1, T);
    printf("\nPreOrder:");
    PreOrder(T);
    printf("\n");

    printf("\nInput what num you want insert:");
    scanf("%d", &num2);
    T = Insert(num2, T);
    printf("\nPreOrder:");
    PreOrder(T);
    printf("\n");

    system("pause");
    return 0;

}

测试结果

这里写图片描述
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值