【資料結構】——搜尋二叉樹的插入,查詢和刪除(遞迴&非遞迴)

龍躍十二發表於2018-02-26

一、搜尋二叉樹的插入,查詢,刪除
簡單說說搜尋二叉樹概念:
二叉搜尋樹又稱二叉排序樹,它或者是一棵空樹,或者是具有以下性質的二叉樹
若它的左子樹不為空,則左子樹上所有節點的值都小於根節點的值
若它的右子樹不為空,則右子樹上所有節點的值都大於根節點的值
它的左右子樹也分別為二叉搜尋樹
例如:int a [] = {5,3,4,1,7,8,2,6,0,9};
搜尋二叉樹
二叉樹結構

typedef struct BSTreeNode 
{
    struct BSTreeNode *_left;
    struct BSTreeNode *_right;
    DataType _data;
}BSTreeNode;

二叉樹節點建立

BSTreeNode *BuyTreeNode(DataType x) //建立節點
{
    BSTreeNode *node = (BSTreeNode*)malloc(sizeof(BSTreeNode));
    assert(node);

    node->_data = x;
    node->_left = NULL;
    node->_right = NULL;

    return node;
}

二叉搜尋樹操作:
1、搜尋二叉樹的插入:在二叉搜尋樹中插入新元素時,必須先檢測該元素是否在樹中已經存在。如果已經存在,則不進行插入;否則將新元素加入到搜尋停止的地方。
搜尋二叉樹插入具體過程
非遞迴程式碼

int BSTreeNodeInsert(BSTreeNode **pptree,DataType x) //搜尋樹的插入
{
    BSTreeNode *parent = NULL;
    BSTreeNode *cur = *pptree;
    if (*pptree == NULL)
    {
        *pptree = BuyTreeNode(x);
        return 0;
    }
    while (cur)
    {
      parent = cur;
      if (cur->_data > x)
          cur = cur->_left;
      else if (cur->_data < x)
          cur = cur->_right;
      else
          return -1;
    }

    if (parent->_data > x)
        parent->_left = BuyTreeNode(x);
    else 
        parent->_right = BuyTreeNode(x);

    return 0;
}

遞迴程式碼 :

int BSTreeNodeInsertR(BSTreeNode **tree,DataType x) //搜尋樹的插入
{
    if(*tree == NULL)
    {
        *tree = BuyTreeNode(x);
        return 0;
    }

    if ((*tree)->_data > x)
        return BSTreeNodeInsertR(&(*tree)->_left,x);
    else if ((*tree)->_data < x)
        return BSTreeNodeInsertR(&(*tree)->_right,x);
    else
        return -1;
}

2、搜尋二叉樹的查詢
這裡寫圖片描述

非遞迴程式碼

BSTreeNode *BSTreeNodeFind(BSTreeNode *tree,DataType x) //查詢
{
    while (tree)
    {
        if (tree->_data == x)
            return tree;
        else if (tree->_data < x)
            tree = tree->_right;
        else 
            tree = tree->_left;
    }

    return NULL;
}

遞迴程式碼

BSTreeNode *BSTreeNodeFindR(BSTreeNode *tree,DataType x) //查詢
{
    if (!tree)
        return NULL;

    if (tree->_data > x)
        BSTreeNodeFindR(tree->_left,x);
    else if (tree->_data < x)
        BSTreeNodeFindR(tree->_right,x);
    else
        return tree;
}

3、搜尋二叉樹的刪除
首先查詢元素是否在二叉搜尋樹中,如果不存在,則返回, 否則要刪除的結點可能分下面四種情況:
a. 要刪除的結點無孩子結點
b. 要刪除的結點只有左孩子結點
c. 要刪除的結點只有右孩子結點
d. 要刪除的結點有左、右孩子結點
情況1可以歸類到2或者3
對於上述情況,相應的刪除方法如下:
a. 直接刪除該結點
b. 刪除該結點且使被刪除節點的雙親結點指向被刪除節點的左孩子結點
c. 刪除該結點且使被刪除節點的雙親結點指向被刪除結點的右孩子結點
d. 在它的右子樹中尋找中序下的第一個結點(關鍵碼最小),用它的值填補到被刪除節點中,在來處理該結點的刪除問題
非遞迴程式碼實現:

int BSTreeNodeDel(BSTreeNode **tree,DataType x) //刪除
{

    BSTreeNode *cur = *tree;
    BSTreeNode *parent = *tree;
    BSTreeNode *del = NULL;

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

            if (cur->_left == NULL) //1、左孩子為空
            {
                if (parent->_left == cur)
                    parent->_left = cur->_right;
                else if (parent->_right == cur)
                    parent->_right = cur->_right;
                else if (parent == cur) //沒有父親節點時
                   *tree = parent->_right;
            }
            else if (cur->_right == NULL) //2、右孩子為空
            {
                if (parent->_left == cur)
                    parent->_left = cur->_left;
                else if (parent->_right == cur)
                    parent->_right = cur->_left;
                else if (parent == cur) //沒有父親節點時
                    *tree = parent->_left;
            }
            else//3、左右孩子都不為空
            {
                BSTreeNode *sub = cur->_right;
                while (sub->_left)
                {
                    parent = sub;
                    sub = sub->_left;
                }

                del = sub;
                cur->_data = sub->_data;

                if (parent->_left == sub)
                    parent->_left = sub->_right;
                else 
                    parent->_right = sub->_right;
            }

            free(del);
            del = NULL;
            return 0;

        }
    }

    return -1;
}

遞迴程式碼實現

int BSTreeNodeDelR(BSTreeNode **tree,DataType x) //刪除
{
    if (!*tree)
        return -1;

    if ((*tree)->_data > x)
        return BSTreeNodeDelR(&(*tree)->_left,x);
    else if ((*tree)->_data < x)
        return BSTreeNodeDelR(&(*tree)->_right,x);
    else
    {
        BSTreeNode *del = *tree;
        if (!(*tree)->_left) //左為空
            *tree = (*tree)->_right;
        else if (!(*tree)->_right) //右為空
             *tree = (*tree)->_left;
        else //左右都不為空
        {
            BSTreeNode *sub = (*tree)->_right;
            while (sub->_left)
                sub = sub->_left;

            (*tree)->_data = sub->_data;
            return BSTreeNodeDelR(&(*tree)->_right,sub->_data);
        }

        free(del);
        del = NULL;
        return 0;
    }
}

完整程式碼請私信或者點此連結下載【資料結構】——搜尋二叉樹的插入,查詢和刪除(遞迴&非遞迴)

相關文章