Вы находитесь на странице: 1из 37

/*

* list.h
* Copyright (c) 2010, Irfan Iqbal
* -------
* This file defines an enhanced version of the list ADT discussed in class.
*/

#ifndef LIST_H
#define LIST_H

#define LIST_SIZE 8

/*
* flags to specify list behavior
*/
#define O_LIMITED 0x00000000 /* list cannot grow beyond a maximum size */
#define O_UNLIMITED 0x00000001 /* list can grow to any size */

/*
* type definitions.
*/
typedef int list_elem_t;
typedef unsigned int list_option_t;
typedef struct listCDT *listADT;
typedef enum {
LIST_NOERROR,
LIST_FULL,
LIST_EMPTY,
LIST_INVALID,
LIST_NOMEM,
LIST_BAD_LOC,
} list_err_t;

/*
* function prototypes.
*/

/*
* list_init
* ---------
* Initializes a list ADT by allocating the necessary resources and
* returns a handle to caller. The handle is used in all subsequent
* calls to various functions/methods of this ADT.
*
* Parameters:
* 'size': specifies the maximum number of elements the list will have.
* 'option': specifies whether the list can grow if it becomes full.
*/
listADT list_init (unsigned int size, list_option_t option);
/*
* list_free
* ---------
* Do away with the list ADT, freeing up all resources allocated.
*
* Parameters:
* 'l': list ADT returned by 'list_init' function.
*/
void list_free (listADT l);

/*
* list_insert
* -----------
* Inserts a specified element at the specified location in the list.
*
* Parameters:
* 'l': the list ADT in which to insert the element.
* 'e': the element to be inserted.
* 'loc': the location at which to insert the element.
*/
list_err_t list_insert (listADT l, list_elem_t e, int loc);

/*
* list_delete
* -----------
* Deletes the element at the specified location in the list.
*
* Parameters:
* 'l': the list ADT from which to delete the element.
* 'loc': the location of the element to be deleted.
*/
list_err_t list_delete (listADT l, int loc);

/*
* list_read
* ---------
* Obtain the element stored at the specified location in the list
* without deleting it. It is similar to the 'peek' function of
* stack ADT.
*
* Parameters:
* 'l': list ADT from which to read.
* 'pe': location at which to write the element read.
* 'loc': location in the list from which to read.
*
* The size of the list does not change after this operation. Only
* the element at the specified location in the list is copied to
* the memory location pointed to by the pointer 'pe'.
*/
list_err_t list_read (listADT l, list_elem_t *pe, int loc);

/*
* list_write
* ----------
* Overwrites the element at the specified location.
*
* Parameters:
* 'l': list ADT in which to overwrite the element.
* 'e': the new element.
* 'loc': the location at which to write the new element.
*
* The size of the list does not change after this operation. Just
* one element is replaced by another element.
*/
list_err_t list_write (listADT l, list_elem_t e, int loc);

/*
* list_print
* ----------
* Print the contents of the list.
*
* This function does not belong to the ADT. It is going to be replaced
* with a mapping function, and will disappear from the future versions
* of this ADT.
*/
list_err_t list_print (listADT l);

/*
* list_map
* --------
* Apply the specified function on every element stored in the list ADT.
*
* Parameters:
* 'l': list ADT on whose elements to apply the mapping function.
* 'map_fn': mapping function to be applied to the list ADT.
*
* We will enhance this mapping function when we talk about lists which
* store elements of arbitrary types.
*/
list_err_t list_map (listADT l, list_map_fn_t map_fn);

#endif /* LIST_H */

/*
* list.c
* Copyright (c) 2010, Irfan Iqbal
* -------
* This file implements list ADT.
*/

#include <stdlib.h>
#include "list.h"

struct listCDT {
int magic_num;
list_elem_t lst[LIST_SIZE];
int count;
};

listADT list_init (void)


{
listADT nl; /* new list */

if (!(nl = malloc(sizeof(struct listCDT)))) {


return NULL;
}
nl->count = 0;

return (nl);
}

void list_free (listADT l)


{
if (l) {
free(l);
}
return;
}

list_err_t list_insert (listADT l, list_elem_t e, int loc)


{
int i;

if (!l) {
return (LIST_INVALID);
}
if (l->count == LIST_SIZE) {
return (LIST_FULL);
}
if ((loc < 1) || (loc > (l->count + 1))) {
return (LIST_BAD_LOC);
}
for (i = (l->count - 1) ; i >= (loc - 1) ; --i) {
l->lst[i + 1] = l->lst[i];
}
l->lst[i + 1] = e;
(l->count)++;
return (LIST_NOERROR);
}

