C算法学习笔记(2)-二叉查找树

本文原始地址:C算法学习笔记(2)-二叉查找树


查找操作

若根结点的关键字值等于查找的关键字,成功。
否则,若小于根结点的关键字值,递归查左子树。
若大于根结点的关键字值,递归查右子树。
若子树为空,查找不成功。

/*
 //二叉树查找算法
 //T 二叉树
 //x 要查找的值
 */
BiTree BSTSearch(BiTree T,int x)
{
    BiTreeNode *p;
    if (T != NULL)
    {
        p = T;
        while (p != NULL)
        {
            if (p->data == x)//如果该结点就是我们想要的
            {
                return p;
            }else if(x > p->data)//如果查找的值是该结点右子树
            {
                p = p->rchild;
            }else//如果查找的值是该结点左子树
            {
                p = p->lchild;
            }
        }
    }
    return NULL;
}


插入操作

首先执行查找算法,找出被插结点的父亲结点。
判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
若二叉树为空。则首先单独生成根结点。
注意:新插入的结点总是叶子结点。

/*
 //二叉树插入操作
 //T 二叉树
 //x 要插入的值
 */
int BSTInsert(BiTree *T,int x)
{
    BiTreeNode *p = NULL;//把x组装成一个只有根结点的树
    BiTreeNode *cur = NULL;//纪录当前遍历的结点
    BiTreeNode *parent = NULL;//纪录上一次遍历的结点,最后一个值为我们需要插入的结点位置
    cur = *T;
    while (cur != NULL)
    {
        if (cur->data == x)//插入操作如果数值已存在,插入失败
        {
            return 0;
        }
        parent = cur;//将到该结点子树遍历,纪录下该结点,该循环最终输出值
        if (x < cur->data)//到该结点左子树继续遍历
        {
            cur = cur->lchild;
        }else//到该结点右子树继续遍历
        {
            cur = cur->rchild;
        }
    }
    //申请内存空间
    p = (BiTreeNode *)malloc(sizeof(BiTreeNode));
    if (!p)//内存空间申请失败,内存不够用了,终止程序
    {
        exit(-1);
    }
    //初始化p结点
    p->data = x;
    p->lchild = NULL;
    p->rchild = NULL;
    
    if (!parent)
    {
        *T = p;//这本来就是棵空树,p将会作为根结点
    }else if(x < parent->data)
    {
        parent->lchild = p;
    }else
    {
        parent->rchild = p;
    }
    return 1;//插入成功
}



删除操作

1.若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
2.若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉排序树的特性。
3.若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,可以有两种做法:
其一是令*p的左子树为*f的左/右(依*p是*f的左子树还是右子树而定)子树,*s为*p左子树的最右下的结点,而*p的右子树为*s的右子树;
其二是令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。

 

/*
 //删除结点
 //删除的结点s
 //原则:保持二叉树性质不变-根结点的值大于左子树的值小于右子树的值...
 */
void DeleteNode(BiTree *s)
{
    if (!s) return;
    BiTreeNode *q = NULL;//中间量,纪录旧的的s结点数据
    BiTreeNode *x = NULL;
    BiTreeNode *y = NULL;
    
    if(!(*s)->rchild)//如果右子树不存在
    {
        q = (*s);
        (*s) = (*s)->lchild;
        free(q);
    }else if(!(*s)->lchild)//如果左子树不存在
    {
        q = (*s);
        (*s) = (*s)->rchild;
    }else//如果左右都存在的话,令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)-即让*f的左子树(如果有的话)成为*p左子树的最左下结点(如果有的话),再让*f成为*p的左右结点的父结点。
    {
        x = (*s);
        y = (*s)->lchild;
        while (y->rchild)//查找s的直接前驱结点,y为s的直接前驱结点,x为y的双亲结点
        {
            x = y;
            y = y->lchild;
        }
        (*s)->data = y->data;//结点s被y取代
        if (x != (*s))//如果结点s的左孩子结点不存在右子树
        {
            x->rchild = y->lchild;//使y的左子树成为x的右子树
        }else
        {
            x->lchild = y->lchild;
        }
        free(y);
    }
}


/*
 //在二叉树中查找关键字为x的结点,并删除,删除成功返回1,否则返回0
 //T 二叉树
 //x 关键字
 */
int BSTDelete(BiTree *T,int x)
{
    if (!*T) return 0;
    if (x == (*T)->data)
    {
        DeleteNode(T);
    }else if (x < (*T)->data)
    {
        BSTDelete(&(*T)->lchild,x);
    }else
    {
        BSTDelete(&(*T)->rchild,x);
    }
    return 1;
}

附:中序遍历

//中序遍历
void InOrderTraverse(BiTree T)
{
    if (T)
    {
        InOrderTraverse(T->lchild);
        printf("%4d",T->data);
        InOrderTraverse(T->rchild);
    }
}


视频地址:BST:二叉查找树

关于二叉查找树

原文地址:https://www.cnblogs.com/javawebsoa/p/3063596.html