This code provides a Tree
abstraction.
I would like to finalize the code structure only in tree
directory, before starting implementation, because there are multiple conditional compilations, written at the function level.
User code (testing) is yet to be attempted, as it is yet to fill the functions in Tree
abstraction.
The main intent of this query is to finalize the code structure.
The code is compiled and linked successfully.
/code
$ ls -LR
.:
list testList.c testTree.c tree type.h
./list:
arrayImpl.c linkedListImpl.c list.h
./tree:
binarySearchTree.c binaryTree.c lcrsImpl.c multiWalkImpl.c tree.h
type.h
This file provides some system headers:
/********* type.h ********/
#ifndef TYPE_H
#define TYPE_H /* Header guard */
#include<stdbool.h>
#include<stddef.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#endif /* TYPE_H */
list.h
This is the List
abstraction, re-used by Tree
abstraction:
/************ list.h ************/
/*
List is an ordered collection of homogenuous type elements(unique or duplicate).
List is not designed to have collection of heterogenuous type elements
All elements in a List are related.
List is mutable
Each element has a position.
If an element is deleted, then still the remaining elements sit in new order.
Array implementation of List
Linked implementation of List
*/
#ifndef LIST_H /* Header guard */
#define LIST_H
#include"type.h"
/***************** Usage-start ************/
#if defined(ARRAY) || (LINKED_LIST)
/* To ensure Encapsulation(i.e., maintain invariants of array & linked list)
So, Just provide the `List` declartion, to avoid mis-use of `List`
*/
typedef struct List List;
#else
#error "Wrong list implementation macro name !!!"
#endif
void listInsertItem(List *, void *newItem);
void *listDeleteItem(List *, int listIndex);
void *listDeleteLastItem(List *);
void *listDeleteFirstItem(List *);
const void *listGetItem(List *, int index); /* 'index' is array index */
int listGetSize(List *);
List* createList();
bool freeList(List *);
#endif /* LIST_H */
/***************** Usage-end ***************/
arrayImpl.c
/***************** arrayImpl.c **************/
#include"list/list.h"
#if defined(ARRAY)
typedef enum {DOUBLE_THE_LIST, HALF_THE_LIST}ListResizeOperation;
static List *resizeList(List *, ListResizeOperation);
/************ Representation - start ************/
typedef struct List{
void **array;
/* Housekeeping - Array enhancement/shrink */
int lastItemPosition;
int size;
}List;
#define INITIAL_LIST_SIZE 50
#define FIRST_ITEM_INDEX 0
/********************* Representation - end ************/
/************* Usage - start ***************/
List *createList(){
List *list = malloc(sizeof(List));
if(list != NULL){
list->array = malloc(INITIAL_LIST_SIZE*sizeof(void*));
if(list->array != NULL){
/* Is it safe to initialise zero to array of pointers? */
list->array = memset(list->array, 0, INITIAL_LIST_SIZE*sizeof(void *));
}else{
return NULL;
}
list->lastItemPosition = -1;
list->size = INITIAL_LIST_SIZE;
return list;
}else{
return NULL;
}
}
bool freeList(List *list){
if(list != NULL){
int index = 0;
while( index < list->size){
free(list->array[index]);
}
free(list->array);
free(list);
return true;
}else{
return false;
}
}
int listGetSize(List *list){
if(list != NULL){
return list->size;
}else{
fprintf(stderr, "List is NULL\n ");
return -1;
}
}
const void *listGetItem(List *list, int index){
if((index >=0) && (index < list->size)){
return (const void *)list->array[index];
}else{
return NULL;
}
}
void listInsertItem(List *arrayList, void *newItem){
/* House keeping - Enhance the array */
if(arrayList->lastItemPosition + 1 == arrayList->size){
arrayList = resizeList(arrayList, DOUBLE_THE_LIST);
if(arrayList == NULL){
fprintf(stderr, "insertItem() - Unable to allocate memory \n");
exit(1);
}
}
/* Insert new element - O(1) operation */
arrayList->array[++(arrayList->lastItemPosition)] = newItem;
}
void *listDeleteItem(List *arrayList, int listIndex){
void *returnElement = arrayList->array[listIndex];
/* Delete operation - O(n) operation */
for(int accumulator = listIndex; accumulator <= arrayList->lastItemPosition; accumulator++){
arrayList->array[accumulator] = arrayList->array[accumulator + 1];
}
arrayList->lastItemPosition--;
/* House keeping - Half the list */
if(arrayList->size > INITIAL_LIST_SIZE){ /* Minimum size maintained */
if((arrayList->lastItemPosition + 1) == ((arrayList->size)/2)){
arrayList = resizeList(arrayList, HALF_THE_LIST);
if(arrayList == NULL){
fprintf(stderr, "deleteItem() - Unable to allocate memory \n");
exit(1);
}
}
}
return returnElement; /* User must free this element*/
}
void * listDeleteLastItem(List *arrayList){
return listDeleteItem(arrayList, arrayList->lastItemPosition);
}
void *listDeleteFirstItem(List *arrayList){
return listDeleteItem(arrayList, FIRST_ITEM_INDEX);
}
/******************** Usage - end *******************/
linkedListImpl.c
/**********linkedListImpl.c ***********/
#include"type.h"
#if defined(LINKED_LIST)
/***************** Representation - start ******************/
/* struct members are not visible to other .c files */
struct DListNode{
void *item;
struct DListNode *next;
struct DListNode *prev;
};
/* Should be used in this .c file, only, so static */
typedef struct DListNode DListNode;
static DListNode* createNode(void *);
/* struct members are not visible to other .c files */
typedef struct List{
DListNode *head;
int size; /*size attribute is not part of list definition, but quick way to help user code */
}List;
#define SENTINEL_NODE_DATA_ITEM (void *)0
/************ Representation - end *************/
/******** Usage - start **********/
List *createList(){
List *list = (List *)malloc(sizeof(List));
if(list != NULL){
DListNode *sentinel = createNode(SENTINEL_NODE_DATA_ITEM);
list->head = sentinel;
list->head->next = list->head;
list->head->prev = list->head;
list->size = 0;
return list;
}else{
return NULL;
}
}
bool freeList(List *list){
if(list != NULL){
if(list->size > 0){
int index = 0;
DListNode *currentNode, *nextNode;
currentNode = list->head->next;
do{
nextNode = currentNode->next;
free(currentNode->item);
free(currentNode);
currentNode = nextNode;
}while(++index < list->size);
return true;
}else{
return true;
}
}else{
return false;
}
}
int listGetSize(List *list){
if(list != NULL){
return list->size;
}else{
fprintf(stderr, "List is NULL\n ");
return -1;
}
}
const void *listGetItem(List *list, int index){
if((index >=0) && (index < list->size)){
DListNode *node = list->head->next;
while(index-- > 0){
node = node->next;
}
return (const void *)node->item;
}else{
fprintf(stderr, "Invalid index \n");
return NULL;
}
}
/* O(1) operation - insert() operation */
void listInsertItem(List *linkedList, void *newItem){
DListNode *newNode = createNode(newItem);
if(linkedList->size == 0){
linkedList->head->next = linkedList->head->prev = newNode;
}else{
/* Link with current last node in the linked list*/
newNode->prev = linkedList->head->prev;
linkedList->head->prev->next = newNode;
/* Link with Sentinel node */
newNode->next = linkedList->head;
linkedList->head->prev = newNode;
}
}
/* O(n) - delete() operation*/
void *listDeleteItem(List *linkedList, int listIndex){
int accumulator = 0;
DListNode *nodeToDelete = linkedList->head->next;
if(listIndex < linkedList->size){
while(accumulator++ < listIndex){
nodeToDelete = nodeToDelete->next;
}
nodeToDelete->prev->next = nodeToDelete->next;
nodeToDelete->next->prev = nodeToDelete->prev;
linkedList->size++;
void *item = nodeToDelete->item;
free(nodeToDelete);
return item; /* User must delete by casting to free(item); */
}else{
fprintf(stderr, "deleteItem() - Invalid Index");
return NULL;
}
}
/* O(1) - deleteLastItem() operation */
void *listDeleteLastItem(List *linkedList){
if(linkedList->size){
DListNode *nodeToDelete = linkedList->head->prev;
void *item = nodeToDelete->item;
nodeToDelete->prev->next = nodeToDelete->next;
nodeToDelete->next->prev = nodeToDelete->prev;
free(nodeToDelete);
return item; /* User must free this item,by casting, free(item) */
}else{
return NULL;
}
}
/* O(1) - deleteFirstItem() operation */
void *listDeleteFirstItem(List *linkedList){
if(linkedList->size){
DListNode *nodeToDelete = linkedList->head->next;
void *item = nodeToDelete->item;
nodeToDelete->next->prev = nodeToDelete->prev;
nodeToDelete->prev->next = nodeToDelete->next;
free(nodeToDelete);
return item; /* User must free this item,by casting, free(item) */
}else{
return NULL;
}
}
/********** Usage - end *************/
/********** Helper function - start ****************/
/* createNode() is not visible to the linker(ld) */
static DListNode *createNode(void * value){
DListNode *newNode= malloc(sizeof(DListNode));
newNode->next = newNode;
newNode->prev = newNode;
newNode->item = value;
return newNode;
}
/******** Helper function - end ********/
#endif
tree.h
/*************** tree.h ***************************/
#ifndef TREE_H /* Header guard */
#define TREE_H
#if defined(MULTI_WALK) || (BINARY_TREE_USING_ARRAY) || (BINARY_SEARCH_TREE_USING_ARRAY)
#include"list/list.h" //Using array implementation
#elif defined(LCRS) || (BINARY_TREE_USING_NODE) || (BINARY_SEARCH_TREE_USING_NODE)
#include"type.h"
#else
#error "Invalid representation\n"
#endif
/****************** Usage-start ************/
#if defined(LCRS)
typedef struct LCRSTree Tree;
#elif defined(MULTI_WALK)
typedef struct multiWalkTree Tree;
#elif defined(BINARY_TREE_USING_NODE) || (BINARY_TREE_USING_ARRAY)
typedef struct BinaryTree Tree;
#elif defined(BINARY_SEARCH_TREE_USING_NODE) || (BINARY_SEARCH_TREE_USING_ARRAY)
typedef struct BinarySearchTree Tree;
#endif
typedef void (*visitFunc)(void *);
Tree * newTree(void);
bool destroyTree(Tree *);
#if defined(LCRS) || (MULTI_WALK)
typedef void* (*parseFunc)(void *);
void treeInsertItem(Tree *, void *item, parseFunc);
void* treeDeleteItem(Tree *, void *item, parseFunc);
#elif defined(BINARY_TREE_USING_NODE) || (BINARY_TREE_USING_ARRAY) || (BINARY_SEARCH_TREE_USING_NODE) || (BINARY_SEARCH_TREE_USING_ARRAY)
void treeInsertItem(Tree *, void *item);
void* treeDeleteItem(Tree *, void *item);
#endif
void preOrderTraversal(Tree*, visitFunc);
void postOrderTraversal(Tree *, visitFunc);
void breadthFirstTraversal(Tree *, visitFunc);
void inOrderTraversal(Tree *, visitFunc);
int treeGetSize(Tree *);
/**************** Usage-end ******************/
#endif /* TREE_H */
multiWalkImpl.c
/******************* multiWalkImpl.c*************/
#include"tree.h"
#if defined(MULTI_WALK)
typedef struct treeNode{
struct treeNode *parent;
void *item;
List **childList;
}Node;
typedef struct multiWalkTree{
Node *root;
int size;
}Tree;
/*
Analysis
========
Ignoring the size of actual data, but including the size of pointer pointing
to data, multi walk tree takes more space compared to LCRS tree
*/
Tree * newTree(void){
return NULL;
}
bool destroyTree(Tree *t){
return false;
}
int treeGetSize(Tree *t){
return 0;
}
void treeInsertItem(Tree *t, void *item, parseFunc f){
return;
}
void* treeDeleteItem(Tree *t, void *item, parseFunc f){
return NULL;
}
void preOrderTraversal(Tree *t, visitFunc f){
return;
}
void postOrderTraversal(Tree *t, visitFunc f){
return;
}
void breadthFirsTraversal(Tree *t, visitFunc f){
return;
}
#endif
lcrsImpl.c
/**********************lcrsImpl.c ***********************/
#include"tree.h"
#if defined(LCRS)
/*******************Representation-start **************/
typedef struct SiblingTreeNode{
struct SiblingTreeNode *parent;
void *item;
struct SiblingTreeNode *firstChild;
struct SiblingTreeNode *nextSibling;
}Node;
static void postOrderTraverse(Node *, visitFunc);
static void preOrderTraverse(Node *, visitFunc);
static void breadthFirstTraverse(Node *, visitFunc);
typedef struct LCRSTree{
Node *root;
int size;
}Tree;
/******************Representation-end*********************/
/**********************Usage-start************************/
Tree * newTree(void){
Tree *rootedTree = malloc(sizeof(Tree));
rootedTree->root = NULL;
rootedTree->size = 0;
return rootedTree;
}
bool destroyTree(Tree *t){
return false;
}
int treeGetSize(Tree *t){
return 0;
}
void *treeDeleteItem(Tree *t, void *item, parseFunc f){
return NULL;
}
void treeInsertItem(Tree *rootedTree, void *item, parseFunc f){
if(rootedTree->root == NULL){
Node *rootNode = malloc(sizeof(Node));
rootNode->parent = NULL;
rootNode->item = item;
rootNode->firstChild = NULL;
rootNode->nextSibling = NULL;
rootedTree->root = rootNode;
rootedTree->size = 0;
}else{
}
}
void preOrderTraversal(Tree *tree, visitFunc f){
preOrderTraverse(tree->root, f);
}
void postOrderTraversal(Tree *tree, visitFunc f){
postOrderTraverse(tree->root, f);
}
/*
Level-order traversal
*/
void breadthFirsTraversal(Tree *t, visitFunc f){
breadthFirstTraverse(t->root, f);
}
/**********************Usage-end ***************/
/***********************Helper function - start ************/
static void postOrderTraverse(Node *node, visitFunc f){
}
static void preOrderTraverse(Node * node, visitFunc f){
}
static void breadthFirstTraverse(Node *n, visitFunc f){
}
/***************Helper function -end******************/
#endif
binaryTree.c
/***************binaryTree.c***************/
#include"tree/tree.h"
#if defined(BINARY_TREE_USING_ARRAY)
/************* Representation-start *************/
typedef struct BinaryTree{
List **array;
int size;
}Tree;
/**************Representation-end *****************/
#elif defined(BINARY_TREE_USING_NODE)
/************* Representation-start *************/
typedef struct BinaryTreeNode{
void *item;
struct BinaryTreeNode *parent;
struct BinaryTreeNode *left;
struct BinaryTreeNode *right;
}Node;
typedef struct BinaryTree{
Node *root;
int size;
}Tree;
/**************Representation-end *****************/
static void inOrderTraverse(Node *, visitFunc);
static void postOrderTraverse(Node *, visitFunc);
static void preOrderTraverse(Node *, visitFunc);
static void breadthFirstTraverse(Node *, visitFunc);
#endif
#if defined(BINARY_TREE_USING_NODE) || (BINARY_TREE_USING_ARRAY)
/******************Usage-start *****************/
Tree * newTree(void){
#if defined(BINARY_TREE_USING_NODE)
#elif defined(BINARY_TREE_USING_ARRAY)
#endif
return NULL;
}
bool destroyTree(Tree *t){
#if defined(BINARY_TREE_USING_NODE)
#elif defined(BINARY_TREE_USING_ARRAY)
#endif
return false;
}
void treeInsertItem(Tree *t, void *item){
#if defined(BINARY_TREE_USING_NODE)
#elif defined(BINARY_TREE_USING_ARRAY)
#endif
}
void* treeDeleteItem(Tree *t, void *item){
#if defined(BINARY_TREE_USING_NODE)
#elif defined(BINARY_TREE_USING_ARRAY)
#endif
return NULL;
}
int treeGetSize(Tree *t){
#if defined(BINARY_TREE_USING_NODE)
#elif defined(BINARY_TREE_USING_ARRAY)
#endif
return 0;
}
void preOrderTraversal(Tree* t, visitFunc action){
#if defined(BINARY_TREE_USING_NODE)
preOrderTraverse(t->root, action);
#elif defined(BINARY_TREE_USING_ARRAY)
#endif
/* only iterative - no recursive approach */
}
void inOrderTraversal(Tree *bT, visitFunc action){
#if defined(BINARY_TREE_USING_NODE)
inOrderTraverse(bT->root, action);
#elif defined(BINARY_TREE_USING_ARRAY)
#endif
}
void postOrderTraversal(Tree *t, visitFunc action){
#if defined(BINARY_TREE_USING_NODE)
postOrderTraverse(t->root, action);
#elif defined(BINARY_TREE_USING_ARRAY)
#endif
void breadthFirsTraversal(Tree *t, visitFunc action){
#if defined(BINARY_TREE_USING_NODE)
breadthFirstTraverse(t->root, action);
#elif defined(BINARY_TREE_USING_ARRAY)
#endif
}
/****************Usage-end ********************/
#endif
#if defined(BINARY_TREE_USING_NODE)
/*****************Helper function-start **************/
static void inOrderTraverse(Node *n, visitFunc action){
}
static void breadthFirstTraverse(Node *n, visitFunc action){
}
static void postOrderTraverse(Node *n, visitFunc action){
}
static void preOrderTraverse(Node *n, visitFunc action){
}
/*****************Helper function-end *****************/
#endif
binarySearchTree.c
/***************binarySearchTree.c***************/
#include"tree/tree.h"
#if defined(BINARY_SEARCH_TREE_USING_ARRAY)
/************* Representation-start *************/
typedef struct BinarySearchTree{
List **array;
int size;
}Tree;
/**************Representation-end *****************/
#elif defined(BINARY_SEARCH_TREE_USING_NODE)
/************* Representation-start *************/
typedef struct BinarySearchTreeNode{
void *item;
struct BinaryTreeNode *parent;
struct BinaryTreeNode *left;
struct BinaryTreeNode *right;
}Node;
typedef struct BinarySearchTree{
Node *root;
int size;
}Tree;
/**************Representation-end *****************/
static void inOrderTraverse(Node *, visitFunc);
static void postOrderTraverse(Node *, visitFunc);
static void preOrderTraverse(Node *, visitFunc);
static void breadthFirstTraverse(Node *, visitFunc);
#endif
#if defined(BINARY_SEARCH_TREE_USING_NODE) || (BINARY_SEARCH_TREE_USING_ARRAY)
/******************Usage-start *****************/
Tree * newTree(void){
#if defined(BINARY_SEARCH_TREE_USING_NODE)
#elif defined(BINARY_SEARCH_TREE_USING_ARRAY)
#endif
return NULL;
}
bool destroyTree(Tree *t){
#if defined(BINARY_SEARCH_TREE_USING_NODE)
#elif defined(BINARY_SEARCH_TREE_USING_ARRAY)
#endif
return false;
}
void treeInsertItem(Tree *t, void *item){
#if defined(BINARY_SEARCH_TREE_USING_NODE)
#elif defined(BINARY_SEARCH_TREE_USING_ARRAY)
#endif
}
void* treeDeleteItem(Tree *t, void *item){
#if defined(BINARY_SEARCH_TREE_USING_NODE)
#elif defined(BINARY_SEARCH_TREE_USING_ARRAY)
#endif
return NULL;
}
int treeGetSize(Tree *t){
#if defined(BINARY_SEARCH_TREE_USING_NODE)
#elif defined(BINARY_SEARCH_TREE_USING_ARRAY)
#endif
return 0;
}
void preOrderTraversal(Tree* t, visitFunc action){
#if defined(BINARY_SEARCH_TREE_USING_NODE)
preOrderTraverse(t->root, action);
#elif defined(BINARY_SEARCH_TREE_USING_ARRAY)
#endif
/* only iterative - no recursive approach */
}
void inOrderTraversal(Tree *bT, visitFunc action){
#if defined(BINARY_SEARCH_TREE_USING_NODE)
inOrderTraverse(bT->root, action);
#elif defined(BINARY_SEARCH_TREE_USING_ARRAY)
#endif
}
void postOrderTraversal(Tree *t, visitFunc action){
#if defined(BINARY_SEARCH_TREE_USING_NODE)
postOrderTraverse(t->root, action);
#elif defined(BINARY_SEARCH_TREE_USING_ARRAY)
#endif
}
void breadthFirsTraversal(Tree *t, visitFunc action){
#if defined(BINARY_SEARCH_TREE_USING_NODE)
breadthFirstTraverse(t->root, action);
#elif defined(BINARY_SEARCH_TREE_USING_ARRAY)
#endif
}
/****************Usage-end ********************/
#endif
#if defined(BINARY_SEARCH_TREE_USING_NODE)
/*****************Helper function-start **************/
static void inOrderTraverse(Node *n, visitFunc action){
}
static void breadthFirstTraverse(Node *n, visitFunc action){
}
static void postOrderTraverse(Node *n, visitFunc action){
}
static void preOrderTraverse(Node *n, visitFunc action){
}
/*****************Helper function-end *****************/
#endif
Compilation procedure:
To test Multiwalk tree using list:
Sit in
code
folder,Run command,
gcc -Wall -g -I. -DMULTI_WALK -DARRAY ./list/*.c ./tree/*.c testTree.c -o testTree
To test Binary tree using list:
Sit in
code
folder,Run command,
gcc -Wall -g -I. -DARRAY -DBINARY_TREE_USING_ARRAY ./list/*.c ./tree/*.c testTree.c -o testTree
To test Binary search tree using list:
Sit in
code
folder,Run command,
gcc -Wall -g -I. -DARRAY -DBINARY_SEARCH_TREE_USING_ARRAY ./list/*.c ./tree/*.c testTree.c -o testTree
To test LCRS tree:
Sit in
code
folder,Run command,
gcc -Wall -g -I. -DLCRS ./tree/*.c testTree.c -o testTree
To test Binary tree using node:
Sit in
code
folder,Run command,
gcc -Wall -g -I. -DBINARY_TREE_USING_NODE ./tree/*.c testTree.c -o testTree
To test Binary search tree using node:
Sit in
code
folder,Run command,
gcc -Wall -g -I. -DBINARY_SEARCH_TREE_USING_NODE ./tree/*.c testTree.c -o testTree
Users of Tree
abstraction:
Priority queue can be implemented efficiently using LCRS implementation of N-ary tree (N <= 2).
State propagation tree, shown here, can be implemented using multi walk tree
Ordered data can be maintained by a binary search tree
Expression trees can be implemented using a binary tree
Questions:
Does the code structure that involves conditional compilation, at function level, looks maintainable? If no, can the code get further structured that minimizes conditional compilations?
As per this declaration,
void inOrderTraversal(Tree *, visitFunc);
inOrder traversal is applied on N-ary tree(N>2). As per this answer, does it practically make sense to apply on other than a binary tree?Further,
PriorityQueue
abstraction code will not be part oftree
directory, by definition. It will sit incode
directory. Please confirm the correction of this approach.
Note: After review of code structure, implementation of the functions would continue. Complete code is here .
const
is meaningless on return types and should be omitted \$\endgroup\$