/*
* l_driver.c
* Copyright (c) 2010, Irfan Iqbal
* -------
* This file tests list ADT defined in list.h header file.
*/

#include <stdio.h>
#include "list.h"

void print_menu (void)


{
printf("Enter 1 to initialize list.\n");
printf("Enter 2 to free list.\n");
printf("Enter 3 to insert element.\n");
printf("Enter 4 to delete element.\n");
printf("Enter 5 to print queue.\n");
printf("Enter 6 to apply mapping function.\n");
printf("Enter 7 to quit.\n");
}

int get_option (void)


{
int c;

scanf("%d", &c);
return (c);
}

int map_fn_1 (list_elem_t *pe)


{
*pe *= 5;
return (0);
}

int map_fn_2 (list_elem_t *pe)


{
*pe /= 5;
return (0);
}

int main (int argc, char *argv[])


{
int z;
listADT myL = NULL;
list_elem_t elem;
list_err_t error;

while (1) {
print_menu();
z = get_option();
switch (z) {
case 1:
myL = list_init();
break;
case 2:
list_free(myL);
myL = NULL;
break;
case 3:
printf("Enter element to insert: ");
scanf("%d", &elem);
printf("Enter location: ");
scanf("%d", &z);
error = list_insert(myL, elem, z);
if (error == LIST_INVALID) {
printf("Invalid list given.\n");
} else if (error == LIST_FULL) {
printf("List is full.\n");
} else if (error == LIST_BAD_LOC) {
printf("Bad insertion location given.\n");
} else {
printf("Insert successful.\n");
}
break;
case 5:
error = list_print(myL);
if (error == LIST_INVALID) {
printf("Invalid list given.\n");
} else if (error == LIST_EMPTY) {
printf("List is empty.\n");
}
break;
case 6:
printf("Enter 1 to multiply every element by 5\n");
printf("Enter 2 to divide every element by 5\n");
scanf("%d", &z);
if (z == 1) {
error = list_map(myL, map_fn_1);
} else if (z == 2) {
error = list_map(myL, map_fn_2);
}
break;
default:
break;
}
if (z < 1 || z > 6) {
break;
}
}
return (0);
}

/*
/*
* list.c
* Copyright (c) 2010, Irfan Iqbal
* -------
* This file implements list ADT using linked-lists.
*/

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

#define MAGIC_NUM 0xdeadbeef

struct cell {
list_elem_t d;
struct cell *next;
};

struct listCDT {
int magic_num;
struct cell *head;
struct cell *tail; /* optional */
int count;
};

listADT list_init (void)


{
listADT nl; /* new list */

if (!(nl = malloc(sizeof(struct listCDT)))) {


return (NULL);
}
nl->magic_num = MAGIC_NUM;
nl->head = NULL;
nl->tail = NULL;
nl->count = 0;
return (nl);
}

void list_free (listADT l)


{
struct cell *t;

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return;
}
while (l->head) {
t = l->head;
l->head = t->next;
free(t);
}
free(l);
return;
}

list_err_t list_insert (listADT l, list_elem_t e, int loc)


{
int i;
struct cell *ip; /* insertion point */
struct cell *nc; /* new cell */

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return (LIST_INVALID);
}
if ((loc < 1) || (loc > (l->count + 1))) {
return (LIST_BAD_LOC);
}

/* allocate a new cell and inititalize it */


if (!(nc = malloc(sizeof(struct cell)))) {
return (LIST_NOMEM);
}
nc->d = e;
nc->next = NULL;

if (loc == 1) { /* special case of insertion at location 1 */


nc->next = l->head;
l->head = nc;
if (!l->tail) { /* list was empty. Now head and tail */
l->tail = nc; /* and tail point to same cell. */
}
} else { /* all other cases. We will come up with a better solution. */
ip = l->head;
for (i = 1 ; i < loc - 1 ; ++i) {
ip = ip->next;
}
nc->next = ip->next;
ip->next = nc;
if (l->tail == ip) {
l->tail = nc; /* newly inserted cell becomes the new tail */
}
}
++l->count;
return (LIST_NOERROR);
}
list_err_t list_print (listADT l)
{
struct cell *t;

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return (LIST_INVALID);
}
t = l->head;
printf("%%%% List Start\n");
while (t) {
printf("%d\n", t->d);
t = t->next;
}
printf("%%%% List End\n");
return (LIST_NOERROR);
}
* list-dll.c
* Copyright (c) 2010, Irfan Iqbal
* -------
* This file implements list ADT using doubly linked-lists.
*/

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

#define MAGIC_NUM 0xdeadbeef

