クラスでAVLツリーのバランスをとる方法を理解するのに最も苦労しています。私はこれを挿入しています:
Node* Tree::insert(int d)
{
cout << "base insert\t" << d << endl;
if (head == NULL)
return (head = new Node(d));
else
return insert(head, d);
}
Node* Tree::insert(Node*& current, int d)
{
cout << "insert\t" << d << endl;
if (current == NULL)
current = new Node(d);
else if (d < current->data) {
insert(current->lchild, d);
if (height(current->lchild) - height(current->rchild)) {
if (d < current->lchild->getData())
rotateLeftOnce(current);
else
rotateLeftTwice(current);
}
}
else if (d > current->getData()) {
insert(current->rchild, d);
if (height(current->rchild) - height(current->lchild)) {
if (d > current->rchild->getData())
rotateRightOnce(current);
else
rotateRightTwice(current);
}
}
return current;
}
私の計画は、balance()を呼び出して、ツリーのバランスが必要かどうかを確認し、必要に応じてバランスを取ることでした。問題は、ツリーを走査して正しい不均衡なノードを見つける方法がわからないことです。私はツリーを再帰的にトラバースする方法を知っていますが、そのアルゴリズムを最も低い不平衡ノードを見つけるように変換することはできません。また、反復アルゴリズムの作成にも問題があります。任意の助けいただければ幸いです。 :)
特定のポイントでブランチのheight
を測定して、不均衡を計算できます
(高さの違いを覚えてください(レベル)> = 2は、ツリーのバランスが取れていないことを意味します)
int Tree::Height(TreeNode *node){
int left, right;
if(node==NULL)
return 0;
left = Height(node->left);
right = Height(node->right);
if(left > right)
return left+1;
else
return right+1;
}
凹凸に応じて、必要に応じて回転できます
void Tree::rotateLeftOnce(TreeNode*& node){
TreeNode *otherNode;
otherNode = node->left;
node->left = otherNode->right;
otherNode->right = node;
node = otherNode;
}
void Tree::rotateLeftTwice(TreeNode*& node){
rotateRightOnce(node->left);
rotateLeftOnce(node);
}
void Tree::rotateRightOnce(TreeNode*& node){
TreeNode *otherNode;
otherNode = node->right;
node->right = otherNode->left;
otherNode->left = node;
node = otherNode;
}
void Tree::rotateRightTwice(TreeNode*& node){
rotateLeftOnce(node->right);
rotateRightOnce(node);
}
これで回転の方法がわかったので、ツリーの値をinsertしたいとしましょう...まず、ツリーは空かどうか
TreeNode* Tree::insert(int d){
if(isEmpty()){
return (root = new TreeNode(d)); //Is empty when root = null
}
else
return insert(root, d); //step-into the tree and place "d"
}
ツリーが空でない場合、recursionを使用してツリーをトラバースし、必要な場所に到達します
TreeNode* Tree::insert(TreeNode*& node, int d_IN){
if(node == NULL) // (1) If we are at the end of the tree place the value
node = new TreeNode(d_IN);
else if(d_IN < node->d_stored){ //(2) otherwise go left if smaller
insert(node->left, d_IN);
if(Height(node->left) - Height(node->right) == 2){
if(d_IN < node->left->d_stored)
rotateLeftOnce(node);
else
rotateLeftTwice(node);
}
}
else if(d_IN > node->d_stored){ // (3) otherwise go right if bigger
insert(node->right, d_IN);
if(Height(node->right) - Height(node->left) == 2){
if(d_IN > node->right->d_stored)
rotateRightOnce(node);
else
rotateRightTwice(node);
}
}
return node;
}
ツリーを変更するときは、常にバランス(および必要に応じてローテーションを行う)をチェックする必要があります。それは物事を複雑にするだけです...
[〜#〜]更新[〜#〜]
実装に誤りがあります。以下のコードでは、ツリーが不均衡であるかどうかを正しくチェックしていません。高さが2に等しいかどうかを確認する必要があります(したがって、アンバランスになります)。その結果、次のコード...
if (height(current->lchild) - height(current->rchild)) { ...
if (height(current->rchild) - height(current->lchild)) {...
なるはず...
if (height(current->lchild) - height(current->rchild) == 2) { ...
if (height(current->rchild) - height(current->lchild) == 2) {...
いくつかのリソース
待って、待って、待って。実際に何かを挿入するたびに、すべてのブランチの「高さ」をチェックするつもりはありませんよね?
高さを測定することは、すべてのサブブランチを横断することを意味します。手段-そのようなツリーへのすべての挿入にはO(N)がかかります。もしそうなら-あなたはそのような木を何が必要ですか?ソートされた配列を使用することもできます。これにより、O(N)挿入/削除およびO(log N)検索が行われます。
正しいAVL処理アルゴリズムはstore各ノードでの左/右の高さの差でなければなりません。次に、すべての操作(挿入/削除)の後-影響を受けるノードが過度に不均衡にならないようにする必要があります。これを行うには、いわゆる「ローテーション」を実行します。それらの間、あなたはしないでください実際に高さを再測定します。必要はありません。回転するたびに、影響を受けるノードのバランスが予測可能な値だけ変化します。
コメントアウトされたコードは、上右回転と左回転、下は私の作業中の右回転と私の作業中の左回転です。上記の回転のロジックは逆になっていると思います:
void rotateRight(Node *& n){
//Node* temp = n->right;
//n->right = temp->left;
//temp->left = n;
//n = temp;
cout << "}}}}}}}}}}}}}}}}}}}}}ROTATE RIGHT}}}}}}}}}}}}}}}}}}}}}" << endl;
Node *temp = n->left;
n->left = temp->right;
temp->right = n;
n = temp;
}
void rotateLeft(Node *& n){
//Node *temp = n->left;
//n->left = temp->right;
//temp->right = n;
//n = temp;
cout << "}}}}}}}}}}}}}}}}}}}}}ROTATE LEFT}}}}}}}}}}}}}}}}}}}}}" << endl;
Node* temp = n->right;
n->right = temp->left;
temp->left = n;
n = temp;
}
goto http://code.google.com/p/self-balancing-avl-tree/ 、追加、削除などのすべての通常の操作が実装され、さらに連結と分割