Какова лучшая структура данных для выполнения следующих запросов и почему я получаю неправильный результат в моем - PullRequest
1 голос
/ 09 февраля 2020

Мне нужно построить структуру данных, которая:

  1. выучить x (вставить x)
  2. забыть x (удаляет x). если x отсутствует, ничего не делать
  3. уменьшить xn - уменьшить счетчик x на n, если n> = count, то узел просто удаляется. и если x не присутствует, то ничего не делать
  4. less_nums x - найти количество узлов (с учетом их кратности), которые меньше x
  5. больший_nums x - аналогично 4., но больше
  6. как c k - вывести k-й элемент в порядке возрастания (с учетом кратности), вывести -1, если k> общее количество узлов

1≤ q ≤ 5 * 10 ^ 5

1≤ x ≤ 10 ^ 9

Я построил дерево AVL для этого, есть ли лучшая и простая структура данных для этого?

Мой код работает нормально для заданные входные и выходные данные:

Input:
14
learn 5
learn 2
learn 7
learn 3
learn 2
smaller_nums 5 
larger_nums 2 
asc 2
decrease 2 1 
asc 2
forget 7 
larger_nums 2 
forget 5 
larger_nums 2
Output: 
3
3
2
3 
2
1

Когда я отправляю, я прохожу 4/9 контрольных примеров. Я получаю неправильный ответ для 2 тестовых случаев и время ожидания для 3 тестовых случаев.

#include <stdio.h>
#include <stdlib.h>
long int N=0; //keeps count of total number nodes, this value is used in asc function only
// An AVL tree node
struct node {
    long int key;
    struct node* left;
    struct node* right;
    long int height;
    long int count;
};

// A utility function to get height of the tree
long int height(struct node* N)
{
    if (N == NULL)
        return 0;
    return N->height;
}

// A utility function to get maximum of two integers
long int max(long int a, long int b)
{
    return (a > b) ? a : b;
}

/* Helper function that allocates a new node with the given key and
    NULL left and right pointers. */
struct node* newNode(long int key)
{
    struct node* node = (struct node*)
        malloc(sizeof(struct node));
    node->key = key;
    node->left = NULL;
    node->right = NULL;
    node->height = 1; // new node is initially added at leaf
    node->count = 1;
    return (node);
}

// A utility function to right rotate subtree rooted with y
// See the diagram given above.
struct node* rightRotate(struct node* y)
{
    struct node* x = y->left;
    struct node* T2 = x->right;

    // Perform rotation
    x->right = y;
    y->left = T2;

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

    // Return new root
    return x;
}

// A utility function to left rotate subtree rooted with x
// See the diagram given above.
struct node* leftRotate(struct node* x)
{
    struct node* y = x->right;
    struct node* T2 = y->left;

    // Perform rotation
    y->left = x;
    x->right = T2;

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

    // Return new root
    return y;
}

// Get Balance factor of node N
long int getBalance(struct node* N)
{
    if (N == NULL)
        return 0;
    return height(N->left) - height(N->right);
}

struct node* insert(struct node* node, long int key)
{
    /* 1. Perform the normal BST rotation */
    if (node == NULL)
    {   N++;
        return (newNode(key));
    }
    // If key already exists in BST, increment count and return
    if (key == node->key) {
        (node->count)++;
        N++;
        return node;
    }

    /* Otherwise, recur down the tree */
    if (key < node->key)
        node->left = insert(node->left, key);
    else
        node->right = insert(node->right, key);

    /* 2. Update height of this ancestor node */
    node->height = max(height(node->left), height(node->right)) + 1;

    /* 3. Get the balance factor of this ancestor node to check whether
    this node became unbalanced */
    long int balance = getBalance(node);

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

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

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

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

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

    /* return the (unchanged) node pointer */
    return node;
}

/* Given a non-empty binary search tree, return the node with minimum
key value found in that tree. Note that the entire tree does not
need to be searched. */
struct node* minValueNode(struct node* node)
{
    struct node* current = node;

    /* loop down to find the leftmost leaf */
    while (current->left != NULL)
        current = current->left;

    return current;
}
struct node* forgetNode(struct node* root, long int key)
{
    // STEP 1: PERFORM STANDARD BST DELETE