struct cell {
list_elem_t d;
struct cell *next; /* also called 'flink' (forward link) */
struct cell *prev; /* also called 'blink' (backward link) */
};

struct listCDT {
int magic_num;
struct cell *head;
struct cell *tail; /* optional */
int count;
};

listADT list_init (void)


{
listADT nl; /* new list */

if (!(nl = malloc(sizeof(struct listCDT)))) {


return (NULL);
}
nl->magic_num = MAGIC_NUM;
nl->head = NULL;
nl->tail = NULL;
nl->count = 0;
return (nl);
}

void list_free (listADT l)


{
struct cell *t;

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return;
}
while (l->head) {
t = l->head;
l->head = t->next;
free(t);
}
free(l);
return;
}

list_err_t list_insert (listADT l, list_elem_t e, int loc)


{
struct cell **ip; /* insertion point. YES, its a double pointer */
struct cell *nc; /* new cell */

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return (LIST_INVALID);
}
if ((loc < 1) || (loc > (l->count + 1))) {
return (LIST_BAD_LOC);
}

/* allocate a new cell and inititalize it */


if (!(nc = malloc(sizeof(struct cell)))) {
return (LIST_NOMEM);
}
nc->d = e;
nc->next = NULL;
nc->prev = NULL;

/* now let's get to the correct insertion point */


ip = &(l->head);
while (--loc) {
ip = &((*ip)->next);
}
/* we are there. now do the insertion */
nc->next = *ip;
*ip = nc;
if (nc->next) {
nc->prev = nc->next->prev;
nc->next->prev = nc;
} else { /* either the list was empty or we're inserting after tail. */
nc->prev = l->tail;
l->tail = nc;
}
++l->count;
return (LIST_NOERROR);
}

list_err_t list_print (listADT l)


{
struct cell *t;

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return (LIST_INVALID);
}
t = l->head;
printf("%%%% List Start\n");
while (t) {
printf("%d\n", t->d);
t = t->next;
}
printf("%%%% List End\n");
return (LIST_NOERROR);
}

list_err_t list_map (listADT l, list_map_fn_t map_fn)


{
struct cell *t;

if (!l) {
return (LIST_INVALID);
}
if (!l->count) {
return (LIST_EMPTY);
}
t = l->head;
while (t) {
map_fn(&(t->d));
t = t->next;
}
return (LIST_NOERROR);
}
/*
* list-gen.h
* Copyright (c) 2010, Irfan Iqbal
* -------
* This file defines list ADT which can store any type of data.
*/

#ifndef LIST_GEN_H
#define LIST_GEN_H

#define LIST_SIZE 8

/*
* type definitions.
*/
typedef struct listCDT *listADT;

/*
* Return value of all of the following functions should be
* LIST_NOERROR in case of successful execution.
*/
typedef int (*list_map_fn_t) (void *p, void *q);
typedef int (*copy_fn_t) (void *dst, void *src);
typedef int (*delete_fn_t) (void *p);

typedef enum {
LIST_NOERROR,
LIST_FULL,
LIST_EMPTY,
LIST_INVALID,
LIST_NOMEM,
LIST_BAD_LOC,
LIST_CP_FAIL,
} list_err_t;

/*
* function prototypes.
*/
listADT list_init (int ds, copy_fn_t cp_fn, delete_fn_t del_fn);
void list_free (listADT l);
list_err_t list_insert (listADT l, void *pe, int loc);
list_err_t list_delete (listADT l, int loc);
list_err_t list_read (listADT l, void *pe, int loc);
list_err_t list_write (listADT l, void *pe, int loc);
list_err_t list_map (listADT l, list_map_fn_t map_fn, void *q);

#endif /* LIST_GEN_H */
/*
* list-gen.c
* Copyright (c) 2010, Irfan Iqbal
* -------
* This file implements the list ADT defined in list-gen.h header file.
* The implementation does not define explicit cell structure to store
* items inserted by client.
*/

/*
* To obtain debug output compile with "-DDEBUG" flag as shown below.
*
* $ gcc -g -Wall -DDEBUG -c list-gen.c
*/
#ifdef DEBUG
#include <stdio.h>
#endif /* DEBUG */

#include <stdlib.h>
#include "list-gen.h"

#define MAGIC_NUM 0xbeefcafe

struct listCDT {
int magic_num;
void *head;
void *tail;
int count;
int ds;
copy_fn_t cp_fn;
delete_fn_t del_fn;
};

typedef enum {
LIST_OP_READ = 1,
LIST_OP_WRITE,
} list_op_t;

listADT list_init (int ds, copy_fn_t cp_fn, delete_fn_t del_fn)


