1. 程式人生 > >二叉排序樹的操作(建立、插入、刪除和查詢)

二叉排序樹的操作(建立、插入、刪除和查詢)

二叉排序樹的建立、插入、刪除和查詢

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

typedef struct node
{
    int key;
    struct node *lchild,*rchild;
}BSTNode;

//二叉排序樹插入操作遞迴演算法
BSTNode *InsertBST1(BSTNode *T, int key)
{
    BSTNode *p, *q = T;

    //p為待插入的新結點
    p = (BSTNode *)malloc(sizeof(BSTNode));
    p->key = key;
    p->lchild = p->rchild = NULL;

    if(T == NULL) //原樹為空
        T = p; //新插入的結點為新的根

    //原樹非空時將新結點p作為q的左孩子或右孩子插入
    else
    {
        if(key == q->key)
            return T;

        if(key < q->key)
        {
            if(q->lchild ==NULL)
                q->lchild = p;
            else
                InsertBST1(q->lchild, key);
        }

        if(key > q->key)
        {
            if(q->rchild ==NULL)
                q->rchild = p;
            else
                InsertBST1(q->rchild, key);
        }
    }
    return T;
}

////二叉排序樹插入操作非遞迴演算法
BSTNode *InsertBST2(BSTNode *T, int key)
{
    BSTNode *f, *p = T;

    //查詢插入位置
    while(p)
    {
        if(key == p->key)
            return T;//無須插入

        f = p;//記錄訪問的結點
        if(key < p->key)
            p = p->lchild;
        else
            p = p->rchild;
        //若key<p->key,則在左子樹中查詢,否則在右子樹中查詢
    }

    //p為待插入的新結點
    p = (BSTNode *)malloc(sizeof(BSTNode));
    p->key = key;
    p->lchild = p->rchild = NULL;

    if(T == NULL) //原樹為空
        T = p; //新插入的結點為新的根

    //原樹非空時將新結點q作為p的左孩子或右孩子插入
    else
    {
        if(key < f->key)
            f->lchild = p;
        else f->rchild = p;
    }

    return T;
}

//二叉排序樹刪除操作
void DelBST(BSTNode *T,int key)
{
    BSTNode *p = T, *f, *q, *s;
    while(p)
    {
        if(p->key == key) break; //找到關鍵字為key的結點
        f=p;//記下關鍵字key節點的父節點
        p=(key < p->key)? p->lchild : p->rchild;//分別在*p的左、右子樹中查詢
    }
    if(!p) return;//二叉排序樹中無關鍵字為key的結點
    if(p->lchild == NULL && p->rchild == NULL)//p無左子樹無右子樹
    {
        if(p == T) T = NULL;//刪除的是根節點
        else
            if(p == f->lchild)
                f->lchild = NULL;
            else
                f->rchild = NULL;
    }
    else if(p->lchild == NULL && p->rchild != NULL)//p無左子樹有右子樹
    {
        if(f->lchild == p)
            f->lchild = p->rchild;
        else
            f->rchild = p->rchild;
    }
    else if(p->rchild == NULL && p->lchild != NULL)//p有左子樹無右子樹
    {
        if (f->lchild == p)
            f->lchild = p->lchild;
        else
            f->rchild = p->lchild;
    }
    else if(p->lchild != NULL && p->rchild != NULL)//p既有左子樹又有右子樹
    {
        q = p;
        s = p->lchild;//轉左
        while(s->rchild)
        {//然後向右到盡頭
            q = s;
            s = s->rchild;//s指向被刪節點的“前驅”(中序前驅)
        }
        p->key = s->key;//以p的中序前趨結點s代替p(即把s的資料複製到p中)
        if(q != p)
            q->rchild = s->lchild;//重接q的右子樹
        else
            q->lchild = s->lchild;//重接q的左子樹。
    }
}


