You are on page 1of 7

Binary Search Tree in C Language

This program is creating binary trees and showing the use of memory
allocation and deallocation.

#include <stddef.h>
#include <unistd.h>
#include <string.h>

/**
* As suggested, two binary search trees are used to organize the free
blocks.
*/
struct tnode { /* a tree node */
struct tnode *left, *right;

/* either the size of the block


* or the starting address of the corresponding header */
size_t value;
};

/* every allocated data block has a header before the returned address
* to store the meta data of this block,
* which includes the binary seach tree nodes */
struct header {
struct tnode nodes[2];
};

static struct tnode *trees[2];

/* binary search tree functions */

/* insert/remove the header in the binary search tree (*node) */


static struct tnode *insert_tree(struct tnode *node, struct tnode *h);
static struct tnode *remove_tree(struct tnode *node, struct tnode *h);

/* try to merge free blocks with continous space using the space
binary tree */
static struct tnode *merge(struct tnode *node);

/* a macro to get the header address before the data block */


#define HEADER(ptr) ((struct header *)((char *)(ptr) - sizeof(struct
header)))

#define CONTINUOUS(h1, h2) ((char *)(h1) + sizeof(struct header) +


(h1)->nodes[0].value == (char *)(h2))

static struct header *allocate_block(size_t size);


static void release_block(struct header *h);

void *malloc(size_t size)


{
/* allocate a free block and return its address for data section
*/
struct header *h = allocate_block(size);
if (h != NULL) {
return (char *)h + sizeof(struct header);
}
return NULL;
}

/*
* free the allocated the memory space.
* Assume the ptr is a valid space allocated before using the malloc()
function.
* */
void free(void *ptr)
{
if (ptr != NULL) {
/* calculate the address of the header */
release_block(HEADER(ptr));
}
}

void *calloc(size_t nmemb, size_t size)


{
size_t totalsize = nmemb * size;
void *ptr = malloc(totalsize);
/* clear the allocate space */
if (ptr != NULL) {
memset(ptr, 0, totalsize);
}
return ptr;
}

void *realloc(void *ptr, size_t size)


{
char *nptr;

if (ptr == NULL) {
return malloc(size);
}

/* if there is enough space in this block, simply return the same


block */
if (HEADER(ptr)->nodes[0].value >= size) {
return ptr;
}
/* otherwise, allocate a new space with the given size
* and copy the data from old block into the new one.
* after that, free the old block */
nptr = (char *)malloc(size);
memcpy(nptr, ptr, HEADER(ptr)->nodes[0].value);
free(ptr);

return nptr;
}

static struct header *allocate_block(size_t size)


{
struct header *h, *h2;
/* find a node in the binary search tree (by size)
* to perform best-fit allocation */
struct tnode *curr = trees[0];
while (curr != NULL) {
if (curr->value < size) {
/* best fit has to be in the right sub tree */
curr = curr->right;
} else if (curr->value == size) {
/* find a block with exact size */
break;
} else if (curr->left != NULL && curr->left->value >= size) {
/* best-fit is in the left sub tree*/
curr = curr->left;
} else {
break;
}
}

if (curr == NULL) {
/* no allocated space for the requested size, use sbrk() to
allocate one */
h = sbrk(size + sizeof(struct header));
/* initialize the header */
h->nodes[0].value = size;
h->nodes[1].value = (size_t)h;
return h;
}

/* remove it from the tree */


h = (struct header *)curr;
trees[0] = remove_tree(trees[0], &h->nodes[0]); /* remove tree by
size */
trees[1] = remove_tree(trees[1], &h->nodes[1]); /* remove tree by
address */

/* if the size of the block is not too large, simply return it */


if (curr->value - size <= sizeof(struct header) + 16) {
return h;
}
/* otherwise, split the node into two and add the remaining space
* into the tree */
h2 = (struct header *)((char *)h + sizeof(struct header) + size);
h2->nodes[0].value = curr->value - size - sizeof(struct header);
h2->nodes[1].value = (size_t)h2;
release_block(h2);

h->nodes[0].value = size;
return h;
}

static void release_block(struct header *h)


{
trees[0] = insert_tree(trees[0], &h->nodes[0]); /* insert tree by
size */
trees[1] = insert_tree(trees[1], &h->nodes[1]); /* insert tree by
address */

/* try to merge with continous memory space in the space tree */


trees[1] = merge(trees[1]);
}

/* try to merge free blocks with continous space */


static struct tnode *merge(struct tnode *node)
{
struct header *h1, *h2;
struct tnode *children[2];
size_t i;

if (node == NULL) {
return node;
}
node->left = merge(node->left);
node->right = merge(node->right);

/* merge with chidlren */


children[0] = node->left;
children[1] = node->right;
for (i = 0; i < 2; i++) {
if (children[i] == NULL) continue;
h1 = (struct header *)((char *)node - sizeof(struct tnode));
h2 = (struct header *)((char *)children[i] - sizeof(struct
tnode));
if (h1 > h2) {
struct header *h3 = h1;
h1 = h2;
h2 = h3;
}
if (CONTINUOUS(h1, h2)) {
/* remove them from the corresponding size tree */
trees[0] = remove_tree(trees[0], &h1->nodes[0]);
trees[0] = remove_tree(trees[0], &h2->nodes[0]);
/* merge them together */
h1->nodes[0].value += h2->nodes[0].value + sizeof(struct
header);
h1->nodes[1].right = h2->nodes[1].right;
/* add back to the size tree */
trees[0] = insert_tree(trees[0], &h1->nodes[0]);
node = &h1->nodes[1];
}
}
return node;
}

/* insert the header into the binary search tree (*node) */


static struct tnode *insert_tree(struct tnode *node, struct tnode *h)
{
int diff = 0;

if (node == NULL) {
/* reach a null branch, simply return the node of the block */
h->left = NULL;
h->right = NULL;
return h;
}

diff = node->value - h->value;

if (diff > 0) { /* insert into the left subtree */


node->left = insert_tree(node->left, h);
} else { /* insert into the right subtree */
node->right = insert_tree(node->right, h);
}

return node;
}

static struct tnode *remove_tree(struct tnode *node, struct tnode *h)


{
if (node == h) {
struct tnode *min;

/* found the node, remove it from the tree */


if (h->left == NULL && h->right == NULL) { /* no children */
return NULL;
}
if (h->left == NULL) { /* only right child */
return h->right;
}
if (h->right == NULL) { /* only left child */
return h->left;
}
/* have both children, find the smallest node in the right
* sub-tree and put it at this position */
min = h->right;
while (min->left != NULL) {
min = min->left;
}
h->right = remove_tree(h->right, min);
/* replace the current node */
min->left = h->left;
min->right = h->right;
return min;
} else {
int diff = node->value - h->value;

if (diff > 0) { /* remove from the left subtree */


node->left = remove_tree(node->left, h);
} else { /* remove from the right subtree */
node->right = remove_tree(node->right, h);
}
return node;
}
}

You might also like