{
listADT nl;

if (!(nl = malloc(sizeof(struct listCDT)))) {


return (NULL);
}
nl->magic_num = MAGIC_NUM;
nl->head = nl->tail = NULL;
nl->count = 0;
nl->ds = ds;
nl->cp_fn = cp_fn;
nl->del_fn = del_fn;
return (nl);
}

void list_free (listADT l)


{
list_err_t rc;
void *c;
void *t;
#ifdef DEBUG
int i = 1;
#endif /* DEBUG */

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return;
}
c = l->head;
while (l->count--) {
rc = l->del_fn((void *)((unsigned)c + sizeof(void *)));
if (rc != LIST_NOERROR) {
return;
}
t = c;
c = *((void **)c);
#ifdef DEBUG
printf("%%%%DEBUG: Freeing item number: %d.\n", i++);
#endif /* DEBUG */
free(t);
}
#ifdef DEBUG
printf("%%%%DEBUG: Freeing container structure.\n");
#endif /* DEBUG */
free(l);
return;
}

list_err_t list_insert (listADT l, void *pe, int loc)


{
int rc;
void **ip;
void *nc;

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return (LIST_INVALID);
}
if ((loc < 1) || (loc > (l->count + 1))) {
return (LIST_BAD_LOC);
}
/* allocate a new cell and inititalize it */
if (!(nc = malloc(l->ds + sizeof(void *)))) {
return (LIST_NOMEM);
}
*(void **)nc = NULL;
rc = l->cp_fn((void *)((unsigned int) nc) + sizeof(void *), pe);
if (rc) {
free(nc);
return (rc);
}
/* now let's get to the correct insertion point */
ip = &(l->head);
while (--loc) {
ip = *ip;
}
/* we are there. now do the insertion */
*(void **)nc = *ip;
*ip = nc;
if (!(*(void **)nc)) {
/* either the list was empty or we're inserting after tail. */
l->tail = nc;
}
++l->count;
return (LIST_NOERROR);
}

list_err_t list_delete (listADT l, int loc)


{
int rc;
void **ip;
void *t;
#ifdef DEBUG
int i = loc;
#endif /* DEBUG */

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return (LIST_INVALID);
}
if ((loc < 1) || (loc > l->count)) {
return (LIST_BAD_LOC);
}
/* now let's get to the cell to be deleted */
ip = &(l->head);
while (--loc) {
ip = *ip;
}
/* we are there. take the cell out of the linked list. */
t = *ip;
*ip = *(void **)t;
if (!(*ip)) {
l->tail = ip; /* we are deleting the last item. update tail. */
}
/* let the client do whatever it wants to do with its part. */
rc = l->del_fn((void *)((unsigned int)t + sizeof(void *)));
#ifdef DEBUG
printf("%%%%DEBUG: Freeing item at location: %d\n", i);
#endif /* DEBUG */
free(t);
--l->count;
if (!l->count) {
l->tail = NULL;
}
return (rc);
}

static
list_err_t list_read_write (listADT l, void *pe, int loc, list_op_t op)
{
list_err_t rc;
void *t;

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return (LIST_INVALID);
}
if ((loc < 1) || (loc > l->count)) {
return (LIST_BAD_LOC);
}
t = l->head;
while (--loc) {
t = *(void **)t;
}
if (op == LIST_OP_READ) {
rc = l->cp_fn(pe, (void *)((unsigned int)t + sizeof(void *)));
} else if (op == LIST_OP_WRITE) {
rc = l->cp_fn((void *)((unsigned int)t + sizeof(void *)), pe);
}
return (rc);
}

list_err_t list_read (listADT l, void *pe, int loc)


{
return (list_read_write(l, pe, loc, LIST_OP_READ));
}

list_err_t list_write (listADT l, void *pe, int loc)


{
return (list_read_write(l, pe, loc, LIST_OP_WRITE));
}

list_err_t list_map (listADT l, list_map_fn_t map_fn, void *q)


{
void *c;
list_err_t rc;

if ((!l) || (l->magic_num != MAGIC_NUM)) {


return (LIST_INVALID);
}
if (!l->count) {
return (LIST_EMPTY);
}
c = l->head;
/*
* Now apply mapping function on each item stored in the list.
* Pass parameter `q' to mapping function every time. Client
* may want to use this parameter. We have nothing to do with
* parameter `q' and we don't know what it is!
*/
while (c) {
rc = map_fn((void *)((unsigned int)c + sizeof(void *)), q);
if (rc != LIST_NOERROR) {
return (rc);
}
c = *((void **)c); /* advance to next item */
}
return (LIST_NOERROR);
}
/*
* bst.h
* Copyright (c) 2010, Irfan Iqbal
* -------
* This header file defines a binary search tree ADT.
*/
#ifndef BST_H
#define BST_H

