二叉排序树的建立、查找和删除

1.二叉排序树的概念:

二叉排序树是一种动态树表.

二叉排序树的定义:二叉排序树或者是一颗空树,或者是一颗具有如下性质的二叉树:

  • 若它的左子树非空,则左子树上的所有的节点的值均小于根节点的值.
  • 若它的右子树非空, 则右子树上的所有节点的值均大于根节点的值.
  • 左右子树本身又各是一颗二叉排序树,二叉排序树的性质:按中序遍历二叉排序树,得到的中序遍历是一个递增有序序列.

2.二叉树的插入:

在二叉排序树中插入新的节点,要保证插入后的二叉树仍然符合二叉树的定义.

插入过程:若二叉排序树为空, 则待插入的节点*s作为根节点插入到空树中;

当非空时,将待插入点关键字k 和根节点bst->key;若k<bst->key.bst=bst-<Lchild;k>bst->key,bst=bst->Rchild,一直这样递归下去,知道bst为空,插入到叶子节点.若k=bst->key,则不做任何操作, 直接返回.

3.二叉树排序树的生成:

从空的二叉排序树开始, 经过一系列的查找插入操作之后,生成了一颗二叉排序树.

说明:

  1. 每次插入的都是二叉树的叶子节点.
  2. 由不同顺序的关键字序列,会得到不同的二叉排序树.
  3. 对于一个任意的关键字序列构造一颗二叉树,其实是对关键字进行排序.

3.二叉排序树的删除:

假设被删节点*p的双亲节点是*f:

1.若*p是叶子节点,则只需要修改双亲节点的指针.

2.若节点*p是*f的左孩子.且*p只有左孩子或者只有右孩子,则只要使*p的左孩子或右孩子成为f的左孩子.     若节点*p是*f的右孩子孩子.且*p只有左孩子或者只有右孩子,则只要使*p的左孩子或右孩子成为f的右孩子.

3.若节点的左右子树均非空,先找到*p的前驱节点*s(注意*s是*p的左子树中最右下的节点,它的右链为空),以*p的中序前趋结点*s代替*p(即把*s的数据复制到*p中),将*s的左子树链到*s的双亲结点*q的左(或右)链上.

下面是我实现的代码:

#include<stdio.h>
#include<stdlib.h>
#define INFINE 32678
typedef int KeyType;  //数据类型
typedef struct Node
{
    KeyType key;
    struct Node *Lchild,*Rchild;
}BSTNode,*BSTree;
void InsertBST(BSTree *bst,KeyType k)    //插入建树法;
{
    BSTNode *s;
    if(*bst == NULL){
        s=(BSTree)malloc(sizeof(BSTNode));
        s->key=k;
        s->Lchild=NULL;
        s->Rchild=NULL;
        *bst=s;
    }else{            //寻找k的位置.
        if(k>(*bst)->key){      
            InsertBST(&((*bst)->Rchild),k);
        }else if(k<(*bst)->key){
            InsertBST(&((*bst)->Lchild),k);
        }
    }
}
void Created(BSTree *bst)
{
    KeyType key;
    *bst=NULL;
    scanf("%d",&key);
    while(key!=INFINE){
        InsertBST(bst,key);
        scanf("%d",&key);
    }
}
void Inorder(BSTree bst)
{
    if(bst!=NULL){
        Inorder(bst->Lchild);
        printf("%d ",bst->key);
        Inorder(bst->Rchild);
    }
}
BSTree SerchBST(BSTree bst,KeyType k)
{
    BSTNode *q;
    q=bst;
    while(q){
        if(q->key ==k){
            return q;
        }
        if(k>q->key){
            q=q->Rchild;
        }else{
            q=q->Lchild;
        }
    }
    return NULL;
}
BSTree DeleteBST(BSTree bst,KeyType k)
{
    BSTNode *p,*f,*q,*s;
    p=bst;
    f=NULL;
    while(p){      //寻找要删除的节点是否在二叉排序树中.
        if(p->key == k){
            break;
        }
        f=p;     //f记录p的双亲节点.
        if(p->key > k){  
            p=p->Lchild;
        }else{
            p=p->Rchild;
        }
        
    }
    if(p==NULL){
        return 0;  //待删除的节点不存在
    }
   if(p->Lchild==NULL && p->Rchild==NULL){   //待删节点的左右子树都为空.
        if(p==bst){
            bst=NULL;   //删除的是根节点;
        }else{
            if(f->Lchild == p){   
                f->Lchild=NULL;
            }else{
                f->Rchild=NULL;
            }
        }
        free(p);
    }else if(p->Lchild == NULL && p->Rchild != NULL){   //待删节点的左子树为空,右子树不为空!
        if(f->Lchild == p){
            f->Lchild=p->Rchild; //将p的右子树链接到其父节点的左链上.
        }else{
            f->Rchild=p->Rchild;   //将p的右子树链接到其父节点的右链上
        }
        free(p);
    }else if(p->Rchild == NULL && p->Lchild != NULL){
        if(f->Lchild == p){
            f->Lchild=p->Lchild;   //将p的左子树链接到父节点的左链上.
        }else{
            f->Rchild == p->Lchild;   //将p的左子树链接到父节点的右链上.
        }
        free(p);
    }else if(p->Lchild!=NULL && p->Rchild!=NULL){    //待删节点的左右子树都不为空,
        q=p;
        s=p->Lchild;    //转向左子树
        while(s->Rchild){      
            q=s;
            s=s->Rchild;       //s指向被删节点的前驱节点(中序前驱)
        }
        if(q!=p){
            q->Rchild=s->Lchild;  //重接q的右子树
        }else{
            q->Lchild=s->Lchild;  //重接q的左子树
        }
        p->key=s->key;              //以p的(中序)前驱节点s的key替换p中值.
        free(s);
    }
}
int main(int argc,char *argv[])
{
    BSTree bst;
    BSTNode *q;
    Created(&bst);
    Inorder(bst);
    printf("\n");
    q=SerchBST(bst,3);
    printf("%d\n",q->key);
    DeleteBST(bst,3);
    Inorder(bst);
    return 0;
}

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/whoamiyang/article/details/50859885
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