//建立二叉排序樹
BSTNode *CreateBST()
{
    BSTNode *T = NULL; //初始時T為空樹
    int key;
    printf("請輸入一系列數,以0結尾:");
    while(1)
    {
        scanf("%d", &key);//讀入一關鍵字
        if(key == 0)
            break;//假設key=0是輸入結束標誌
        else
            T = InsertBST1(T, key); //使用遞迴演算法,將key插入二叉排序樹T,改為 T = InsertBST2(T, key);為非遞迴插入演算法
    }
    return T; //返回建立的二叉排序樹的根指標
}

//二叉排序樹查詢遞迴演算法
int BSTsearch1(BSTNode *T, int data)
{
    BSTNode *p = T;
    if(!p)
        return 0;
    else if(p->key == data)
            return 1;
        else if(p->key > data)
                return BSTsearch1(p->lchild, data);
            else
                return BSTsearch1(p->rchild, data);
}

//二叉排序樹查詢非遞迴演算法
int BSTsearch2(BSTNode *T, int data)
{
    BSTNode *p = T;
    while(p)
    {
        if(p->key == data)
            return 1;
        p = (p->key > data)? p->lchild : p->rchild;
    }
    return 0;
}

//中序遍歷得到的是一個有序的序列,實現了排序功能
void Inorder(BSTNode *T)
{
    if(T)
    {
        Inorder(T->lchild);
        printf("%d ",T->key);
        Inorder(T->rchild);
    }
}

int main()
{
    BSTNode *T = NULL;
    int data1,data2;
    T = CreateBST();

    printf("以上述數建立的二叉排序樹,中序遍歷的結果:");
    Inorder(T);

    printf("\n輸入待搜尋的資料data1=");
    scanf("%d", &data1);
    //遞迴演算法查詢
    if(BSTsearch1(T, data1))
        printf("%d存在\n");
    else
        printf("%d不存在\n");
    //非遞迴演算法查詢
    if(BSTsearch2(T, data1))
        printf("%d存在");
    else
        printf("%d不存在");


    printf("\n輸入待刪除的資料data2=");
    scanf("%d", &data2);
    DelBST(T,data2);
    printf("刪除後的二叉排序樹,中序遍歷的結果:");
    Inorder(T);

    return 0;
}


對於刪除操作的一點小改動的程式

//二叉排序樹刪除操作
void DelBST(BSTNode *T,int key)
{
    BSTNode *p = T, *f, *q, *s;
    while(p)
    {
        if(p->key == key) break; //找到關鍵字為key的結點
        f=p;//記下關鍵字key節點的父節點
        p=(key < p->key)? p->lchild : p->rchild;//分別在*p的左、右子樹中查詢
    }
    if(!p) return;//二叉排序樹中無關鍵字為key的結點
    if(p->lchild == NULL && p->rchild == NULL)//p無左子樹無右子樹
    {
        if(p == T) T = NULL;//刪除的是根節點
        else
            if(p == f->lchild)
                f->lchild = NULL;
            else
                f->rchild = NULL;
    }
    else if(p->lchild == NULL && p->rchild != NULL)//p無左子樹有右子樹
    {
        if(f->lchild == p)
            f->lchild = p->rchild;
        else
            f->rchild = p->rchild;
    }
    else if(p->rchild == NULL && p->lchild != NULL)//p有左子樹無右子樹
    {
        if (f->lchild == p)
            f->lchild = p->lchild;
        else
            f->rchild = p->lchild;
    }
    else if(p->lchild != NULL && p->rchild != NULL)//p既有左子樹又有右子樹
    {
        q = p;
        s = p->lchild;
        if(s->rchild == NULL)
        {
            q->key = s->key;
            q->lchild = s->lchild;//重接q的左子樹
        }
        else
        {
            while(s->rchild)
            {//然後向右到盡頭
                q = s;
                s = s->rchild;//s指向被刪節點的“前驅”(中序前驅)
            }
            p->key = s->key;//以p的中序前趨結點s代替p(即把s的資料複製到p中
            q->rchild = s->lchild;//重接q的右子樹
        }
    }
}