typedef enum {
BST_NOERROR,
BST_INVALID,
BST_NOMEM,
BST_DUP_KEY,
BST_BAD_WALK,
} bst_err_t;

typedef enum {
WALK_PRE_ORDER = 1,
WALK_IN_ORDER,
WALK_POST_ORDER,
} walk_t;

typedef int bst_key_t;


typedef struct bstCDT *bstADT;
typedef bst_err_t (*map_fn_t) (bst_key_t k, void *cd);

bstADT bst_init (void);


void bst_free (bstADT t);
bst_err_t bst_insert (bstADT t, bst_key_t k);
bst_err_t bst_delete (bstADT t, bst_key_t k);
bst_err_t bst_map (bstADT t, map_fn_t map_fn, walk_t wt, void *cd);

#endif /* BST_H */
/*
* bst.c
* Copyright (c) 2010, Irfan Iqbal
* -------
* This file implements the binary search tree ADT defined in `bst.h'
* header file. Keys are restricted to integer type.
*/

#include <stdlib.h>
#include "bst.h"

struct node {
bst_key_t k;
struct node *lst; /* left sub-tree */
struct node *rst; /* right sub-tree */
};

struct bstCDT {
struct node *root;
int count; /* total number of nodes in the tree */
};

bstADT bst_init (void)


{
bstADT nt;

if (!(nt = malloc(sizeof(struct bstCDT)))) {


return (NULL);
}
nt->root = NULL;
nt->count = 0;
return (nt);
}

void bst_free (bstADT t)


{
if (t != NULL)
free(t->lst);
free(t->rst);
free (t);
t = NULL;
}

static bst_err_t bst_insert_key (struct node **n, bst_key_t k)


{
if (!n) {
return (BST_INVALID);
}
if (!(*n)) {
struct node *new; /* why did we define the variable here? */

if (!(new = malloc(sizeof(struct node)))) {


return (BST_NOMEM);
}
new->k = k;
new->lst = new->rst = NULL;
*n = new;
return (BST_NOERROR);
}
if ((*n)->k < k) {
return (bst_insert_key(&((*n)->rst), k));
} else if ((*n)->k > k) {
return (bst_insert_key(&((*n)->lst), k));
} else {
return (BST_DUP_KEY);
}
}

bst_err_t bst_insert (bstADT t, bst_key_t k)


{
bst_err_t rc;

if (!t) {
return (BST_INVALID);
}
rc = bst_insert_key(&(t->root), k);
if (rc == BST_NOERROR) {
++t->count;
}
return (rc);
}

node find_min (bstADT t)


{

if (t == NULL )
return NULL;
else
if(t->left == NULL);
return t;
else
return find_min(t-lst);
bst_err_t bst_delete (bstADT t, bst_key_t k)
{
struct node *temp;
if (t == NULL)
{return (BST_INVALID)
else
if (k<t->k)
t->lst = delete (k, t->lst);
else
if (k>t->k)
t->rst = delete (k, t->lst);
else
if (t->lst && t->rst)
{
temp = findmin (t->right); //find_min implemented before
delete function
t->k = temp->k;
t->rst = delete (t->k, t->rst);
}
else
temp = t;
if t->lst == NULL)
t = t->rst;
else if (t->right == NULL)
t = t->lst;
free (temp);
}

return (BST_NOERROR);
}

static void bst_map_tree (struct node *n, map_fn_t mf, walk_t wt,
void *cd)
{
if (!n) {
return;
}
if (wt == WALK_PRE_ORDER) {
mf(n->k, cd);
bst_map_tree(n->lst, mf, wt, cd);
bst_map_tree(n->rst, mf, wt, cd);
} else if (wt == WALK_IN_ORDER) {
bst_map_tree(n->lst, mf, wt, cd);
mf(n->k, cd);
bst_map_tree(n->rst, mf, wt, cd);
} else if (wt == WALK_POST_ORDER) {
bst_map_tree(n->lst, mf, wt, cd);
bst_map_tree(n->rst, mf, wt, cd);
mf(n->k, cd);
}
}

bst_err_t bst_map (bstADT t, map_fn_t map_fn, walk_t wt, void *cd)


{
if (!t || !map_fn) {
return (BST_INVALID);
}
if ((wt == WALK_PRE_ORDER) || (wt == WALK_IN_ORDER) ||
(wt == WALK_POST_ORDER)) {
bst_map_tree(t->root, map_fn, wt, cd);
return (BST_NOERROR);
} else {
return (BST_BAD_WALK);
}
}
/*
* bst_driver.c
* Copyright (c) 2010, Irfan Iqbal
* -------
* This is the driver code for bstADT defined in `bst.h' header file.
*/
#include <stdio.h>
#include "bst.h"