    if (root == NULL)
        return root;

    // If the key to be deleted is smaller than the root's key,
    // then it lies in left subtree
    if (key < root->key)
        root->left = forgetNode(root->left, key);

    // If the key to be deleted is greater than the root's key,
    // then it lies in right subtree
    else if (key > root->key)
        root->right = forgetNode(root->right, key);

    // if key is same as root's key, then This is the node
    // to be deleted
    else {
        N += -(root->count);
        // If key is present more than once, simply decrement
        // count and return
        // Else, delete the node

        // node with only one child or no child
        if ((root->left == NULL) || (root->right == NULL)) {
            struct node* temp = root->left ? root->left : root->right;

            // No child case
            if (temp == NULL) {
                temp = root;
                root = NULL;
            }
            else // One child case
                *root = *temp; // Copy the contents of the non-empty child

            free(temp);
        }
        else {
            // node with two children: Get the inorder successor (smallest
            // in the right subtree)
            struct node* temp = minValueNode(root->right);

            // Copy the inorder successor's data to this node and update the count
            root->key = temp->key;
            root->count = temp->count;
            temp->count = 1;

            // Delete the inorder successor
            root->right = forgetNode(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 = max(height(root->left), height(root->right)) + 1;

    // STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to check whether
    // this node became unbalanced)
    long 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;
}

struct node* decreaseNode(struct node* root, long int key, long int n)
{
    // STEP 1: PERFORM STANDARD BST DELETE

    if (root == NULL)
        return root;

    // If the key to be deleted is smaller than the root's key,
    // then it lies in left subtree
    if (key < root->key)
        root->left = decreaseNode(root->left, key, n);

    // If the key to be deleted is greater than the root's key,
    // then it lies in right subtree
    else if (key > root->key)
        root->right = decreaseNode(root->right, key, n);

    // if key is same as root's key, then This is the node
    // to be deleted
    else {

        // If key is present more than once, simply decrement
        // count and return
        if (root->count > 1 && n < root->count) {
            (root->count) += -n;
            N += -n;
            return root;
        }
        // Else, delete the node

        // node with only one child or no child
        N += -(root->count);
        if ((root->left == NULL) || (root->right == NULL)) {
            struct node* temp = root->left ? root->left : root->right;

            // No child case
            if (temp == NULL) {
                temp = root;
                root = NULL;
            }
            else // One child case
                *root = *temp; // Copy the contents of the non-empty child

            free(temp);
        }
        else {
            // node with two children: Get the inorder successor (smallest
            // in the right subtree)
            struct node* temp = minValueNode(root->right);

            // Copy the inorder successor's data to this node and update the count
            root->key = temp->key;
            root->count = temp->count;
            temp->count = 1;

            // Delete the inorder successor
            root->right = decreaseNode(root->right, temp->key, n);
        }
    }

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

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

    // STEP 3: GET THE BALANCE FACTOR OF THIS NODE (to check whether
    // this node became unbalanced)
    long 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;
}
// Convinience function to travers the tree in ascending order
void inOrder(struct node* root)
{
    if (root != NULL) {
        inOrder(root->left);
        printf("%ld(%ld) ", root->key, root->count);
        inOrder(root->right);
    }
}
// Find out number of larger nodes
void largerNums(struct node* root, long int key, long int* lnums){
    if (root == NULL)
        return;

    if (key < root->key){
        (*lnums) += root->count;
        largerNums(root->right, key, lnums);
        largerNums(root->left, key, lnums);
    }
    else if (key >= root->key)
        largerNums(root->right, key, lnums);

    return;
}
// Find out number of smaller nodes
void smallerNums(struct node* root, long int key, long int* snums){
    if (root == NULL)
        return;

    if (key <= root->key){
        smallerNums(root->left, key, snums);
    }
    else if (key > root->key){
        (*snums) += root->count;
        smallerNums(root->left, key, snums);
        smallerNums(root->right, key, snums);
    }
    return;

}
// Prints k'th element in ascending order
void asc(struct node* root, long int key, long int* cnt){

    if (root != NULL) {
        asc(root->left, key, cnt);
        int i;
        for(i=1; i <= (root->count); ++i){
            (*cnt)++;
            if(*cnt == key){
                printf("%ld\n", root->key);
                return;
            }
        }
        asc(root->right, key, cnt);
    }

}
// Function to compare strings
int myStrCompare(char a[], char b[]){
   int c = 0;

   while (a[c] == b[c]) {
      if (a[c] == '\0' || b[c] == '\0')
         break;
      c++;
   }

   if (a[c] == '\0' && b[c] == '\0')
      return 0;
   else
      return -1;
}
// Function to know what command entered by user
int myCompare(char *str){

    if(myStrCompare(str, "learn") == 0)
        return 1;
    else if(myStrCompare(str, "forget") == 0)
        return 2;
    else if(myStrCompare(str, "decrease") == 0)
        return 3;
    else if(myStrCompare(str, "smaller_nums") == 0)
        return 4;
    else if(myStrCompare(str, "larger_nums") == 0)
        return 5;
    else if(myStrCompare(str, "asc") == 0)
        return 6;

    return -1;
}

/* Driver program to test above function*/
int main()
{
    long int i, q, x, n, lnums, snums, cnt;
    int choice;
    char input[100];
    struct node* root= NULL;

    scanf("%ld", &q);
    //printf("%s", input);

    for(i=1; i<=q; ++i){
        scanf("%s", input);
        //printf("%s", input);
        choice = myCompare(input);
        //printf("\n%d", choice);

        switch(choice){
            case 1: scanf("%ld", &x);
                //printf("\nEntered x\n: %d", x);
                root = insert(root, x);
               /* printf("\n");
                inOrder(root);
                printf("\n");*/
                break;
            case 2: scanf("%ld", &x);
                //printf("\nEntered x\n: %d", x);
                root = forgetNode(root, x);
                /*printf("\n");
                inOrder(root);
                printf("\n");*/
                break;
            case 3: scanf("%ld%ld", &x, &n);
                //printf("\nEntered x\n: %d", x);
                if(n < 1){
                    break;
                }else{
                    root = decreaseNode(root, x, n);
                }
               /* printf("\n");
                inOrder(root);
                printf("\n");*/
                break;
            case 4: scanf("%ld", &x);
                //printf("\nEntered x\n: %d", x);
                snums = 0;
                smallerNums(root, x, &snums);
                /*printf("\n");
                inOrder(root);
                printf("\n");*/
                printf("%ld\n", snums);
                break;
            case 5: scanf("%ld", &x);
                //printf("\nEntered x\n: %d", x);
                lnums = 0;
                largerNums(root, x, &lnums);
                /*printf("\n");
                inOrder(root);
                printf("\n");*/
                printf("%ld\n", lnums);
                break;
            case 6: scanf("%ld", &x);
                if(x > N){
                    printf("%d\n", -1);
                    break;
                }else{
                //printf("\nEntered x\n: %d", x);
                    cnt=0;
                    asc(root, x, &cnt);
                }
                /*printf("\n");
                inOrder(root);
                printf("\n");*/
                break;

        }
    }
    /*root = insert(root, 5);
    root = insert(root, 2);
    root = insert(root, 7);
    root = insert(root, 3);
    root = insert(root, 2);
    smallerNums(root, 5, &s);
    printf("\n%d\n", s);
    largerNums(root, 2, &l);
    printf("%d\n", l);
    inOrderK(root, 2, &cnt); cnt = 0;
    root = decreaseNode(root, 2, 1);
    inOrderK(root, 2, &cnt); cnt = 0;
    root = forgetNode(root, 7);
    l=0;
    largerNums(root, 2, &l);
    printf("%d\n", l);
    root = forgetNode(root, 5);
    l=0;
    largerNums(root, 2, &l);
    printf("%d\n", l);
    inOrder(root);
    l=0;
    largerNums(root, 1, &l);
    printf("\n%d\n", l);
    */


    return 0;
}

Я просматривал свой код несколько раз и не смог выяснить, в чем дело

1 Ответ

0 голосов
/ 11 февраля 2020

Попробуйте сделать это в log (n) раз. Поместите left_count и right_count в узел

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...