Why so mainstream? the spinoff

Revision en4, by DanAlex, 2016-03-21 05:02:42

An intro would be also be kind of mainstream, but I'll still be...

Cutting to the chase

Rotations and balancing are kind of boring, but invariants are not. The nice thing about in looking for different solutions for the same problem is that you can find elegance in each of them. Maybe more importantly, it helps you develop backups when the first solution fails.

It is just the fact that sometimes to sell and start over is the right call. Of course, starting off with a small amount of one million dollars would do(couldn't help myself, people keep saying orange is the new black(now seriously: I say Donald, you say... Knuth))

Binary search tree

The problems is to implement the basic operations of a (STL's)set: * Insert * Delete * Search * Lower bound * Upper bound And so on...

The obvious slow solution is as always a list. We will try to improve it and blah, blah, blah. This is not helpful at all.

The lower and upper bounds keeps our attention. For those to be executed we need an order. A hash or whatever structure that keeps things unsorted is really hard to manage around this operation. Is the structure was static, binary search would have done the job.

From this point, I see some approaches: * leave gaps in a static structure * work with chunks of data * try to link data differently * work around binary search and make a structure that does it dynamically(that goes to BST)

I will focus on the last one, but all of them lead to interesting stuff. You can try to look up skiplists, for example.

Now, how binary works is that it looks first at the middle and then at another middle and so on. What if our structure does the exact same thing? If you draw a decision tree for a binary search, the thing that happens is that you put the middle in the top, then the middle of the left interval in left, the middle of the right interval in right and so on.

The cool things that we observe here are that: * the tree is balanced * all element in the left of a node are smaller that node and those in the right bigger

The BST is a binary tree that respects the second property.

Finding a structure that respects this property is not that hard(for example an ordered list works), but the thing that makes the decision tree above is the so called balance. Firstly, let's look why BST operations work good on average case and then try to add more invariants to make the structures good every time.

Searching

The search is straight forward. We look is the current node is what we are looking for, otherwise look in which part should we go. Here is some (stolen)code just to be clear:

void search(Node node, int value) {
    if (!node || node.value == value) {
        return node;
    } else {
        if (node.value > value) {
            return search(node.left, value);
        } else {
            return search(node.right, value);
        }
    }
}

Insert

Insertion goes just as the search. When we reach a null value, we insert a new node in the tree.

Node* insert(Node* node, int value) {
    if (!node) {
        return new Node(value);
    } else if (key < node->value) {
        node->left = insert(node->left, value);
    } else  
        node->right = insert(node->right, value);
    }
}

The reason we used a pointer for the node is that we want to actually modify the reference from the father of the new inserted leaf.

Delete

First search the tree to find the node that we have to delete. Now we have just to tackle the case when we have to delete the root. We need a node that we can put as a the new root. That is the biggest element from the left subtree. This is the rightmost element of the left subtree.

def binary_tree_delete(self, key):
    if key < self.key:
        self.left_child.binary_tree_delete(key)
    elif key > self.key:
        self.right_child.binary_tree_delete(key)
    else: # delete the key here
        if self.left_child and self.right_child: # if both children are present
            successor = self.right_child.find_min()
            self.key = successor.key
            successor.binary_tree_delete(successor.key)
        elif self.left_child:   # if the node has only a *left* child
            self.replace_node_in_parent(self.left_child)
        elif self.right_child:  # if the node has only a *right* child
            self.replace_node_in_parent(self.right_child)
        else: # this node has no children
            self.replace_node_in_parent(None)

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en19 English DanAlex 2017-08-08 03:32:22 7 Tiny change: 'n[cut]\n\nBinary' -> 'n[cut]\n\n\nBinary'
en18 English DanAlex 2017-08-08 03:27:34 9 Tiny change: 'uth)) \n\nBinary' -> 'uth)) \n\n[cut]\n\nBinary'
en17 English DanAlex 2016-03-22 03:06:15 106
en16 English DanAlex 2016-03-21 06:23:59 11 Tiny change: 'tree. \n\nPS \n----\n\nIn fac' -> 'tree. \n\n#### PS \n\nIn fac'
en15 English DanAlex 2016-03-21 06:23:38 3 Tiny change: 'ee. \n\nPS\n--\n\nIn f' -> 'ee. \n\nPS \n----\n\nIn f'
en14 English DanAlex 2016-03-21 06:23:12 0 Tiny change: '. \n\nPS\n--\n\nIn fac' -> '. \n\nPS\n\nIn fac'
en13 English DanAlex 2016-03-21 06:22:37 372 (published)
en12 English DanAlex 2016-03-21 06:19:25 364 Tiny change: ' a $O(log N)$ compl' -
en11 English DanAlex 2016-03-21 06:08:52 511
en10 English DanAlex 2016-03-21 05:50:57 978
en9 English DanAlex 2016-03-21 05:32:35 22
en8 English DanAlex 2016-03-21 05:32:05 4
en7 English DanAlex 2016-03-21 05:31:52 10
en6 English DanAlex 2016-03-21 05:31:16 212
en5 English DanAlex 2016-03-21 05:28:55 1836
en4 English DanAlex 2016-03-21 05:02:42 1261
en3 English DanAlex 2016-03-21 04:54:51 538
en2 English DanAlex 2016-03-21 04:31:22 2421
en1 English DanAlex 2016-03-21 03:44:36 692 Initial revision (saved to drafts)