Binary Search Tree
Written by Luka Kerr on August 12, 2018
The code for a binary search tree, written while at UNSW.
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
/**
* Handy macros for operating on a binary search tree
*/
#define left(tree) tree->left
#define right(tree) tree->right
#define key(tree) tree->key
#define val(tree) tree->key
/**
* @typedef {struct} BST: a pointer to the root node of a BST
*/
typedef struct BSTNode *BST;
/**
* @typedef {struct} BSTNode: a node in a binary search tree
* @property {key} - unique key of node
* @property {val} - value of node
* @property {BSTNode *} - pointer to left child node
* @property {BSTNode *} - pointer to right child node
*/
typedef struct BSTNode {
int key;
int val;
struct BSTNode *left;
struct BSTNode *right;
} BSTNode;
static BST deleteRootBST(BST tree);
/**
* Creates a new node with a key and a value
* @param {int} key The key of the new node
* @param {int} val The value of the new node
* @return {BSTNode *} A pointer to a new node
*/
static BSTNode *newBSTNode(int key, int val) {
BSTNode *new = malloc(sizeof(BSTNode));
assert(new != NULL);
new->key = key;
new->val = val;
new->left = NULL;
new->right = NULL;
return new;
}
/**
* Creates a new binary search tree and returns it
* @return {BST} A new binary search tree (NULL initially)
*/
BST newBST() {
return NULL;
}
/**
* Frees all memory of the given binary search tree
* @param {BST} tree The tree to free
* @return {void}
*/
void freeBST(BST tree) {
if (tree == NULL) {
return;
}
freeBST(left(tree));
freeBST(right(tree));
free(tree);
}
/**
* Inserts a new node in to the tree with a given key and value
* @param {BST} tree The tree to insert into
* @param {int} key The key of the new node
* @param {int} val The value of the new node
* @return {BST} The tree containing the inserted value
*/
BST insertBST(BST tree, int key, int val) {
if (tree == NULL) {
return newBSTNode(key, val);
} else if (key < key(tree)) {
left(tree) = insertBST(left(tree), key, val);
} else if (key > key(tree)) {
right(tree) = insertBST(right(tree), key, val);
}
return tree;
}
/**
* Checks whether a node is in a tree, given a key
* @param {int} key The key to use to search
* @param {BST} tree The tree to search
* @return {int} Returns -1 if the node doesn't exist, or
* returns the value of the node if it exists
*/
int searchBST(BST tree, int key) {
if (tree == NULL) {
return -1;
} else if (key < key(tree)) {
return searchBST(left(tree), key);
} else if (key > key(tree)) {
return searchBST(right(tree), key);
} else {
return val(tree);
}
}
/**
* Checks whether a node is in a tree, given a key
* @param {int} key The key to use to search
* @param {BST} tree The tree to search
* @return {BST} Returns NULL if the node doesn't exist, or
* returns the node if it exists
*/
static BST searchNodeBST(BST tree, int key) {
if (tree == NULL) {
return NULL;
} else if (key < key(tree)) {
return searchNodeBST(left(tree), key);
} else if (key > key(tree)) {
return searchNodeBST(right(tree), key);
}
return tree;
}
/**
* Swaps two nodes in a tree given two unique keys, given both nodes exist
* @param {BST} tree The tree to operate on
* @param {BST} k1 The first key
* @param {int} k2 The second key
* @return {void}
*/
void swapBST(BST tree, int k1, int k2) {
BST t1 = searchNodeBST(tree, k1);
BST t2 = searchNodeBST(tree, k2);
if (t1 && t2) {
int tmp = val(t1);
val(t1) = val(t2);
val(t2) = tmp;
}
}
/**
* Delete a node from a tree given a key
* @param {BST} tree The tree to operate on
* @param {int} key The key of the node to delete
* @return {BST} The tree with the node removed
*/
BST deleteBST(BST tree, int key) {
if (tree == NULL) {
return NULL;
} else if (key < key(tree)) {
left(tree) = deleteBST(left(tree), key);
} else if (key > key(tree)) {
right(tree) = deleteBST(right(tree), key);
} else {
tree = deleteRootBST(tree);
}
return tree;
}
/**
* Deletes the root node of the given tree
* @param {BST} tree The tree to operate on
* @return {BST} The tree with the root node removed
*/
static BST deleteRootBST(BST tree) {
// handle cases where both or one subtree doesn't exist
if (left(tree) == NULL && right(tree) == NULL) {
free(tree);
return NULL;
} else if (left(tree) == NULL && right(tree) != NULL) {
free(tree);
return right(tree);
} else if (left(tree) != NULL && right(tree) == NULL) {
free(tree);
return left(tree);
}
// the root node has both a left and right tree
// - find inorder successor
// - move its value to root
// - delete inorder successor node
BSTNode *parent = tree;
BSTNode *successor = right(tree);
while (left(successor) != NULL) {
parent = successor;
successor = left(successor);
}
key(tree) = key(successor);
val(tree) = val(successor);
free(successor);
if (parent == tree) {
right(parent) = NULL;
} else {
left(parent) = NULL;
}
return tree;
}