diff --git a/labs/cs2106/labs/lab4/linkedlist/pb/bintree.c b/labs/cs2106/labs/lab4/linkedlist/pb/bintree.c new file mode 100644 index 0000000..0365c92 --- /dev/null +++ b/labs/cs2106/labs/lab4/linkedlist/pb/bintree.c @@ -0,0 +1,192 @@ +#include "bintree.h" +#include "mymalloc.h" +#include +#include + +/* ------------------------- DO NOT IMPLEMENT THESE ---------------------- + +These are provided "free" to you, and you do not need to implement them, +though you MAY need to understand what they do. Some give you hints +on how to work with pointers to pointers. You MAY find some of these +functions useful. + + ------------------------------------------------------------------------- */ + +// Searches for the node containing "name" in the tree whose root is at "root", +// returning both the node ifself in "node", and its parent in "prevnode" +// (useful for deleting node). Both "node" and "prevnode" are set to NULL +// if name is not found in the tree. + +void findNode(char *name, TTreeNode *root, TTreeNode **node, + TTreeNode **prevnode) { + + TTreeNode *trav = root; + TTreeNode *prev = NULL; + + while (trav != NULL) { + int cmp = strcmp(trav->name, name); + + if (cmp == 0) { + *node = trav; + *prevnode = prev; + return; + } + + prev = trav; + if (cmp < 0) + trav = trav->right; + else + trav = trav->left; + } + + *node = NULL; + *prevnode = NULL; +} + +// Searches for the node with the smallest value ("smallest node") in the tree +// originating at "node". Returns the smallest node and its parent in +// "smallest_node" and "parent" respectively. +void findSmallest(TTreeNode *node, TTreeNode **smallest_node, + TTreeNode **parent) { + TTreeNode *trav = node; + TTreeNode *prev = NULL; + + if (trav == NULL) + return; + + while (trav->left != NULL) { + prev = trav; + trav = trav->left; + } + + *smallest_node = trav; + *parent = prev; +} + +// Delete a node at "node" with parent node "prevnode" +void delNode(TTreeNode *node, TTreeNode *prevnode) { + // This is a leaf node + if (node->left == NULL && node->right == NULL) { + // See whether node is on parent's left or right, and NULL the + // corresponding pointer + + int cmp = strcmp(prevnode->name, node->name); + + // Previous node is smaller than this one. This + // node is on the right + if (cmp < 0) + prevnode->right = NULL; + else + prevnode->left = NULL; + + freenode(node); + + return; + } + + // This has a child on the left only + if (node->right == NULL) { + // Copy the right child over + node = node->left; + freenode(node->left); + return; + } + + // This has a child on the right only + if (node->left == NULL) { + node = node->right; + freenode(node->right); + return; + } + + // This has children on both nodes + TTreeNode *smallest, *smallest_parent; + findSmallest(node->right, &smallest, &smallest_parent); + node = smallest; + smallest_parent->left = NULL; + freenode(smallest); +} + +/* ---------------------------- IMPLEMENT THESE --------------------------- */ + +// Create a new node with name set to "name" and +// phoneNum set to "phoneNum". +void delTree(TTreeNode *root) { + // Implement deleting the entire tree, whose + // root is at "root". + if (root == NULL) + return; + if (root->left != NULL) + delTree(root->left); + if (root->right != NULL) + delTree(root->right); + freenode(root); +} + +TTreeNode *makeNewNode(char *name, char *phoneNum) { + TTreeNode *node = mymalloc(sizeof(TTreeNode)); + node->name = mymalloc(strlen(name) + 1); + strcpy(node->name, name); + strcpy(node->phoneNum, phoneNum); + node->left = NULL; + node->right = NULL; + return node; + // Implement makeNewNode to create a new + // TTreeNode containing name and phoneNum +} + +// Add a new node to the tree. +// Note that "root" is a POINTER to the tree's root, +// not the root itself. + +void addNode(TTreeNode **root, TTreeNode *node) { + if (*root == NULL) { + *root = node; + } + + TTreeNode **trav = root; + + while (1) { + + int cmp = strcmp((*trav)->name, node->name); + if (cmp == 0) + return; + if (cmp > 0) { + if ((*trav)->left == NULL) + (*trav)->left = node; + else { + trav = &((*trav)->left); + continue; + } + } else if (cmp < 0) { + if ((*trav)->right == NULL) + (*trav)->right = node; + else { + trav = &((*trav)->right); + continue; + } + } + } + + // Add a new node to the tree, where root is + // the POINTER to the tree's root. +} + +void freenode(TTreeNode *node) { + myfree(node->name); + myfree(node); + // Frees the memory used by node. +} + +void print_inorder(TTreeNode *node) { + // Implement in-order printing of the tree + // Recursion is probably best here. + + if (node == NULL) + return; + if (node->left != NULL) + print_inorder(node->left); + printf("Name is %s Number is %s\n", node->name, node->phoneNum); + if (node->right != NULL) + print_inorder(node->right); +} diff --git a/labs/cs2106/labs/lab4/linkedlist/pb/bintree.h b/labs/cs2106/labs/lab4/linkedlist/pb/bintree.h new file mode 100644 index 0000000..7f4744d --- /dev/null +++ b/labs/cs2106/labs/lab4/linkedlist/pb/bintree.h @@ -0,0 +1,17 @@ +#include +#include + +typedef struct tn { + char *name; + char phoneNum[9]; + struct tn *left, *right; +} TTreeNode; + +void findNode(char *, TTreeNode *, TTreeNode **, TTreeNode **); +void findSmallest(TTreeNode *, TTreeNode **, TTreeNode **); +void delNode(TTreeNode *, TTreeNode *); +void delTree(TTreeNode *); +TTreeNode *makeNewNode(char *, char *); +void addNode(TTreeNode **, TTreeNode *); +void freenode(TTreeNode *); +void print_inorder(TTreeNode *); diff --git a/labs/cs2106/labs/lab4/linkedlist/pb/llist.c b/labs/cs2106/labs/lab4/linkedlist/pb/llist.c new file mode 100644 index 0000000..22398a9 --- /dev/null +++ b/labs/cs2106/labs/lab4/linkedlist/pb/llist.c @@ -0,0 +1,239 @@ +#include +#include +#include + +#include "llist.h" + +//#define DEBUG // Enable debug printing + +// Debug printer + +void dbprintf(char *format, ...) { +#ifdef DEBUG + va_list args; + + va_start(args, format); + vprintf(format, args); +#endif +} + +// Implements a double linked list. + +// Create a new node. You need to +// Create your own TData node, populate +// it, then create a new node with a suitable +// key. Insertion into the link list is +// by ascending order of the key. An example key +// might be the starting address of a memory segment. + +TNode *make_node(unsigned int key, TData *data) { + TNode *node = malloc(sizeof(TNode)); + node->key = key; + node->pdata = data; + node->prev = NULL; + node->next = NULL; + + return node; +} + +// Inserts a node into the correct point of the +// double linked list. The list is sorted +// in ascending order of the key. Duplicate keys +// are permitted, though not recommended. +// llist = Pointer to link list +// node = Pointer to node created by make_node +// dir = 0: Insert in ascending order +// dir = 1: Insert in descending order + +void insert_node(TNode **llist, TNode *node, int dir) { + if(*llist == NULL) { + *llist = node; + (*llist)->trav = *llist; + (*llist)->tail = *llist; + } + else + if(((*llist)->key >= node->key && dir == 0) || (((*llist)->key <= node->key) && dir == 1)) { + node->next = *llist; + (*llist)->prev = node; + *llist = node; + (*llist)->trav = *llist; + } + else + { + TNode *trav = *llist; + + if(dir == 0) + while(trav->next != NULL && trav->key < node->key) + trav = trav->next; + else if(dir == 1) + while(trav->next != NULL && trav->key > node->key) + trav = trav->next; + + if(trav->next == NULL && ((trav->key < node->key && dir == 0) || + (trav->key > node->key && dir == 1))) { + trav->next = node; + node->prev = trav; + + // Set the tail + (*llist)->tail = node; + } else { + // Insert into the previous space + + node->next = trav; + + if(trav->prev != NULL) { + trav->prev->next = node; + node->prev = trav->prev; + } + + if(trav->next != NULL) { + } + + trav->prev = node; + } + } +} + +// Remove a given node from the linked list +void delete_node(TNode **llist, TNode *node) { + + if(*llist == NULL || node == NULL) + return; + + if((*llist)->key == node->key) { + // Node to be deleted is at the front of the list. + *llist = (*llist)->next; + + // Ensure that we don't point to it anymore. + if(*llist != NULL) + (*llist)->prev = NULL; + } + else + { + TNode *trav = *llist; + + while(trav != NULL && trav->key != node->key) + trav = trav->next; + + // We've found the deletion point + if(trav != NULL) { + trav->prev->next = trav->next; + + if(trav->next != NULL) + trav->next->prev = trav->prev; + else + (*llist)->tail = trav->prev; + } + + } + + free(node); +} + +// Find a node that has the value of key +// If there are duplicate keys, the first one encountered +// will be returned. +TNode *find_node(TNode *llist, unsigned int key) { + if(llist == NULL) + return NULL; + + TNode *trav = llist; + + while(trav != NULL && trav->key != key) + trav = trav->next; + + return trav; +} + +// Merge the node provided with either the node after or the node before. +// You need to manage merging the data in node->pdata yourself. This code just +// deletes the larger of the two nodes. +// dir = 0: Merge with node before +// dir = 1: Merge with node after + +void merge_node(TNode *llist, TNode *node, int dir) { + if(dir == 0) { + if(node->prev == NULL) + return; + + delete_node(&llist, node); + } + else + if(dir == 1) { + if(node->next == NULL) + return; + + delete_node(&llist, node->next); + } +} + +// Go over every element of llist, and call func +// func prototype is void func(TNode *); + +void process_list(TNode *llist, void (*func)(TNode *)) { + TNode *trav = llist; + while(trav) { + func(trav); + trav = trav->next; + } + +} + + +// Purge the entire list. You must +// free any dynamic data in the TData +// struct yourself. +void purge_list(TNode **llist) { + TNode *trav = *llist, *tmp; + while(trav) { + tmp = trav->next; + free(trav); + trav = tmp; + } + + *llist = NULL; +} + + +// Reset traverser +// where=0 START: Resets traverser to start of list +// where=1 END: Rsets +void reset_traverser(TNode *llist, int where) +{ + if(llist == NULL) + return; + + if(where == FRONT) + llist->trav = llist; + else + if(where == REAR) + llist->trav = llist->tail; +} + +// Get the next node +TNode *succ(TNode *llist) +{ + if(llist == NULL) + return NULL; + + TNode *ret = llist->trav; + + if(llist->trav != NULL) + llist->trav = llist->trav->next; + + return ret; +} + +// Get the previous node +TNode *pred(TNode *llist) +{ + if(llist == NULL) + return NULL; + + TNode *ret = llist->trav; + + if(llist->trav != NULL) + llist->trav = llist->trav->prev; + + return ret; +} diff --git a/labs/cs2106/labs/lab4/linkedlist/pb/llist.h b/labs/cs2106/labs/lab4/linkedlist/pb/llist.h new file mode 100644 index 0000000..23624a9 --- /dev/null +++ b/labs/cs2106/labs/lab4/linkedlist/pb/llist.h @@ -0,0 +1,115 @@ +#include +#include + +// Uncomment the next line to enable debug printing +#define DEBUG // Enable debug printing + +// The debug printer; used like a normal printf, except +// that printing can be turned off by commenting out the +// #define DEBUG above. +void dbprintf(char *format, ...); + +// You should modify this structure to hold +// whatever you need to implement your +// memory manager. You can delete the +// val field. It is only used for testlist.c + +typedef struct td { + bool occupied; + size_t size; +} TData; + +/* ----------------------------------------- + BASIC ROUTINES + + Basic linked list routines + + ---------------------------------------- */ + +// Basic double linked list node. + +typedef struct tn { + unsigned int key; + TData *pdata; // Pointer to the data you want to store + + struct tn *trav; // Only used in the root for traversal + struct tn *tail; // Only used in the root for finding the end of the list + struct tn *prev; + struct tn *next; +} TNode; + +// Insert Direction +#define ASCENDING 0 +#define DESCENDING 1 + +// Merge direction +#define PRECEDING 0 +#define SUCCEEDING 1 + +// Traverser position +#define FRONT 0 +#define REAR 1 + +// Create a new node. You need to +// Create your own TData node, populate +// it, then create a new node with a suitable +// key. Insertion into the link list is +// by ascending order of the key. An example key +// might be the starting address of a memory segment. + +TNode *make_node(unsigned int key, TData *data); + +// Inserts a node into the correct point of the +// double linked list. The list is sorted +// in ascending order of the key. Duplicate keys +// are permitted, though not recommended. +// llist = Pointer to link list +// node = Pointer to node created by make_node +// dir = 0: Insert in ascending order +// dir = 1: Insert in descending order + +void insert_node(TNode **llist, TNode *node, int dir); + +// Remove a given node from the linked list +void delete_node(TNode **llist, TNode *node); + +// Find a node that has the value of key +// If there are duplicate keys, the first one encountered +// will be returned. +TNode *find_node(TNode *llist, unsigned int key); + +// Merge the node provided with either the node after or the node before. +// You need to manage merging the data in node->pdata yourself. This code just +// deletes the larger of the two nodes. +// dir = 0: Merge with node before +// dir = 1: Merge with node after + +void merge_node(TNode *llist, TNode *node, int dir); + +// Purge the entire list. You must +// free any dynamic data in the TData +// struct yourself. +void purge_list(TNode **llist); + +/* ----------------------------------------- + TRAVERSAL ROUTINES + + Lets you traverse the linked list + + ---------------------------------------- */ + +// Go over every element of llist, and call func +// func prototype is void func(TNode *); + +void process_list(TNode *llist, void (*func)(TNode *)); + +// Reset traverser +// where=0 START: Resets traverser to start of list +// where=1 END: Rsets +void reset_traverser(TNode *llist, int where); + +// Get the next node +TNode *succ(TNode *llist); + +// Get the previous node +TNode *pred(TNode *llist); diff --git a/labs/cs2106/labs/lab4/linkedlist/pb/mymalloc.c b/labs/cs2106/labs/lab4/linkedlist/pb/mymalloc.c new file mode 100644 index 0000000..f4e0366 --- /dev/null +++ b/labs/cs2106/labs/lab4/linkedlist/pb/mymalloc.c @@ -0,0 +1,103 @@ +#include "mymalloc.h" + +#include +#include +#include +#include + +#include "llist.h" + +char _heap[MEMSIZE] = {0}; +TNode *_memlist = NULL; // To maintain information about length + +// Do not change this. Used by the test harness. +// You may however use this function in your code if necessary. +long get_index(void *ptr) { + if (ptr == NULL) + return -1; + else + return (long)((char *)ptr - &_heap[0]); +} + +// Allocates size bytes of memory and returns a pointer +// to the first byte. +void *mymalloc(size_t size) { + if (_memlist == NULL) { + TData *data = malloc(sizeof(TData)); + data->occupied = false; + data->size = MEMSIZE; + _memlist = make_node(0, data); + } + + // loop through the list to find a free block + // if found, split the block and return the pointer + // if not found, return NULL + TNode *curr = _memlist; + TNode *best = NULL; + while (curr != NULL) { + if (curr->pdata->occupied == true) { + curr = curr->next; + continue; + } + if (curr->pdata->size < size) { + curr = curr->next; + continue; + } + if (best == NULL) { + best = curr; + curr = curr->next; + continue; + } + if (best->pdata->size > curr->pdata->size) { + best = curr; + curr = curr->next; + continue; + } + curr = curr->next; + } + if (best == NULL) + return NULL; + best->pdata->occupied = true; + if (best->pdata->size > size) { + // Create a new node with the leftover space + TData *newData = malloc(sizeof(TData)); + newData->occupied = false; + newData->size = best->pdata->size - size; + TNode *newNode = make_node(best->key + size, newData); + // insert new node after the current one in the list. + insert_node(&_memlist, newNode, 0); + // change the size of the current node. + best->pdata->size = size; + } + return &_heap[best->key]; +} + +// Frees memory pointer to by ptr. +void myfree(void *ptr) { + if (ptr == NULL) + return; + long index = get_index(ptr); + TNode *node = find_node(_memlist, index); + if (node == NULL) + return; + node->pdata->occupied = false; + // merge with the next node if it is free + while (node->next != NULL && node->next->pdata->occupied == false) { + node->pdata->size += node->next->pdata->size; + merge_node(_memlist, node, 1); + } + + while (node->prev != NULL && node->prev->pdata->occupied == false) { + TNode *prev = node->prev; + prev->pdata->size += node->pdata->size; + merge_node(_memlist, node, 0); + } +} + +void print_node(TNode *node) { + printf("Status: %s Start index: %d Length: %zu\n", + node->pdata->occupied ? "ALLOCATED" : "FREE", node->key, + node->pdata->size); +} + +void print_memlist() { process_list(_memlist, print_node); } diff --git a/labs/cs2106/labs/lab4/linkedlist/pb/mymalloc.h b/labs/cs2106/labs/lab4/linkedlist/pb/mymalloc.h new file mode 100644 index 0000000..9fe7bac --- /dev/null +++ b/labs/cs2106/labs/lab4/linkedlist/pb/mymalloc.h @@ -0,0 +1,7 @@ +#include +#define MEMSIZE 64 * 1024 // Size of memory in bytes + +long get_index(void *ptr); +void print_memlist(); +void *mymalloc(size_t); +void myfree(void *); diff --git a/labs/cs2106/labs/lab4/linkedlist/pb/phonebook.c b/labs/cs2106/labs/lab4/linkedlist/pb/phonebook.c new file mode 100644 index 0000000..8b58851 --- /dev/null +++ b/labs/cs2106/labs/lab4/linkedlist/pb/phonebook.c @@ -0,0 +1,51 @@ +#include +#include "phonebook.h" +#include "bintree.h" + +static TTreeNode *_root = NULL; + +char *findPerson(char *name) +{ + TTreeNode *node, *prev; + findNode(name, _root, &node, &prev); + + if (node != NULL) + return node->phoneNum; + else + return NULL; +} + +void print_phonebook() +{ + print_inorder(_root); +} + +void addPerson(char *name, char *phoneNum) +{ + if (findPerson(name) == NULL) + { + TTreeNode *node = makeNewNode(name, phoneNum); + addNode(&_root, node); + } + else + printf("%s is already in phonebook.\n", name); +} + +void delPerson(char *name) +{ + TTreeNode *node, *prevnode; + findNode(name, _root, &node, &prevnode); + if (node == NULL) + { + printf("Unable to find %s\n", name); + return; + } + + delNode(node, prevnode); +} + +void delPhonebook() +{ + delTree(_root); + _root = NULL; +} diff --git a/labs/cs2106/labs/lab4/linkedlist/pb/phonebook.h b/labs/cs2106/labs/lab4/linkedlist/pb/phonebook.h new file mode 100644 index 0000000..539cd43 --- /dev/null +++ b/labs/cs2106/labs/lab4/linkedlist/pb/phonebook.h @@ -0,0 +1,5 @@ +char *findPerson(char *); +void addPerson(char *, char *); +void delPerson(char *); +void print_phonebook(); +void delPhonebook(); diff --git a/labs/cs2106/labs/lab4/linkedlist/pb/testpb.c b/labs/cs2106/labs/lab4/linkedlist/pb/testpb.c new file mode 100644 index 0000000..5a85e56 --- /dev/null +++ b/labs/cs2106/labs/lab4/linkedlist/pb/testpb.c @@ -0,0 +1,60 @@ +#include +#include "phonebook.h" + +#define ITEMS 5 + +typedef struct d +{ + char *name, *tel; +} TData; + +void printResult(char *name) +{ + char *result; + + printf("Looking for %s ", name); + result = findPerson(name); + if (result == NULL) + printf("NOT FOUND\n"); + else + printf(" Number is %s\n", result); +} + +int main() +{ + TData data[ITEMS] = {{"Fred Astaire", "95551234"}, {"Jean Valjean", "95558764"}, {"Gal Gadot", "95551123"}, {"Aiken Dueet", "95558876"}, {"Victor Hugo", "95524601"}}; + + int i; + + for (i = 0; i < ITEMS; i++) + { + printf("Adding %s, phone number %s\n", data[i].name, data[i].tel); + addPerson(data[i].name, data[i].tel); + } + + printf("\nNow retrieiving stored data.\n"); + char *result; + + for (i = 0; i < ITEMS; i++) + { + printResult(data[i].name); + } + + printf("\nRetrieving unknown person.\n"); + printResult("Wee Tu Loh"); + + printf("\nPrinting entire phonebook.\n"); + print_phonebook(); + + printf("\nDeleting Aiken Dueet.\n"); + delPerson("Aiken Dueet"); + print_phonebook(); + + printf("\nDeleting Victor Hugo.\n"); + delPerson("Victor Hugo"); + print_phonebook(); + + printf("\nDeleting entire phone book.\n"); + delPhonebook(); + print_phonebook(); +}