void print_menu (void)


{
printf("Enter 1 to initialize BST.\n"
"Enter 2 to free BST.\n"
"Enter 3 to insert a key.\n"
"Enter 4 to delete a key.\n"
"Enter 5 to print keys.\n"
"Enter 6 to quit.\n");
return;
}

bst_err_t print_keys (bst_key_t k, void *cd)


{
printf("%d,", k);
return (BST_NOERROR);
}

int main (int argc, char *argv[])


{
bstADT my_bst = NULL;
bst_err_t rc;
bst_key_t k;
int opt;
int sub_opt;

while (1) {
print_menu();
scanf("%d", &opt);
switch (opt) {
case 1:
if (my_bst) {
printf("BST already initialized.\n");
} else {
my_bst = bst_init();
if (my_bst) {
printf("BST successfully initialized.\n");
} else {
printf("Failed to initialize BST.\n");
}
}
break;
case 2:
printf("Function not implemented yet.\n");
break;
case 3:
printf("Enter key: ");
scanf("%d", &k);
rc = bst_insert(my_bst, k);
if (rc == BST_NOERROR){
printf("Key inserted successfully inserted.\n");
} else if (rc == BST_DUP_KEY) {
printf("Duplicate key. Key not inserted.\n");
} else {
printf("Unknown error inserting key.\n");
}
break;
case 4:
printf("Function not implemented yet.\n");
break;
case 5:
printf("Enter 1 for pre-order printing.\n"
"Enter 2 for in-order printing.\n"
"Enter 3 for post-order printing. ");
scanf("%d", &sub_opt);
rc = bst_map(my_bst, print_keys, sub_opt, NULL);
printf("\n");
break;
default:
break;
}
if ((opt < 1) || (opt > 5)) {
break;
}
}
return (0);
}
/*
* symtab.h
* Copyright (c) 2010, Irfan Iqbal
* --------
* This file defines a symbol table abstract data type.
*/

#ifndef SYMTAB_H
#define SYMTAB_H

/*
* Type definitions
*/
typedef struct symtabCDT *symtabADT;
typedef int (*cmp_fn_t)(void *k1, void *k2);
typedef int (*hash_fn_t)(void *k, int num_bins);
typedef int (*map_fn_t)(void *k, void *cd);
typedef int (*del_fn_t)(void *k, void *d);
typedef enum {
SYMTAB_NOERROR,
SYMTAB_NOMEM,
SYMTAB_INVALID,
SYMTAB_EMPTY,
SYMTAB_KEY_NOT_FOUND,
SYMTAB_NO_HASH_FN,
SYMTAB_NO_CMP_FN,
SYMTAB_NO_DEL_FN,
SYMTAB_OP_FAILURE,
} symtab_err_t;

/*
* Exported API
*/
symtabADT symtab_init (void);
void symtab_free (symtabADT st);
symtab_err_t enter (symtabADT st, void *key, void *data);
symtab_err_t lookup (symtabADT st, void *key, void *data);
symtab_err_t delete (symtabADT st, void *key);
symtab_err_t set_cmp_fn (symtabADT st, cmp_fn_t cmp_fn);
symtab_err_t set_hash_fn (symtabADT st, hash_fn_t hash_fn);
symtab_err_t set_del_fn (symtabADT st, del_fn_t del_fn);
symtab_err_t map (symtabADT st, map_fn_t map_fn);

#endif /* SYMTAB_H */
/*
* symtab.c
* Copyright (c) 2010, Irfan Iqbal
* --------
*
* This file implements the symbol table abstract data type defined in
* symtab.h header file. Keys as well as their values are known only to
* client.
*/
#ifdef DEBUG
#include <stdio.h>
#endif /* DEBUG */
#include <stdlib.h>
#include <string.h>
#include "symtab.h"
#include "list-gen.h"

#define NUM_BINS 5
#define MAGIC_NUM 0xdeadcafe

struct symtabCDT {
int magic_num;
int num_bins;
int num_keys;
listADT *bin_list;
cmp_fn_t cmp_fn;
hash_fn_t hash_fn;
del_fn_t del_fn;
};

/*
* We do not know the type of `key' and the type of the corresponding
* `value'. Therefore, both are `void *'. We will store this structure
* in the linked list attached to the bin to which the given key hashes.
*/
struct key_val_pair {
void *key;
void *val;
};

/*
* This function will be passed to `list_init'. Please see `list-gen.h'
* header file for details.
*/
static int st_lst_cp_fn (void *dst, void *src)
{
memcpy(dst, src, sizeof(struct key_val_pair));
return (0);
}

