Member 14789769 Ответов: 2

Подсчет количества вершин в поддереве


Я написал дерево AVL, я уверен, что оно работает правильно, но мой подсчет вершин не работает для поддерева. Помогите найти ошибку.
Я считаю количество вершин только в поле: "кол".

Вот мой код:

#include <cmath>
#include <assert.h>

using namespace std;

class Node
{
public:
    int key;
    Node *left;
    Node *right;
    int height;
    int kol;
};

int max(int a, int b);

int height(Node *N){
    if(N == nullptr)
        return 0;
    return N->height;
}

int max(int a, int b){
    return (a > b)? a : b;
}

Node* newNode(int key){
    Node* node = new Node();
    node->key = key;
    node->left = nullptr;
    node->right = nullptr;
    node->height = 1;
    node->kol = 1;


    return node;
}

Node * rightRotate(Node *y){



    Node *x = y->left;
    Node *T2  = x->right;


    x->right = y;
    y->left = T2;

    if (y->left == nullptr && y->right == nullptr) y->kol = 1;
    else
    if (y->left == nullptr) y->kol = y->right->kol + 1;
    else
    if (y->right == nullptr) y->kol = y->left->kol + 1;
    else
        y->kol = y->right->kol + y->left->kol + 1;

    if (x->left == nullptr && x->right == nullptr) x->kol = 1;
    else
    if (x->left == nullptr) x->kol = x->right->kol + 1;
    else
    if (x->right == nullptr) x->kol = x->left->kol + 1;
    else
        x->kol = x->right->kol + x->left->kol + 1;



    y->height = max(height(y->left), height(y->right)) + 1;
    x->height = max(height(x->left), height(x->right)) + 1;

    return x;
}

Node * leftRotate(Node *x){

    Node *y = x->right;
    Node *T2 = y->left;

    y->left = x;
    x->right = T2;


    if (x->left == nullptr && x->right == nullptr) x->kol = 1;
    else
    if (x->left == nullptr) x->kol = x->right->kol + 1;
    else
    if (x->right == nullptr) x->kol = x->left->kol + 1;
    else
    x->kol = x->right->kol + x->left->kol + 1;

    if (y->left == nullptr && y->right == nullptr) y->kol = 1;
    else
    if (y->left == nullptr) y->kol = y->right->kol + 1;
    else
    if (y->right == nullptr) y->kol = y->left->kol + 1;
    else
    y->kol = y->right->kol + y->left->kol + 1;

    x->height = max(height(x->left), height(x->right)) + 1;
    y->height = max(height(y->left), height(y->right)) + 1;


    return y;
}

int getBalance(Node *N){
    if (N == nullptr)
        return 0;
    return height(N->left) - height(N->right);
}

Node* insert(Node* node, int key){
    if (node == nullptr)
        return (newNode(key));

    //node->kol++;
    if(key < node->key){
        node->left = insert(node->left, key);
        node->kol += 1;
    }
    else if (key > node->key){
        node->right = insert(node->right, key);
        node->kol += 1;
    }

    else {
        return node;
    }
    node->height = 1 + max(height(node->left), height(node->right));


    int balance = getBalance(node);

    //left left
    if (balance > 1 && key < node->left->key)
        return rightRotate(node);

    //right right
    if (balance < -1 && key > node->right->key)
        return leftRotate(node);

    // left right
    if (balance > 1 && key > node->left->key){
        node->left = leftRotate(node->left);
        return rightRotate(node);
    }

    //right left
    if (balance < -1 && key < node->right->key){
        node->right = rightRotate(node->right);
        return  leftRotate(node);
    }


    return node;
}

Node* minValueNode(Node* node){
    Node* current = node;

    while (current->left != nullptr)
        current = current->left;

    return  current;
}

