балансировка дерева AVL (C++)

мне труднее всего понять, как сбалансировать дерево AVL для моего класса. У меня есть вставка с этим:

Node* Tree::insert(int d)
{
    cout << "base insertt" << d << endl;
    if (head == NULL)
        return (head = new Node(d));
    else
        return insert(head, d);
}

Node* Tree::insert(Node*& current, int d)
{
    cout << "insertt" << 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() проверяли, нужно ли балансировать дерево, а затем балансировать по мере необходимости. Проблема в том, что я даже не могу понять, как пройти по дереву, чтобы найти правильный неуравновешенный узел. Я знаю, как пересечь дерево рекурсивно, но я не могу перевести этот алгоритм в поиск самого низкого несбалансированный узел. У меня также проблемы с написанием итеративного алгоритма. Любая помощь будет оценена. :)

4 ответов


вы можете измерить 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);
}

теперь, когда мы знаем, как вращаться, давайте скажем, что вы хотите вставить значение в дереве... Сначала проверим, есть ли дерево is пусто или

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"
}

когда дерево не пустое, мы используем рекурсия чтобы пересечь дерево и добраться туда, где это необходимо

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 должен магазине левая / правая высота разница на каждом узле. Затем, после каждой операции (insert / remove) - вы должны убедиться, что ни один из затронутых узлов не будет слишком несбалансированным. Для этого вы делаете так называемые"вращения". Во время них вы не на самом деле повторно измерить высоту. Вам просто не нужно: каждое вращение изменяет баланс затронутых узлов на некоторое предсказуемое значение.


Гото http://code.google.com/p/self-balancing-avl-tree/, все обычные операции, такие как add, delete, реализованы, а также concat и split


закомментировано-это код, правый поворот выше и левый поворот, ниже мой рабочий правый поворот и мой рабочий левый поворот. Я думаю, что логика в вращении выше инвертирована:

 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;
}