1

私の削除がツリーを順番に (左から右へ) バランスを取り直そうとすると仮定します。

私は現在 BinarySearchTree クラスを書いていますが、ほとんどの場合、私の削除機能は現在機能しています (私は <3 を願っています)。私は対処すべきいくつかのフリンジケースを持っています:

  • 親ノードがないため、ルート ノードを削除しても機能しません。
  • next に 2 つの子がある最後のケースでは、その左端の一番右の子孫が右の子自体である場合、newCurr は next を指します。これは、newCurr (別名 next) が New と交換されるため、問題を引き起こします。

ルート削除の提案された解決策:

  1. 私の解決策は、ルートを削除し、BST クラスのメンバー関数を使用して Root を New に設定し (そのノードをルートにする)、New があった場所を 0/NULL に設定することです。

    A: これは機能しますが、ケースワークをあちこちに配置する必要があります。

  2. BST クラスにダミーの親ノードを用意します。このノードは単にルート ノードを右側のオブジェクトとして持ちます (billyswong による提案)。

    A: これでうまくいくかもしれませんが、それに対処するには特別なケースの作業が必要だと思います。

2 人の子供を削除するための提案された解決策:

  1. 私の解決策は、New の場所を一時的に保存し、親の New の場所を New の右の子に設定してから、一時ポインタを削除することです。

    A: これは機能しますが、私が思っているほどエレガントではありません。

  2. 「ノードを回転させます」(Agorが提案した方法がわからない)。

これが私のコードです:

if (root()->value() == val)
{
    delete root();
    this->setRoot(New);
    newCurr->setLeft(0);
}    
else if (newCurr == next)
{
    Node *temp = New;
    newCurr->setRight(New->right());
    delete temp;
} 

ポスターは、このコードが 1) 機能するかどうか、2) 最適かどうか教えてください。

編集:関数の終わり近くで一貫性のないキャメルキャップの使用について申し訳ありません。変数名のより良い説明は思いつきませんでしたがnew、C++ で定義されたキーワードです。

Edit2: リファクタリングされたコードを投稿しましたが、エラーは解決しません。

void BinarySearchTree::del(int val)
{
//curr refers to the parent of next
//next is the node we will want to delete
    Node* curr = 0;
    Node* next = root(); 

//these will only be used if you get into
//the last case, where you have two children
//on next
    Node* newCurr = curr;
    Node* New = next;

//boolean value to check if you found the value
//in the binary search tree
    bool found;

//set curr and next; will be false if val not found
    found = setCurrAndNext(val, curr, next);


//get next to the node needing deletion
//and set curr to its parent
//pass by ref function  
//return value is that you found it  
    if (found)
    {
        setNewCurrAndNew (newCurr, New);
    }   
    else
    { 
        return;    
    }

/* next is a leaf */

    if (nextIsLeaf(next))
    {
        handleLeafCase(curr, next);
        return;
    }   
/* next has a single child */        
    else if (nextHasSingleChild(next))       
    {
        if(leftIsChild(next))  
        {
            handleLeftCase(curr, next);
        }
        else
        {
            handleRightCase(curr, next);
        }
    }
/* next has two children */    
    else
    {  
       if (newCurr == next)
       {
            Node *temp = New;
            newCurr->setRight(New->right());
            delete temp;
       } 
       else if (next == curr->left())
       {
            if (New == newCurr->left())
            {
               curr->setLeft(New);
               newCurr->setLeft(next);
            }
            else
            {
               curr->setLeft(New);
               newCurr->setRight(next);
            }
       }
       else
       {
            if (New == newCurr->left())
            {
               curr->setRight(New);
               newCurr->setLeft(next);
            }    
            else
            {
               curr->setRight(New);
               newCurr->setRight(next);
            }
       }

       if (next->left() == 0 && next->right() == 0)
       {
            newCurr->setRight(0);
            newCurr->setLeft(0);

            delete next;
       }
       else
       {
            if (next->left() == 0)
            {
               newCurr->setRight(next->left());
            }
            else
            {
               newCurr->setLeft(next->right());
            }

               delete next;
            }
        }
    }
}
4

2 に答える 2

1

親ノードがないため、ルート ノードを削除しても機能しません。

これについての私の考えは、ルートにダミーの親、つまり実際に有用な値を含まないがルートをその正しい子として含むノードを与えることです。これで、すべての削除可能なノードがすべて親を持つようになり、root() は他のノードと同様により均一に処理できるようになります。そうすれば、ツリーも空かどうかを覚えておくための特別なメソッドは必要ありません。

編集:どのように外側をfound = setCurrAndNext(val, curr, next);設定できますか?私の知る限り、C/C++は常に値渡しです。これらのヘルパー関数に何か問題があるようです。currnext

于 2009-07-26T15:40:19.963 に答える
1

コードなどを提供することはできませんが、探しているのは「回転」演算子です。基本的に、「迷惑な」削除のケースを扱います-ルートなどの2つの子を持つツリーを削除するだけでなく、ツリー内の他のノードも削除する場合。

回転が行うことは、基本的に、非常に局所的な領域で、関連するノード間で子を交換することです (私が知っているトラウマ化)。これにより、子の順序 (左が小さく、右が大きい) が維持されます。これは、プライオリティ キューの「バブルアップ」機能に似ています。

これがウィキペディア ( http://en.wikipedia.org/wiki/Tree_rotation ) ページです。

これがあなたを正しい軌道に乗せることを願っています!

コメントに応じて編集: 申し訳ありませんが、説明する必要がありました。「ツリー」と言うときはノードを意味し、ウィキペディアのページは依然として役立つはずです。二分探索木の数学的な再帰的定義により、各ノードを独自のサブツリーとして表示できるため、私の最初のステートメントは変更されていません。しかし、それはあなたの質問に接しているだけなので、続けてください... :)

于 2009-07-26T15:47:53.193 に答える