0

I'm trying to implement binary search tree operations MIN and MAX efficiently, in O(1) time. I see if BST is balanced, then these take O(lgn) in the worst-case; otherwise, O(h), where h is the height of the root of the bst, worst-case runtime. But both of them isn't efficient considering that (max/min)heap provide O(1) time to get min and max. I've tried to augment bst to get max and min in constant time, but I got doubts on it. The implementation is in C programming language:

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <math.h>
typedef struct node {
    int key;
    struct node* left, * right, * parent, * min, * max;
}augmented_bst;

augmented_bst* find_min(augmented_bst* node) {
    if (!node)
        return node;
    return node->min;
}

augmented_bst* next_larger(augmented_bst* node) {
    if (!node)
        return node;
    if (node->right)
        return node->right->min;
    
    while (node->parent && node->parent->right == node)
        node = node->parent;
    return node->parent;
}

augmented_bst* new_Node(int x) {
    augmented_bst* node = (augmented_bst*)malloc(sizeof(augmented_bst));
    assert(node != NULL);
    node->key = x;
    node->left = node->right = NULL;
    node->min = node->max = node;
    return node;
}

void insert(augmented_bst** root, int x) {
    augmented_bst* node = new_Node(x);
    if (!node)
        return;
    if (!*root)
        *root = node;
    else if ((*root)->key > node->key) {
        if ((*root)->min->key > node->key)
            (*root)->min = node;
        if (!(*root)->left) {
            (*root)->left = node;
            node->parent = *root;
        }
        else {
            insert(&(*root)->left, x);
        }
    }
    else {
        if ((*root)->max->key < node->key)
            (*root)->max = node;
        if (!(*root)->right) {
            (*root)->right = node;
            node->parent = *root;
        }
        else {
            insert(&(*root)->right, x);
        }
    }
}

augmented_bst* search_tree(augmented_bst* root, int x) {
    if (root == NULL || root->key == x)
        return root;
    if (root->key > x)
        return search_tree(root->left, x);
    return search_tree(root->right, x);
}

void TRANSPLANT(augmented_bst* root, augmented_bst* u, augmented_bst* v) {
    if (u->parent == NULL)
        root = v;
    else if (u->parent->left == u)
        u->parent->left = v;
    else
        u->parent->right = v;
    if (v != NULL)
        v->parent = u->parent;
}

void fixMin(augmented_bst** node) {
    if (!*node)
        return;
    augmented_bst* current = *node;
    while (current->parent && current->parent->left == current) {
        current->parent->min = current->min;
        current = current->parent;
    }
}

void fixMax(augmented_bst** node) {
    if (!*node)
        return;
    augmented_bst* current = node;
    while (current->parent && current->parent->right == current) {
        current->parent->max = current->max;
        current = current->parent;
    }
}

void DELETE(augmented_bst** root, int x) {
    augmented_bst* node = search_tree(*root, x);
    assert(node != NULL);
    if (!node->right) {
        TRANSPLANT(*root, node, node->left);
        fixMin(&node);
    }
    else if (!node->left) {
        TRANSPLANT(*root, node, node->right);
        fixMax(&node);
    }
    else {
        augmented_bst* temp = next_larger(node);
        if (node->right != temp) {
            TRANSPLANT(*root, temp, temp->right);
            fixMin(&temp->right);
            temp->right = node->right;
            temp->right->parent = temp;
            temp->max = node->right->max;
        
        }
        TRANSPLANT(*root, node, temp);
        fixMax(&temp);
        temp->left = node->left;
        temp->left->parent = temp;
        temp->min = temp->left->min;
    }
}

NOTES: some procedures in the code is take from CLRS. I put whole implementation thinking someone might need it. My problem is with the DELETE procedure, but you can suggest anything about other parts of the code. If you think this can be done in better way, please state it. I used fixMin and fixMax functions four times inside DELETE procedure. Can we do it better? If yes, how? Is there a better (or different) way to implement DELETE procedure? I appreciate your answers and am open to any suggestions about anything.

Alparslan
  • 35
  • 6
  • 1
    Unless you have a problem getting it to work, it should go on Code Review. – 500 - Internal Server Error Mar 11 '21 at 09:58
  • My 2¢: when I augment a tree with a synthesized attribute (function of children and other fields of self), I invariably wrap assignments to `left` and `right` in a function. In this case, `set_left` would set the left child and update `min` and the child's `parent`, while `set_right` would set the right child and update `max` and the child's `parent`. The compiler will inline these on any reasonable setting. – David Eisenstat Mar 11 '21 at 12:48
  • (1/2) On the other hand, for this specific attribute, I'd actually be inclined to either 1. store min and max at the root only and handle deletion using the O(h)-time algorithm, thus avoiding the space overheads; or 2. replace the `min` and `max` fields with `prev` and `next` to form a doubly linked list in sorted order. This list should have a sentinel and be circularly linked. Then deletion is really easy (from the deleted node, set `prev->next = next;` and `next->prev = prev;`). – David Eisenstat Mar 11 '21 at 12:57
  • (2/2) For insertion, initialize `prev` and `next` to the sentinel node on descent. Whenever the new value compares greater than a node, update `prev` to that node. Whenever the new value compares less than a node, update `next` to that node. Splice in the new node by setting `node->prev = prev; node->next = next; prev->next = node; next->prev = node;`. The min and max are the `next` and `prev` respectively of the sentinel. – David Eisenstat Mar 11 '21 at 12:57

0 Answers0