Node* deleteNode(Node* root, int key)
{
    if (root == NULL)
        return root;

    if ( key < root->key ){
        root->left = deleteNode(root->left, key);
        root->kol--;
    }


    else if( key > root->key ){
        root->right = deleteNode(root->right, key);
        root->kol--;
    }


    else
    {

        if( (root->left == NULL) ||
            (root->right == NULL) )
        {

            Node *temp = root->left ?
                         root->left :
                         root->right;

            // No child case
            if (temp == NULL)
            {
                temp = root;
                root = NULL;
            }
            else
            {
                int t = root->kol;
//                cout << -1;
                *root = *temp;
                root->kol = t - 1;
            }

            free(temp);
        }
        else
        {

            Node* temp = minValueNode(root->right);

            root->key = temp->key;
            //root->kol = temp->kol;


            root->right = deleteNode(root->right,
                                     temp->key);
        }
    }

    // If the tree had only one node
    // then return
    if (root == NULL)
        return root;

    // STEP 2: UPDATE HEIGHT OF THE CURRENT NODE
    root->height = 1 + max(height(root->left),
                           height(root->right));

    // STEP 3: GET THE BALANCE FACTOR OF
    // THIS NODE (to check whether this
    // node became unbalanced)
    int balance = getBalance(root);

    // If this node becomes unbalanced,
    // then there are 4 cases

    // Left Left Case
    if (balance > 1 &&
        getBalance(root->left) >= 0)
        return rightRotate(root);

    // Left Right Case
    if (balance > 1 &&
        getBalance(root->left) < 0)
    {
        root->left = leftRotate(root->left);
        return rightRotate(root);
    }

    // Right Right Case
    if (balance < -1 &&
        getBalance(root->right) <= 0)
        return leftRotate(root);

    // Right Left Case
    if (balance < -1 &&
        getBalance(root->right) > 0)
    {
        root->right = rightRotate(root->right);
        return leftRotate(root);
    }

    return root;
}


void preOrder(Node* root){
    if(root != nullptr){
        preOrder(root->right);
        cout << root->key << " ";
        preOrder(root->left);

    }
}

int KMin(Node* root, int k){
    int rsize = root->right ? root->right->kol : 0;

    if (k < rsize + 1)
        return KMin(root->right, k);

    if (k > rsize + 1)
        return KMin(root->left, k - 1 - rsize);

    return root->key;


/*
    if (root){
        if (root->right) {
            if (k < root->right->kol + 1) {
                return KMin(root->right, k);
            } else if (k > root->right->kol + 1) {
                return KMin(root->left, k - root->right->kol - 1);
            } else if (k == root->right->kol + 1)
                return root->key;
        } else
        {
            if (k == 1) return root->key;
            //if (k == root->kol) cout << root->key << "\n";
            return KMin(root->left, k - 1);
        }
    }


    return -1;
*/
}

int main(){

    Node *root = NULL;

    int n = 0;
    int type = 0;
    int number = 0;

    cin >> n;

    for (int i = 0; i < n; ++i) {
        cin >> type >> number;
        //cout << type << " ";
        if (type == 1){
            root = insert(root, number);
        }
        if (type == 0){
           cout << KMin(root, number) << endl;
        }
        if (type == -1){
            root = deleteNode(root, number);
        }
    }


Что я уже пробовал:

Я написал дерево AVL, но мой подсчет вершин не работает для поддерева.

2 Ответов

Рейтинг:
2

Stefan_Lang

Прошло уже несколько десятилетий с тех пор, как я в последний раз касался кода дерева, так что, возможно, я упускаю что-то очевидное. Но:

Балансирующая часть в функции insert выглядит неправильно: вы сравниваете ключ нового узла с ключами его дочерних узлов. Но так как вы всегда следите за порядком вставок по ключам, то уже предопределено, что ключи в левой ветви всегда меньше, а ключи в правой ветви всегда больше, после вставки. Если вы пытаетесь сохранить равновесие, Почему вы смотрите на клавиши - разве вы не должны смотреть на графы?


Рейтинг:
1

Patrice T

Цитата:
Я написал дерево AVL, я уверен, что оно работает правильно, но мой подсчет вершин не работает для поддерева. Помогите найти ошибку.

Как программист, ваша задача-создавать программы без ошибок (как можно больше).
Поэтому вам нужно научиться отлаживать свой код самостоятельно, инструмент выбора - это отладчик.
-----
Ваш код ведет себя не так, как вы ожидаете, или вы не понимаете, почему !

Существует почти универсальное решение: запускайте свой код на отладчике шаг за шагом, проверяйте переменные.
Отладчик здесь, чтобы показать вам, что делает ваш код, и ваша задача-сравнить с тем, что он должен делать.
В отладчике нет никакой магии, он не знает, что должен делать ваш код, он не находит ошибок, он просто помогает вам, показывая, что происходит. Когда код не делает того, что ожидается, вы близки к ошибке.
Чтобы увидеть, что делает ваш код: просто установите точку останова и посмотрите, как работает ваш код, отладчик позволит вам выполнять строки 1 на 1 и проверять переменные по мере их выполнения.

Отладчик - Википедия, свободная энциклопедия[^]

Освоение отладки в Visual Studio 2010 - руководство для начинающих[^]
Базовая отладка с помощью Visual Studio 2010 - YouTube[^]

1.11 — отладка программы (пошаговое выполнение и останова) | выучить C++[^]

Отладчик здесь только для того, чтобы показать вам, что делает ваш код, и ваша задача-сравнить его с тем, что он должен делать.