/*
* This function will be passed to `list_init'. Please see `list-gen.h'
* header file for details.
*/
static int st_lst_del_fn (void *t)
{
return (0);
}

symtabADT symtab_init (void)


{
int i;
symtabADT new_st;

if (!(new_st = malloc(sizeof(struct symtabCDT)))) {


return (NULL);
}
if (!(new_st->bin_list = malloc(sizeof(listADT) * NUM_BINS))) {
free(new_st);
return (NULL);
}
new_st->magic_num = MAGIC_NUM;
new_st->num_bins = NUM_BINS;
new_st->num_keys = 0;
new_st->cmp_fn = NULL;
new_st->hash_fn = NULL;
new_st->del_fn = NULL;
for (i = 0 ; i < NUM_BINS ; ++i) {
new_st->bin_list[i] = list_init(sizeof(struct key_val_pair),
st_lst_cp_fn, st_lst_del_fn);
}
return (new_st);
}

symtab_err_t enter (symtabADT st, void *key, void *data)


{
int i;
int bin_num;
int key_found = 0;
struct key_val_pair kvp;
list_err_t rc;

if (!st || (st->magic_num != MAGIC_NUM)) {


return (SYMTAB_INVALID);
}
if (!st->hash_fn) {
return (SYMTAB_NO_HASH_FN);
}
if (!st->cmp_fn) {
return (SYMTAB_NO_CMP_FN);
}
bin_num = st->hash_fn(key, st->num_bins);
#ifdef DEBUG
printf("%%%%DEBUG: key hashes to bin %d.\n", bin_num);
#endif /* DEBUG */
if (bin_num > (st->num_bins - 1)) {
#ifdef DEBUG
printf("%%%%DEBUG: hashing function returns invalid bin number.\n");
#endif /* DEBUG */
return (SYMTAB_OP_FAILURE);
}
i = 1;
while (LIST_NOERROR == list_read(st->bin_list[bin_num], &kvp, i)) {
key_found = st->cmp_fn(key, kvp.key);
if (key_found) {
break;
}
++i;
}
kvp.val = data;
if (key_found) {
#ifdef DEBUG
printf("%%%%DEBUG: key found in symbol table.\n");
#endif /* DEBUG */
/* overwrite the value */
rc = list_write(st->bin_list[bin_num], &kvp, i);
} else {
#ifdef DEBUG
printf("%%%%DEBUG: key not found in symbol table.\n");
#endif /* DEBUG */
kvp.key = key;
/* insert this `kvp' into the listADT attached to this bin */
rc = list_insert(st->bin_list[bin_num], &kvp, 1);
++st->num_keys;
}
if (rc != LIST_NOERROR) {
/* OMG! there is some internal error */
#ifdef DEBUG
printf("%%%%DEBUG: list_write or list_insert failed.\n");
#endif /* DEBUG */
return (SYMTAB_OP_FAILURE);
}
#ifdef DEBUG
printf("%%%%DEBUG: key entered successfully.\n");
#endif /* DEBUG */
return (SYMTAB_NOERROR);
}

symtab_err_t lookup (symtabADT st, void *key, void *data)


{
int i;
int bin_num;
int key_found = 0;
struct key_val_pair kvp;
list_err_t rc;

if (!st || (st->magic_num != MAGIC_NUM)) {


return (SYMTAB_INVALID);
}
if (!st->hash_fn) {
return (SYMTAB_NO_HASH_FN);
}
if (!st->cmp_fn) {
return (SYMTAB_NO_CMP_FN);
}
bin_num = st->hash_fn(key, st->num_bins);
i = 1;
while (LIST_NOERROR == list_read(st->bin_list[bin_num], &kvp, i)) {
key_found = st->cmp_fn(key, kvp.key);
if (key_found) {
break;
}
++i;
}
if (!key_found) {
#ifdef DEBUG
printf("%%%%DEBUG: key not found in symbol table.\n");
#endif /* DEBUG */
return (SYMTAB_KEY_NOT_FOUND);
} else {
#ifdef DEBUG
printf("%%%%DEBUG: key found in symbol table.\n");
#endif /* DEBUG */
rc = list_read(st->bin_list[bin_num], &kvp, i);
if (rc != LIST_NOERROR) {
/* OMG! there is some internal error*/
#ifdef DEBUG
printf("%%%%DEBUG: list_read failed.\n");
#endif /* DEBUG */
return (SYMTAB_OP_FAILURE);
}
memcpy(data, &(kvp.val), sizeof(void *));
}
#ifdef DEBUG
printf("%%%%DEBUG: key looked up successfully.\n");
#endif /* DEBUG */
return (SYMTAB_NOERROR);
}

