aboutsummaryrefslogtreecommitdiff
path: root/strbst.c
blob: d30460582bc9d3321e0e7d066159dfc40264dd26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "strbst.h"
/*
strbst defines strbst with one member: strbstnode->head.
strbstnode has left, right, data, ind, and ht for avl balancing
*/
int max(int a, int b) {
    return ( (a < b) ? a : b);
}

typedef char height;

strbst* newbst(void) {
    return calloc(1,sizeof(strbst));
}

static strbstnode* newbstnode(char* ind, void* data) {
    // Doesn't insert, just allocates
    strbstnode* out = malloc(sizeof(strbstnode));
    out->ind = ind;
    out->data = data;
    out->left = out->right = NULL;
    out->ht = 0;
    return out;
}

// A nonexistent node has height of -1 so that childless nodes are ht 0.
#define getht(node) ( (node) ? node->ht : -1 )

// The basic (and only) balancing operations for AVL: rotations
// Take address of top node so that the real tree can change.
static void rightrot(strbstnode** bst) {
/*
    a         b
   / \       / \
  b   e =>  c   a
 / \           / \
c   d         d   e
*/
    strbstnode* flip = (*bst)->left->right; // flip = d
    (*bst)->left->right = *bst; // position of d = a
    *bst = (*bst)->left; // tip = b
    (*bst)->right->left = flip;
}

static void leftrot(strbstnode** bst) {
/*
  a            b
 / \          / \
e   b   =>   a   c
   / \      / \
  d   c    e   d
*/
    strbstnode* flip = (*bst)->right->left; // flip = d
    (*bst)->right->left = *bst; // position of d = a
    *bst = (*bst)->right; // tip = b
    (*bst)->left->right = flip;
}
// NOTE: These functions are valid because `b` is guaranteed in the
// conditions where the rotations are called.

static int insnode(strbstnode** bst, strbstnode* new) {
    // returns height of right node minus height of left node ("bias")
    if (!*bst) { // When an empty node is reached,
        *bst = new; // place the node
        return 0; // no children, so height difference is zero
    }
    strbstnode** node;
    if (strcmp(new->ind, (*bst)->ind) < 0) // bst < ind?
        // the address of the new node has to be taken so that node's
        // addr is not returned
        node = &((*bst)->left);
    else // assumed that new's index is not contained in tree
        node = &((*bst)->right);
    // node is the parent of the subtree which will contain new
    int heavy = insnode( node, new );
        // insert it into the subtree and get its bias
    int diff = getht((*bst)->right) - getht((*bst)->left);
    if (diff > 1) { // was originally valid (diff==1), so diff == 2
        if (heavy == -1) // if node is left heavy,
            rightrot(node); // make it right heavy. ht shouldn't change.
        leftrot(bst); // fixes, since heavy side is either right heavy
                      // or centered
    } else if (diff < -1){ // diff == -2
        if (heavy == 1)
            leftrot(node); // make left heavy
        rightrot(bst); // fix
    }
    // Calculate the current node's height
    (*bst)->ht = max( getht((*bst)->left), getht((*bst)->right) )+1;
    // And return calculated bias
    return ( getht((*bst)->right) - getht((*bst)->left) );
}

void insbst(strbst* bst, char* ind, void* data) {
    insnode(&(bst->head), newbstnode(ind, data)); // allows recursion
}

static void* querynode(strbstnode* node, char* ind){
    // tail-recursive finding algorithm
    if (!node) return NULL; // NULL => node not found
    int cmp = strcmp(ind, node->ind);
    if (cmp > 0) // ind > node->ind
        return querynode(node->right, ind);
    else if (cmp < 0) // ind < node->ind
        return querynode(node->left, ind);
    else
        return node->data; // void* data is passed back up the chain
}

void* query(strbst* bst, char* ind) {
    return querynode(bst->head, ind);
}

static void printbstnode(strbstnode* node) {
    if (!node) return;
    // Recursive printing
    if (node->right)
        printbstnode(node->right);
    if (node->left)
        printbstnode(node->left);
    // Print one line.
    // With all components, "node %s (right) %s (left) %s\n"
    printf("node %s", node->ind);
    if (node->right)
        printf(" (right) %s",node->right->ind);
    if (node->left)
        printf(" (left) %s", node->left->ind);
    printf("\n");
}

void printbst(strbst* bst) {
    printbstnode(bst->head);
}