溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

如何實(shí)現(xiàn)二叉查找樹(shù)

發(fā)布時(shí)間:2021-10-21 11:12:40 來(lái)源:億速云 閱讀:158 作者:小新 欄目:編程語(yǔ)言

小編給大家分享一下如何實(shí)現(xiàn)二叉查找樹(shù),相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

        二叉查找樹(shù)又叫二叉排序樹(shù),其特點(diǎn)有:

  1. 對(duì)于每一棵子樹(shù),若左子樹(shù)不為NULL,則左子樹(shù)所有節(jié)點(diǎn)都小于它的根結(jié)點(diǎn)值。

  2. 對(duì)于每一棵子樹(shù),若右子樹(shù)不為NULL,則左子樹(shù)所有節(jié)點(diǎn)都大于它的根結(jié)點(diǎn)值。

  3. 沒(méi)有鍵值相等的結(jié)點(diǎn)。

完成二叉查找樹(shù)的基本操作有:

  1. 插入結(jié)點(diǎn)。

  2. 查找結(jié)點(diǎn)。

  3. 查找最小關(guān)鍵字:根據(jù)二叉查找樹(shù)的特點(diǎn),應(yīng)該是最左邊的結(jié)點(diǎn)

  4. 查找最大關(guān)鍵字:根據(jù)二叉查找樹(shù)的特點(diǎn),應(yīng)該是最右邊的結(jié)點(diǎn)

  5. 刪除結(jié)點(diǎn)。

以上操作中,難點(diǎn)在與插入和刪除。分別說(shuō)下其主要思想:

插入:根據(jù)插入數(shù)據(jù)與結(jié)點(diǎn)的比較,找尋它的插入位置,若比結(jié)點(diǎn)值大,則往結(jié)點(diǎn)的右子樹(shù)繼續(xù)尋找,直到其右孩子為空,將新結(jié)點(diǎn)作為其右孩子;若比結(jié)點(diǎn)值小,則往結(jié)點(diǎn)的左子樹(shù)繼續(xù)尋找,直到其左孩子為空,將新結(jié)點(diǎn)作為其左孩子。

刪除:設(shè)要查找的結(jié)點(diǎn)為d

  1. 若d有左子樹(shù),則用d的左孩子取代它,找到其左子樹(shù)的最右邊的結(jié)點(diǎn)r,把f的右孩子作為r的右子樹(shù)。

  2. 若d無(wú)左子樹(shù),則直接用它的右孩子取代它。

但執(zhí)行刪除操作時(shí)要注意要?jiǎng)h除的結(jié)點(diǎn)是否是幾個(gè)特殊的結(jié)點(diǎn):空結(jié)點(diǎn)、根結(jié)點(diǎn)、葉子節(jié)點(diǎn)。

代碼示例:

