#include "general-list.h" #include #include "smartall.h" /**** * * Implementation of general-list.h. * * This is the solution to the deliverable for Lab 2 -- the translation of * GeneralList.java into C. All other supporting C files are provided as part * of the lab materials, including general-list.h. * * This version of the solution is compiled with the smartalloc functions to * provide information about memory leaks. */ GeneralList* newGeneralList() { /* * Allocate the new list. */ GeneralList* newlist = newc(GeneralList); /* * Initialize the front and back pointers to null. */ newlist->first = null; newlist->last = null; /* * Set the length to 0. */ newlist->length = 0; /* * Set sorted to false. */ newlist->sorted = false; /* * Return the new list. */ return newlist; } GeneralList* newGeneralListArray(char* array[], int numElems) { GeneralList* newlist = newc(GeneralList); /* new list */ int i; /* Array traversal index */ /* * Copy in the array elements into the list. */ for (i = 0; i < numElems; i++) { putLast(newlist, array[i]); } /* * Set sorted to false. */ newlist->sorted = false; /* * Return the new list. */ return newlist; } /*-* * Constructive (i.e., storage) methods */ GeneralList* putFirst(GeneralList* list, char* element) { /* * If the list is currently empty, make a GeneralListNode for the given * element and make it the first and last in the list. */ if (list->first == null) { list->first = list->last = newGeneralListNode(element); list->length = 1; } /* * Otherwise, make a new node and splice it into the front. */ else { list->first = list->first->prev = newGeneralListNodeLinked(element, null, list->first); list->length++; } /* * Set sorted false in case it is. */ list->sorted = false; return list; } GeneralList* putLast(GeneralList* list, char* element) { /* * If the list is currently empty, make a GeneralListNode for the given * element and make it the first and last in the list. */ if (list->first == null) { list->first = list->last = newGeneralListNode(element); list->length = 1; } /* * Otherwise, make a new node and splice it into the back. */ else { list->last = list->last->next = newGeneralListNodeLinked(element, list->last, null); list->length++; } /* * Set sorted false in case it is. */ list->sorted = false; return list; } GeneralList* put(GeneralList* list, char* element, int i) { GeneralListNode* ithNode; /* The located ith node */ GeneralListNode* newNode; /* New node to splice in */ /* * Outta here if i < 0 or i > length. */ if ((i < 0) || (i > list->length)) { return list; } /* * If i = 0 or length, call putFirst putLast, resp. */ if (i == 0) { return putFirst(list, element); } if (i == list->length) { return putLast(list, element); } /* * Get the ith node via the O(N/2) method. */ ithNode = getIthNode(list, i); /* * Splice in a new node before the ith spot. */ newNode = newGeneralListNodeLinked(element, ithNode->prev, ithNode); ithNode->prev = ithNode->prev->next = newNode; list->length++; /* * Set sorted false in case it is. */ list->sorted = false; return list; } GeneralList* set(GeneralList* list, char* element, int i) { GeneralListNode* ithNode; /* The located ith node */ /* * Get the ith node via the O(N/2) method. */ ithNode = getIthNode(list, i); /* * Set the ith value. */ ithNode->value = element; /* * Set sorted false in case it is. */ list->sorted = false; return list; } char* getFirst(GeneralList* list) { return list->first->value; } char* getLast(GeneralList* list) { return list->last->value; } char* get(GeneralList* list, int i) { return getIthNode(list, i)->value; } char* removeFirst(GeneralList* list) { GeneralListNode* node; /* Node to be removed */ /* * Outta here if we're empty. */ if (list->first == null) { return null; } /* * Handle length = 1 case separate since it alone affects value of * last pointer. */ if (list->length == 1) { node = list->first; list->first = list->last = null; list->length = 0; return node->value; } /* * Splice out the first node and return its value. */ node = list->first; list->first = list->first->next; list->first->prev = null; list->length--; return node->value; } char* removeLast(GeneralList* list) { GeneralListNode* node; /* Node to be removed */ /* * Outta here if we're empty. */ if (list->first == null) { return null; } /* * Handle length = 1 case separate since it alone affects value of * last pointer. */ if (list->length == 1) { node = list->first; list->first = list->last = null; list->length = 0; return node->value; } /* * Splice out the last node and return its value. */ node = list->last; list->last = list->last->prev; list->last->next = null; list->length--; return node->value; } char* removeIth(GeneralList* list, int i) { GeneralListNode* node; /* Node to be removed */ /* * Outta here if i < 0 or i > length. */ if ((i < 0) || (i >= list->length)) { return null; } /* * If i = 0 or length, call removeFirst removeLast, resp. */ if (i == 0) { return removeFirst(list); } if (i == list->length - 1) { return removeLast(list); } /* * Get the ith node, splice it out, and return its value. */ node = getIthNode(list, i); node->prev->next = node->next; node->next->prev = node->prev; list->length--; return node->value; } /*-* * Searching and sorting methods. */ bool elementOf(GeneralList* list, char* element) { if (list->sorted) { return (binarySearch(list, element) >= 0); } else { return (linearSearch(list, element) >= 0); } } int findIndex(GeneralList* list, char* element) { if (list->sorted) { return (binarySearch(list, element)); } else { return linearSearch(list, element); } } GeneralList* sort(GeneralList* list) { int i, j; /* Traversal indices */ GeneralListNode* nodeI, *nodeJ; /* Traversal pointers */ /* * Outta here if this is empty. */ if (list->length == 0) { return list; } /* * Create the parallel array. */ list->sortedArray = newblock(GeneralListNode*, (list->length + 1)); /* * Use a basic bubble sort algorithm. */ for (i=0, nodeI=list->first; ilength-1; i++, nodeI=nodeI->next) { for (j=list->length-1, nodeJ=list->last->prev; iprev) { if (nodeCompareTo(nodeJ, nodeJ->next) > 0) { swapNodeValues(nodeJ, nodeJ->next); } } list->sortedArray[i] = nodeI; } list->sortedArray[list->length-1] = list->last; /* * Set sorted to true for use by searching methods. */ list->sorted = true; return list; } /*-* * Utility methods */ GeneralList* subList(GeneralList* list, int i, int j) { GeneralList* subList; /* Return value */ int k; /* Sublist creation loop index */ /* * Return null if either index is out of range or i > j. */ if ((i > j) || (i < 0) || (j < 0) || (i >= list->length) || (j >= list->length)) { return null; } /* * Make a new list for the return value. */ subList = newGeneralList(); /* * Get the ith through jth elements, put each in the return list, and * return the list. */ for (k = i; k <= j; k++) { putLast(subList, get(list, k)); } return subList; } int length(GeneralList* list) { return list->length; } bool isEmpty(GeneralList* list) { return (list->length == 0); } bool equals(GeneralList* list1, GeneralList* list2) { GeneralListNode* node1, *node2; /* Traversal pointers */ /* * Return false immediately if list sizes are different. */ if (list1->length != list2->length) { return false; } for (node1 = list1->first, node2 = list2->first; node1 != null; node1 = node1->next, node2 = node2->next) { if (! nodeEquals(node1, node2)) { return false; } } return true; } char* toString(GeneralList* list) { char* rtn = "["; /* Return value */ GeneralListNode* node; /* Traversal pointer */ /* * Return "[]" immediately if list is empty. */ if (list->length == 0) { return newstr("[]"); } /* * Cruise the list, concatenating of each element onto the return value. */ for (node = list->first; node != list->last; node = node->next) { rtn = newstrcat(rtn, newstrcat(node->value, ", ")); } /* * Handle the last element, which has no following comma. */ rtn = newstrcat(rtn, newstrcat(node->value, "]")); return rtn; } /*-* * Internal methods */ GeneralListNode* getIthNode(GeneralList* list, int i) { int j; /* Traversal counter */ GeneralListNode* node; /* Traversal pointer */ /* * If i is in first half of the list, locate the node starting from the * front, else from the back. */ if (i < list->length / 2) { for (j = 0, node = list->first; j < i; j++, node = node->next) ; } else { for (j = list->length-1, node = list->last; j > i; j--, node = node->prev) ; } return node; } int linearSearch(GeneralList* list, char* element) { GeneralListNode* node; /* Traversal pointer */ int i; /* Traversal index */ for (node = list->first, i = 0; node != null; node = node->next, i++) { if (valueEquals(element, node->value)) { return i; } } return -1; } int binarySearch(GeneralList* list, char* element) { int midpoint; /* Midpoint of startPos/endPos interval */ int startPos = 0; /* Initial start position */ int endPos = list->length - 1; /* Initial end position */ /* * Iterate through the list while the length of the startPos/endPos * interval is >= 1 and we haven't yet found the searched-for element. * For each loop iteration, compute the interval midpoint and then do * one of the following: * * (a) If the searched-for element is at the midpoint, return * successfully. * * (b) If the searched-for element is less than the midpoint * element, search the lower half of the list. * * (c) If the searched-for element is greater than the midpoint * element, search the upper half of the list. */ while (startPos <= endPos) { midpoint = (startPos + endPos) / 2; if (valueEquals(element, list->sortedArray[midpoint]->value)) { return midpoint; } else if (valueCompareTo(element, list->sortedArray[midpoint]->value) < 0 ) { endPos = midpoint - 1; } else startPos = midpoint + 1; } /* * Fail if we never find the element. */ return -1; } void swapNodeValues(GeneralListNode* n1, GeneralListNode* n2) { char* temp; /* Temp value; */ /* * Use standard swap logic. */ temp = n1->value; n1->value = n2->value; n2->value = temp; }