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:二叉查找树

关于二叉查找树

 

你可能感兴趣的:(二叉查找树)