//插入結(jié)點(diǎn)
//查找元素
//查找最小關(guān)鍵字
//查找最大關(guān)鍵字
//刪除節(jié)點(diǎn)
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
    int data;
    struct Node* lchild;
    struct Node* rchild;
    struct Node* parent;
}Node;
//往二叉查找樹(shù)中插入結(jié)點(diǎn)  
//插入的話(huà),可能要改變根結(jié)點(diǎn)的地址,所以傳的是二級(jí)指針  
void insert_node(Node** root,int _data)
{
    Node* newnode=(Node*)malloc(1*sizeof(Node));
    newnode->data=_data;
    newnode->lchild=NULL;
    newnode->rchild=NULL;
    newnode->parent=NULL;
    if(*root==NULL)
    {
        *root=newnode;
        return ;
    }
    if((*root)->lchild==NULL && _data < (*root)->data)
    {
        (*root)->lchild=newnode;
        newnode->parent=*root;
        return ;
    }
    if((*root)->rchild==NULL && _data > (*root)->data)
    {
        (*root)->rchild=newnode;
        newnode->parent=*root;
        return ;
    }
    if( _data < (*root)->data )
    {
        insert_node(&(*root)->lchild,_data);
    }
    else
    {
        if( _data > (*root)->data)
        {
            insert_node(&(*root)->rchild,_data);
        }
        else
        {
            return ;
        }
    }
}
//輸出節(jié)點(diǎn)元素
void print_tree(Node* root)
{
    if(root==NULL)
        return ;
    printf("%d\t",root->data);
    print_tree(root->lchild);
    print_tree(root->rchild);
}
//查找元素,找到返回關(guān)鍵字的結(jié)點(diǎn)指針,沒(méi)找到返回NULL  
Node* find_node(Node* root,int _data)
{
    if(root==NULL || ( _data == root->data))
    {
        return root;
    }
    if( _data < root->data )
    {
        return find_node(root->lchild,_data);
    }
    if(_data > root->data)
    {
        return find_node(root->rchild,_data);
    }
}
//查找最小關(guān)鍵字,空樹(shù)時(shí)返回NULL  
Node* search_min(Node* root)
{
    if(root==NULL)
    {
        return NULL;
    }
    if(root->lchild==NULL)
    {
        return root;
    }
    search_min(root->lchild);
}
//查找最大關(guān)鍵字
Node* search_max(Node* root)
{
    if(root==NULL)
    {
        return NULL;
    }
    if(root->rchild==NULL)
    {
        return root;
    }
    search_max(root->rchild);
}
//根據(jù)關(guān)鍵字刪除某個(gè)結(jié)點(diǎn),刪除成功返回1,否則返回0  如果把根結(jié)點(diǎn)刪掉,那么要改變根結(jié)點(diǎn)的地址,所以傳二級(jí)指針
/*思想: 1。若p有左子樹(shù),p的左孩子取代它;找到其左子樹(shù)的最右邊的葉子結(jié)點(diǎn)r,把p的右子樹(shù)作為r的右子樹(shù)。
 2。若p沒(méi)有左子樹(shù),直接用p的右孩子取代它。
*/
void delete_node(Node** root,int _data)
{
    if(root==NULL)
        return ;
    Node* dnode=find_node(*root,_data);
    if(dnode==NULL)
    {
        return ;
    }
    if(dnode->lchild==NULL && dnode->rchild==NULL && dnode!=*root)
    {
        if(dnode->parent->lchild==dnode)
        {
            dnode->parent->lchild=NULL;
        }
        if(dnode->parent->rchild==dnode)
        {
            dnode->parent->rchild=NULL;
        }
        free(dnode);
        dnode=NULL;
        return ;
    }
    //如沒(méi)有左子樹(shù)
    if(dnode->lchild==NULL)
    {
        //若這個(gè)節(jié)點(diǎn)是根節(jié)點(diǎn)
        if(dnode==*root)
        {
            *root=(*root)->rchild;
            (*root)->parent=NULL;
            free(dnode);
            return ;
        }
        //若這個(gè)節(jié)點(diǎn)是父節(jié)點(diǎn)的左孩子
        if(dnode->parent->lchild==dnode)
        {
            dnode->parent->lchild=dnode->rchild;
            dnode->rchild->parent=dnode->parent;
            free(dnode);
            return ;
        }
        //若這個(gè)節(jié)點(diǎn)是父節(jié)點(diǎn)的右孩子
        if(dnode->parent->rchild==dnode)
        {
            dnode->parent->rchild=dnode->rchild;
            dnode->rchild->parent=dnode->parent;
            free(dnode);
            return ;
        }
    }
    if(dnode->lchild!=NULL)
    {
    //找到其左子樹(shù)的最右邊的葉子結(jié)點(diǎn)r,把p的右子樹(shù)作為r的右子樹(shù)。
        Node* r=dnode->lchild;
        while(r->rchild!=NULL)
        {
            r=r->rchild;
        }
        r->rchild=dnode->rchild;
        dnode->rchild->parent=r->rchild;
        //用dnode的左節(jié)點(diǎn)來(lái)取代ta
        if(dnode==*root)
        {
            *root=dnode->lchild;
            (*root)->parent=NULL;    
        }
        else
        {
            if(dnode->parent->lchild==dnode)
            {
                dnode->parent->lchild=dnode->lchild;
                dnode->lchild->parent=dnode->parent;
            }
            if(dnode->parent->rchild==dnode)
            {
                dnode->parent->rchild=dnode->lchild;
                dnode->lchild->parent=dnode->parent;
            }
        }
        free(dnode);
        dnode=NULL;
    }
}
int main(int argc, char const *argv[])
{
    Node* root=NULL;
    insert_node(&root,15);
    insert_node(&root,6);
    insert_node(&root,18);
    insert_node(&root,3);
    insert_node(&root,7);
    insert_node(&root,17);
    insert_node(&root,20);
    
    print_tree(root);
    printf("\n");
    Node* f=find_node(root,6);
    if(f!=NULL)
    {
        printf("%d\n",f->parent->data);
    }
    delete_node(&root,3);
    print_tree(root);
    printf("\n");
    return 0;
}

以上是“如何實(shí)現(xiàn)二叉查找樹(shù)”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI