rebalance()
AVL の機能の実装に関する記事をいくつか見ました。
各挿入の後、挿入ノードの先祖のバランスをチェックする必要があります。
ということで、先祖のバランスを確認するために、挿入ノードの親を知りました。
しかし、親ポインターを使用せずにそれを行う方法は他にあるのでしょうか?
たとえば、ノード構造体:
struct Node {
int data;
struct Node *lchild, *rchild; //*parent;
};
rebalance()
AVL の機能の実装に関する記事をいくつか見ました。
各挿入の後、挿入ノードの先祖のバランスをチェックする必要があります。
ということで、先祖のバランスを確認するために、挿入ノードの親を知りました。
しかし、親ポインターを使用せずにそれを行う方法は他にあるのでしょうか?
たとえば、ノード構造体:
struct Node {
int data;
struct Node *lchild, *rchild; //*parent;
};
ツリーをたどっている間、現在のノードへのスタックを維持できます
stack<Node*> nodeStack;
新しいノードにたどり着いたら、それをスタックに追加すると、祖先が得られます。ノードの処理が終了したら、スタックからポップします。
** 編集 **
配置コメントの詳細:
struct Node {
int data;
struct Node *children, *parent
};
子を作成するときは、次のようにします。
node.children = new Node[2]; or node.children = malloc(sizeof(Node) * 2);
node.children[0].parent = node;
node.children[1].parent = node;
二重ポインター (または C++ で要求したポインターへの参照) を使用すると、親ポインターの必要性が完全になくなります。
typedef struct Node {
int value;
int height;
struct Node *left;
struct Node *right;
} Node;
int height(Node *node) {
return (node == NULL) ? -1 : node->height;
}
void insert(Node * & node, int value) {
if (node == NULL) {
node = new Node();
node->value = value;
} else if (value < node->value) {
insert(node->left, value);
if (height(node->left) - height(node->right) == 2) {
if (value < note->left->value) {
singleRotateWithLeftChild(node);
} else {
doubleRotateWithLeftChild(node);
}
}
} else if (value > node->value) {
// Symmetric case
}
node->height = 1 + max(height(node->left), height(node->right));
}
データ構造の宿題を正しく覚えていれば:
あなたがすることは、次のいずれかの int としてノード自体にバランス係数を格納することです。
insert(Node subtree) 関数はブール値を返します。これは、挿入によってサブツリーの高さが増加した場合に true になります。再帰的な insert() 呼び出しから戻ったときに、バランス ファクターを更新し、ツリーのバランスを取り直します。
これはおそらく、いくつかの例で最もよく説明されています。
現在のノードのバランス係数が-1で、右側のサブツリーに挿入していて、insert(rchild) がtrueを返す場合:
いずれかのサブツリーに挿入する場合、insert(…) はfalseを返します:
現在のノードのバランス係数が0の場合、左側のサブツリーに挿入しているため、insert(lchild) はtrueを返します。
(同様に、右側のサブツリーに挿入すると、バランス係数は 1 に変わります。)
現在のノードのバランス ファクターが-1の場合、左側のサブツリーに挿入し、insert(lchild) はtrueを返します。
バランス係数は -2 に変わります。これは、適切な回転を行ってノードのバランスを取り直す必要があることを意味します。4 つのローテーションのそれぞれがバランス ファクターに対して何を行うか、および insert(current) が何を返すかについて、空白を描いていることを認めます。うまくいけば、前の例で、ノードのバランスを十分に追跡するためのアプローチを説明できます。
私がコーディングした方法は、削除する要素をツリーで検索しているときに、トラバースする子リンク (左または右) をトラバースしたノードのスタック内のリンクに一時的に変更することです (事実上、一時的な親ポインター)。 . 次に、このスタックから各ノードをポップし、子ポインターを復元して、バランスを取り直します。
C++ エンコーディングについては、 https://github.com/wkaras/C-plus-plus-intrusive-container-templates/blob/master/avl_tree.hの remove member 関数 (現在は 882 行目) を参照してください。
C エンコーディングについては、 http://wkaras.webs.com/gen_c/cavl_impl_h.txt のマクロ呼び出し L__(remove) によって名前が生成される関数を参照してください。
親ポインタを持つことは、挿入には何の役にも立たないと思います。
一意のキーではなく、ノード ポインターによって識別されるノードを削除する場合は、おそらく親ポインターを使用した方が高速になると思います。