symtab_err_t set_cmp_fn (symtabADT st, cmp_fn_t cmp_fn)


{
if (!st || (st->magic_num != MAGIC_NUM)) {
return (SYMTAB_INVALID);
}
st->cmp_fn = cmp_fn;
return (SYMTAB_NOERROR);
}

symtab_err_t set_hash_fn (symtabADT st, hash_fn_t hash_fn)


{
if (!st || (st->magic_num != MAGIC_NUM)) {
return (SYMTAB_INVALID);
}
st->hash_fn = hash_fn;
return (SYMTAB_NOERROR);
}

symtab_err_t set_del_fn (symtabADT st, del_fn_t del_fn)


{
if (!st || (st->magic_num != MAGIC_NUM)) {
return (SYMTAB_INVALID);
}
st->del_fn = del_fn;
return (SYMTAB_NOERROR);
}
/*
* st_driver.c
* --------
* Copyright (c) 2010, Irfan Iqbal
*
* The driver code to test the functionality of symbol table ADT.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "symtab.h"

#define MAX_KEY_LEN 512


#define MULTIPLIER -1664117991L

/*
* Function to hash string type keys. It advisable to pass a prime
* number as second argument (bins).
*/
int hash_string (char key[], int bins)
{
int i;
unsigned long bin_number;

bin_number = 0;
for (i = 0 ; key[i] != '\0' ; ++i) {
bin_number = bin_number * MULTIPLIER + key[i];
}
return (bin_number % bins);
}

int key_compare (void *k1, void *k2)


{
if (0 == strcmp((char *)k1, (char *)k2)) {
return (1);
} else {
return (0);
}
}

void print_menu (void)


{
printf("Enter 1 to initialize symbol table.\n");
printf("Enter 2 to free symbol table.\n");
printf("Enter 3 to enter a key-value pair.\n");
printf("Enter 4 to lookup a key.\n");
printf("Enter 5 to delete a key.\n");
printf("Enter 6 to quit.\n");
return;
}

symtab_err_t enter_key_in_symtab (symtabADT st)


{
symtab_err_t rc;
char key_buf[MAX_KEY_LEN];
char *key;
int key_len;
int val;
void *v;

printf("Enter string key: ");


scanf("%s", key_buf);
key_len = strlen(key_buf);
key_buf[key_len] = '\0';
printf("Enter integer value: ");
scanf("%d", &val);
rc = lookup(st, key_buf, &v);
if (SYMTAB_INVALID == rc) {
printf("%%%%Symbol table corrupt or un-initialized.\n");
return (rc);
}
if (SYMTAB_KEY_NOT_FOUND == rc) {
key = malloc(sizeof(char) * key_len + 1);
strcpy(key, key_buf);
v = malloc(sizeof(int));
*(int *)v = val;
if (SYMTAB_NOERROR != (rc = enter(st, key, v))) {
printf("%%%% failed to enter key.\n");
}
} else {
*(int *)v = val;
if (SYMTAB_NOERROR != (rc = enter(st, key_buf, v))) {
printf("%%%% failed to enter key.\n");
}
}
return (rc);
}

symtab_err_t lookup_key_in_symtab (symtabADT st)


{
symtab_err_t rc;
char key_buf[MAX_KEY_LEN];
int key_len;
void *v;
printf("Enter string key: ");
scanf("%s", key_buf);
key_len = strlen(key_buf);
key_buf[key_len] = '\0';
rc = lookup(st, key_buf, &v);
if (rc == SYMTAB_KEY_NOT_FOUND) {
printf("%%%% key not found in symbol table.\n");
} else if (rc == SYMTAB_NOERROR) {
printf("%%%% key found. value is %d\n", *(int *)v);
}
return (rc);
}

int main (int argc, char *argv[])


{
symtabADT st;
int opt;

while (1) {
print_menu();
scanf("%d", &opt);
switch (opt) {
case 1:
if (!(st = symtab_init())) {
printf("%%%%Unable to initialize symbol table.\n");
break;
}
set_cmp_fn(st, key_compare);
set_hash_fn(st, (int(*)(void *, int))hash_string);
break;
case 2:
/* function not implemented yet. */
printf("%%%%Function not implemented.\n");
break;
case 3:
enter_key_in_symtab(st);
break;
case 4:
lookup_key_in_symtab(st);
break;
case 5:
/* function not implemented yet. */
printf("%%%%Function not implemented.\n");
break;
}
if ((opt < 1) || (opt > 5)) {
break;
}
}
return (0);
}

Вам также может понравиться