feat: working wf
This commit is contained in:
parent
39fd68c0c8
commit
4bbd2c2be6
239
labs/cs2106/labs/lab4/linkedlist/llist.c
Normal file
239
labs/cs2106/labs/lab4/linkedlist/llist.c
Normal file
@ -0,0 +1,239 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#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;
|
||||
}
|
114
labs/cs2106/labs/lab4/linkedlist/llist.h
Normal file
114
labs/cs2106/labs/lab4/linkedlist/llist.h
Normal file
@ -0,0 +1,114 @@
|
||||
|
||||
// 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 {
|
||||
int val;
|
||||
} 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);
|
25
labs/cs2106/labs/lab4/linkedlist/mymalloc.c
Normal file
25
labs/cs2106/labs/lab4/linkedlist/mymalloc.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "mymalloc.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) {
|
||||
}
|
||||
|
||||
// Frees memory pointer to by ptr.
|
||||
void myfree(void *ptr) {
|
||||
}
|
||||
|
5
labs/cs2106/labs/lab4/linkedlist/mymalloc.h
Normal file
5
labs/cs2106/labs/lab4/linkedlist/mymalloc.h
Normal file
@ -0,0 +1,5 @@
|
||||
#define MEMSIZE 64 * 1024 // Size of memory in bytes
|
||||
|
||||
long get_index(void *ptr);
|
||||
void *mymalloc(size_t);
|
||||
void myfree(void *);
|
178
labs/cs2106/labs/lab4/linkedlist/testlist.c
Normal file
178
labs/cs2106/labs/lab4/linkedlist/testlist.c
Normal file
@ -0,0 +1,178 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "llist.h"
|
||||
|
||||
#define COUNT 10
|
||||
|
||||
void print_node(TNode *node) {
|
||||
if(node != NULL)
|
||||
printf("Key: %d\n", node->key);
|
||||
else
|
||||
printf("Unable to find key.\n");
|
||||
}
|
||||
|
||||
void free_data(TNode *node) {
|
||||
free(node->pdata);
|
||||
}
|
||||
|
||||
void trav_list(TNode *llist) {
|
||||
reset_traverser(llist, FRONT);
|
||||
TNode *node;
|
||||
|
||||
do {
|
||||
node = succ(llist);
|
||||
if(node)
|
||||
print_node(node);
|
||||
} while(node != NULL);
|
||||
}
|
||||
|
||||
void rev_trav_list(TNode *llist) {
|
||||
reset_traverser(llist, REAR);
|
||||
TNode *node;
|
||||
|
||||
do{
|
||||
node = pred(llist);
|
||||
if(node)
|
||||
print_node(node);
|
||||
} while(node != NULL);
|
||||
}
|
||||
|
||||
|
||||
int main(){
|
||||
TNode *llist = NULL;
|
||||
|
||||
int test_array[COUNT] = {10, 6, 2, 8, 1, 4, 5, 3, 9, 7};
|
||||
|
||||
// Insert
|
||||
|
||||
char c;
|
||||
printf("Hit enter to start ascending order test\n");
|
||||
scanf("%c", &c);
|
||||
|
||||
int i;
|
||||
printf("Inserting in ascending order\n");
|
||||
TData *data;
|
||||
TNode *node;
|
||||
|
||||
for(i=0; i<COUNT; i++) {
|
||||
data = (TData *) malloc(sizeof(TData));
|
||||
data->val = test_array[i];
|
||||
node = make_node(test_array[i], data);
|
||||
insert_node(&llist, node, ASCENDING);
|
||||
}
|
||||
|
||||
printf("Printing entire list\n");
|
||||
process_list(llist, print_node);
|
||||
printf("\n");
|
||||
|
||||
printf("Printing entire list using reverse traversal\n");
|
||||
rev_trav_list(llist);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 2\n");
|
||||
node = find_node(llist, 2);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 2\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 2\n");
|
||||
node = find_node(llist, 2);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 5\n");
|
||||
node = find_node(llist, 5);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 5\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 5\n");
|
||||
node = find_node(llist, 5);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 22\n");
|
||||
node = find_node(llist, 22);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 22\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 22\n");
|
||||
node = find_node(llist, 22);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Purging list\n");
|
||||
process_list(llist, free_data);
|
||||
purge_list(&llist);
|
||||
|
||||
printf("Printing entire list\n");
|
||||
process_list(llist, print_node);
|
||||
printf("\n");
|
||||
|
||||
printf("Hit enter to start descending order test\n");
|
||||
scanf("%c", &c);
|
||||
|
||||
printf("Inserting in descending order\n");
|
||||
for(i=0; i<COUNT; i++) {
|
||||
TNode *node = make_node(test_array[i], NULL);
|
||||
insert_node(&llist, node, DESCENDING);
|
||||
}
|
||||
|
||||
printf("Printing entire list\n");
|
||||
process_list(llist, print_node);
|
||||
printf("\n");
|
||||
|
||||
printf("Printing entire list using reverse traversal\n");
|
||||
rev_trav_list(llist);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 2\n");
|
||||
node = find_node(llist, 2);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 2\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 2\n");
|
||||
node = find_node(llist, 2);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 5\n");
|
||||
node = find_node(llist, 5);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 5\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 5\n");
|
||||
node = find_node(llist, 5);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Searching for 22\n");
|
||||
node = find_node(llist, 22);
|
||||
print_node(node);
|
||||
|
||||
printf("Deleting node 22\n");
|
||||
delete_node(&llist, node);
|
||||
|
||||
printf("Searching for 22\n");
|
||||
node = find_node(llist, 22);
|
||||
print_node(node);
|
||||
printf("\n");
|
||||
|
||||
printf("Purging list\n");
|
||||
process_list(llist, free_data);
|
||||
purge_list(&llist);
|
||||
|
||||
printf("Printing entire list\n");
|
||||
process_list(llist, print_node);
|
||||
printf("\n");
|
||||
|
||||
}
|
36
labs/cs2106/labs/lab4/linkedlist/testmalloc.c
Normal file
36
labs/cs2106/labs/lab4/linkedlist/testmalloc.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
void testalloc(long size, char *ptrname, char **ptr) {
|
||||
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
|
||||
*ptr = mymalloc(size);
|
||||
|
||||
if(*ptr == NULL)
|
||||
printf("Allocation failed.\n");
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
void testfree(char *ptr, char *ptrname) {
|
||||
printf("\nFreeing %s\n", ptrname);
|
||||
myfree(ptr);
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
int main() {
|
||||
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
testalloc(2048, "ptr1", &ptr1);
|
||||
testalloc(6144, "ptr2", &ptr2);
|
||||
testalloc(1024, "ptr3", &ptr3);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(2048, "ptr2", &ptr2);
|
||||
testalloc(4096, "ptr4", &ptr4);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(3072, "ptr5", &ptr5);
|
||||
testfree(ptr1, "ptr1");
|
||||
testfree(ptr2, "ptr2");
|
||||
testfree(ptr3, "ptr3");
|
||||
testfree(ptr4, "ptr4");
|
||||
testfree(ptr5, "ptr5");
|
||||
|
||||
}
|
13
labs/cs2106/labs/lab4/linkedlist/wf/Makefile
Normal file
13
labs/cs2106/labs/lab4/linkedlist/wf/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
.PHONY: run test
|
||||
|
||||
run: harness-wf
|
||||
./harness-wf
|
||||
|
||||
test: testmalloc
|
||||
./testmalloc
|
||||
|
||||
harness-wf: harness-wf.c llist.c mymalloc.c
|
||||
gcc $^ -o $@
|
||||
|
||||
testmalloc: testmalloc.c mymalloc.c llist.c
|
||||
gcc $^ -o $@
|
55
labs/cs2106/labs/lab4/linkedlist/wf/harness-wf.c
Normal file
55
labs/cs2106/labs/lab4/linkedlist/wf/harness-wf.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
void *runmalloc(size_t len, long expected_ndx) {
|
||||
|
||||
long ndx;
|
||||
void *ptr;
|
||||
|
||||
printf("Allocate %ld bytes.\n", len);
|
||||
printf("Before: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
ptr = mymalloc(len);
|
||||
ndx = get_index((void *) ptr);
|
||||
printf("EXPECTED: %ld ACTUAL: %ld\n", expected_ndx, ndx);
|
||||
printf("After: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
assert(ndx == expected_ndx);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void runfree(void *ptr) {
|
||||
printf("Free\n");
|
||||
printf("Before: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
myfree(ptr);
|
||||
printf("After: ");
|
||||
print_memlist();
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
void *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
ptr1 = runmalloc(4, 0);
|
||||
ptr2 = runmalloc(32, 4);
|
||||
ptr3 = runmalloc(2, 36);
|
||||
runfree(ptr2);
|
||||
ptr2 = runmalloc(12, 38);
|
||||
ptr4 = runmalloc(24, 50);
|
||||
ptr5 = runmalloc(18, 74);
|
||||
runfree(ptr1);
|
||||
ptr1 = runmalloc(2, 92);
|
||||
runfree(ptr1);
|
||||
runfree(ptr2);
|
||||
runfree(ptr3);
|
||||
runfree(ptr4);
|
||||
runfree(ptr5);
|
||||
}
|
||||
|
||||
|
239
labs/cs2106/labs/lab4/linkedlist/wf/llist.c
Normal file
239
labs/cs2106/labs/lab4/linkedlist/wf/llist.c
Normal file
@ -0,0 +1,239 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#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;
|
||||
}
|
115
labs/cs2106/labs/lab4/linkedlist/wf/llist.h
Normal file
115
labs/cs2106/labs/lab4/linkedlist/wf/llist.h
Normal file
@ -0,0 +1,115 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// 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);
|
103
labs/cs2106/labs/lab4/linkedlist/wf/mymalloc.c
Normal file
103
labs/cs2106/labs/lab4/linkedlist/wf/mymalloc.c
Normal file
@ -0,0 +1,103 @@
|
||||
#include "mymalloc.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/_types/_null.h>
|
||||
|
||||
#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); }
|
7
labs/cs2106/labs/lab4/linkedlist/wf/mymalloc.h
Normal file
7
labs/cs2106/labs/lab4/linkedlist/wf/mymalloc.h
Normal file
@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#define MEMSIZE 64 * 1024 // Size of memory in bytes
|
||||
|
||||
long get_index(void *ptr);
|
||||
void print_memlist();
|
||||
void *mymalloc(size_t);
|
||||
void myfree(void *);
|
36
labs/cs2106/labs/lab4/linkedlist/wf/testmalloc.c
Normal file
36
labs/cs2106/labs/lab4/linkedlist/wf/testmalloc.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include "mymalloc.h"
|
||||
|
||||
void testalloc(long size, char *ptrname, char **ptr) {
|
||||
printf("\nAllocating %ld bytes to %s\n", size, ptrname);
|
||||
*ptr = mymalloc(size);
|
||||
|
||||
if(*ptr == NULL)
|
||||
printf("Allocation failed.\n");
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
void testfree(char *ptr, char *ptrname) {
|
||||
printf("\nFreeing %s\n", ptrname);
|
||||
myfree(ptr);
|
||||
print_memlist();
|
||||
}
|
||||
|
||||
int main() {
|
||||
char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
|
||||
|
||||
testalloc(2048, "ptr1", &ptr1);
|
||||
testalloc(6144, "ptr2", &ptr2);
|
||||
testalloc(1024, "ptr3", &ptr3);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(2048, "ptr2", &ptr2);
|
||||
testalloc(4096, "ptr4", &ptr4);
|
||||
testfree(ptr2, "ptr2");
|
||||
testalloc(3072, "ptr5", &ptr5);
|
||||
testfree(ptr1, "ptr1");
|
||||
testfree(ptr2, "ptr2");
|
||||
testfree(ptr3, "ptr3");
|
||||
testfree(ptr4, "ptr4");
|
||||
testfree(ptr5, "ptr5");
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user