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
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#pragma pack(1)  // Tell compiler not to padding between struct fields

/********************************************************************
|* SEE iterative_tree_traversals.c.  It is the 3:00 PM with some improvements
|* for clarity made later.
|*
|* This is the 1:30pm version.
\*/

typedef struct _BSTNode {
    int value;                //  =4 bytes¹
    struct _BSTNode* left;    //  =8 bytes¹
    struct _BSTNode* right;   //  =8 bytes¹
} BSTNode;                    // =20 bytes¹

typedef struct _StackNode {
    BSTNode* value;
    struct _StackNode* next;
} StackNode;

void stack_push(StackNode** a_top, BSTNode* value) {
    StackNode* new_top = malloc(sizeof(*new_top));
    *new_top = (StackNode) { .next = NULL, .value = value };  // Compound literal
    if(*a_top != NULL) {  // If stack is not initially empty...
        new_top -> next = *a_top;   // make the new top refer to the existing top
    }
    *a_top = new_top; // new top becomes the top of the stack
    assert(*a_top != NULL);  // Just added something, so can't possibly be empty now.
    assert((*a_top) -> value == value);  // Top should have the character we just pushed.
}

BSTNode* stack_pop(StackNode** a_top) {  // Usage:  Must not be called with an empty stack.
    StackNode* old_top = *a_top;
    BSTNode* value = old_top -> value;
    *a_top = old_top -> next;
    free(old_top);
    return value;
}

bool stack_is_empty(StackNode* top) {
    return (top == NULL);
}

void insert(int value, BSTNode** a_root) {
    // If tree is empty, then insert the value as the root of this tree.
    if(*a_root == NULL) {
        // CREATE new node
        BSTNode* new_node = malloc(sizeof(*new_node));
        *new_node = (BSTNode) { .value = value, .left = NULL, .right = NULL };

        // CONNECT new node to the tree
        *a_root = new_node;
    }
    // Otherwise, insert in either the left or right subtree, depending on the value.
    else if(value < (*a_root) -> value) {
        insert(value, &((*a_root) -> left));
    }
    else if(value >= (*a_root) -> value) {
        insert(value, &((*a_root) -> right));
    }
}

void print_tree_in_order(BSTNode* root) {  // IN-ORDER traversal:  left, root, right
    StackNode* top = NULL;  // create empty stack
    BSTNode* curr = root;
    while(curr != NULL || top != NULL) {
        if(curr != NULL) {
            stack_push(&top, curr);  // ex: "Push the 4 node"
            curr = curr -> left;     // ex: "Go to its left subtree"
        }
        else {
            curr = stack_pop(&top);  // ex: "Pop gives us the 1 node"
            printf("curr -> value == %d\n", curr -> value);  // "Print the '1'"
            curr = curr -> right;    // ex: Will lead to pushing the right next time.
        }
    }
}

void print_tree_pre_order(BSTNode* root) {  // PRE-ORDER traversal:  root, left, right
    if(root != NULL) {
        StackNode* top = NULL;  // create empty stack
        stack_push(&top, root);
        while(top != NULL) {
            BSTNode* curr = stack_pop(&top);
            if(curr != NULL) {
                printf("curr -> value == %d\n", curr -> value);
                stack_push(&top, curr -> right);
                stack_push(&top, curr -> left);
            }
        }
    }
}

void destroy_tree(BSTNode** a_root) {  // 
    if(*a_root != NULL) {
        destroy_tree(&((*a_root) -> left));
        assert((*a_root) -> left == NULL);  // left subtree has been destroyed and is empty
        destroy_tree(&((*a_root) -> right));
        assert((*a_root) -> right == NULL);

        free(*a_root);   // deallocate
        *a_root = NULL;  // set to NULL to indicate that it is empty
    }
    assert(*a_root == NULL); // Tree must be empty
}

int main(int argc, char* argv[]) {
    // Empty list
    BSTNode* root = NULL;

    // Insert a value
    insert(4, &root);
    insert(2, &root);
    insert(6, &root);
    insert(1, &root);
    insert(3, &root);
    insert(5, &root);
    insert(7, &root);

    // Print
    //print_tree_in_order(root);
    print_tree_pre_order(root);

    // Free
    destroy_tree(&root);

    return EXIT_SUCCESS;
}
/* vim: set tabstop=4 shiftwidth=4 fileencoding=utf-8 noexpandtab: */

© Copyright 2023 Alexander J. Quinn         This content is protected and may not be shared, uploaded, or distributed.