二叉搜索樹的基本操作(插入,刪除)

前言

二叉搜索樹是什麼
二叉查找樹(Binary Search Tree),(又:二叉搜索樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別爲二叉排序樹。

基本操作

插入

遞歸

int BSTreeInsertR(BSTreeNode** tree, BSTDataType x)
{
    assert(tree);
    if (*tree == NULL)
    {
        *tree = BuyBSTreeNode(x);
        return 1;
    }
    if ((*tree)->_data > x)
        return BSTreeInsertR(&(*tree)->_left, x);
    else if ((*tree)->_data < x)
        return BSTreeInsertR(&(*tree)->_right, x);
    else
        return 0;
}

非遞歸

//搜索二叉樹左子樹的數據小於根結點,右子樹的的數據大於根節點   並且不能插入裏面已經有的數據
int BSTreeInsert(BSTreeNode** tree, BSTDataType x)
{
    assert(tree);
    BSTreeNode* parent =NULL;
    BSTreeNode* cur = *tree;
    if (cur == NULL)
    {
        *tree = BuyBSTreeNode(x);
        //插入成功
        return 1;
    }


    while (cur)
    {
        if (x < cur->_data)
        {
            parent = cur;
            cur = cur->_left;
        }
        else if (x>cur->_data)
        {
            parent = cur;
            cur = cur->_right;
        }
        else
        {
            //遇到相同的數據插入失敗
            return 0;
        }
    }

    if (x < parent->_data)
    {
        parent->_left = BuyBSTreeNode(x);
    }
    else
    {
        parent->_right = BuyBSTreeNode(x);
    }

    return 1;
}

刪除

思路分析:(將要刪除的結點標記爲del)
第一種情況要刪除的結點無左右孩
方法:直接刪除該結點,並讓其父結點從指向它變爲指向空
注意:如果刪除的結點爲根結點,根結點是沒有父結點的,就將根節點的右孩重新定爲新的根節點。

第二種情況要刪除的結點有左孩無右孩
方法:讓該結點的父節點的左孩指向該結點的左孩
注意:如果刪除的結點爲根結點,根結點是沒有父結點的,就將根節點的左孩重新定爲新的根節點。

第三種情況要刪除的結點無左孩有右孩
方法:與第一種情況解決方法一樣。

第四種情況要刪除的結點左右孩都存在
方法:找到該結點的右子樹中最左的結點(在此稱它爲repalce),爲什麼要找replace呢,因爲replace是del右子樹中最小的數,然後將replace的數據代替del中的數據,這樣整體依然滿足二叉搜索樹的特性,然後再利用遞歸刪除,刪除replace。
ps:要刪除的結點並不是真的刪除這個結點,而是將它的值替換了。

遞歸

int BSTreeRemoveR(BSTreeNode** tree, BSTDataType x)
{
    if (*tree == NULL)
        return -1;
    if ((*tree)->_data > x)
        BSTreeRemoveR(&(*tree)->_left, x);
    else if ((*tree)->_data < x)
        BSTreeRemove(&(*tree)->_right,x);
    else
    {
        //左爲空右不爲空/爲空
        BSTreeNode* del = *tree;
        if ((*tree)->_left == NULL)
        {
            *tree = (*tree)->_right;
            free(del);
        }
        //左不爲空  右爲空
        else if ((*tree)->_right == NULL)
        {
            *tree = (*tree)->_left;
            free(del);
        }
        //左右都不爲空
        else
        {
            //先找右子樹的最左子樹
            BSTreeNode* replace = (*tree)->_right;
            while (replace->_left)
            {
                replace = replace->_left;
            }
            (*tree)->_data = replace->_data;
            return BSTreeRemoveR(&(*tree)->_right, replace->_data);
        }

        return 1;
    }
    return 0;
}

非遞歸

int BSTreeRemove(BSTreeNode** tree, BSTDataType x)
{
    assert(tree);

    assert(tree);
    BSTreeNode* parent = NULL;
    BSTreeNode* cur = *tree;
    if (cur == NULL)
        return 0;//刪除失敗

    while (cur)
    {
        if (x < cur->_data)
        {
            parent = cur;
            cur = cur->_left;
        }
        else if (x>cur->_data)
        {
            parent = cur;
            cur = cur->_right;
        }
        else
        {
            //無左孩子有右孩     或者無左孩無右孩
             if (cur->_left == NULL)
            {
                 //如果是根結點,特殊處理
                 if (cur == *tree)
                 {
                     *tree = cur->_right;
                     free(cur);
                     return 1;
                 }
                 else
                 {
                     if (parent->_left == cur)
                     {
                         parent->_left = cur->_right;
                     }
                     else
                     {
                         parent->_right = cur->_right;
                     }
                     free(cur);
                     return 1;//刪除成功
                 }
            }
            //有左孩子無右孩
            else if (cur->_right == NULL)
            {
                //如果是根結點,特殊處理
                if (cur == *tree)
                {
                    *tree = cur->_left;
                    free(cur);
                    return 1;
                }
                else
                {
                    if (parent->_left == cur)
                    {
                        parent->_left = cur->_left;
                    }
                    else
                    {
                        parent->_right = cur->_left;
                    }
                    free(cur);
                    return 1;//刪除成功
                }
            }
            //有左孩也有右孩
            //採用替換的方法
            //找到該結點底下右結點中最左的孩子與其交換 因爲其右結點中最左的孩子比該結點左邊的結點都要大,但比該結點右邊結點都要小,所以要找到它
            else
            {
                BSTreeNode* cur1 = cur->_right;
                while (cur1->_left)
                {
                    cur1 = cur1->_left;
                }
                //找到後開始交換值
                cur->_data = cur1->_data;
            return  BSTreeRemove(&cur->_right, cur1->_data);//遞歸刪除
            }
        }
    }


    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章