Data Structures in C C Programming and Software Tools N.C. State Department of Computer Science Data Structures in C The combination of pointers, structs, and dynamic memory allocation allow for creation of data structures Linked lists Trees Graphs Without dynamic memory allocation, you could still create these data structures within an array Using structs and pointers 1
Collections Array Lists Elements stored in a partially filled array Size of collection can quickly identify next place to add element (if adding at end of the list) If size == capacity of array, the array grows automatically through the creation of a new, larger array, with the elements copied Linked Lists A struct represents a single node in the list A node contains a pointer to the next node in the list A null value represents the end of the list Collections (2) When considering any functionality related to a list collection always consider: An empty list Beginning of the list Middle of the list End of the list 2
Array List vs. Linked List For each of the following characteristics, identify if it describes an Array List or a Linked List. Characteristic Array List? Linked List? Access any element via an index in the collection in constant time. Easily grow or shrink the collection. Space only allocated for elements currently in the collection. May have unused space. Constant runtime efficiency to get an item from the list at a particular index. Adding or removing an element at in the middle of the collection requires a shift of other elements (as appropriate for the operation). Declaring a Node Type Each node contains data and a pointer to the next node Use a struct Data can be multiple members of the struct Cannot use typedef when defining node type for a linked list. Otherwise, the type of the next node is unknown. struct node int value; struct node *next; ; 3
Creating a List A list is a pointer to the first node in the list. The list initially is empty (NULL) struct node *front = NULL; Procedural decomposition of list functionality Create functions that represent discrete operations on a list (similar to the LinkedList and ArrayList methods) add, remove, find, etc. Consider a global vs. local list If global list, then all functions can access the front of the list If local list, the front of the list must be passed into functions and the modified list must be returned Adding a Node to a List Adding a node to a list has three steps 1. Allocating memory for the node 2. Storing data in the node 3. Inserting the node into the list Consider empty list, front of the list, middle of the list, and end of the list There may be specializations 4
Adding a Node to the Front of List Global reference to the front of the list struct node *front; void add_to_front(int v) struct node *new_node; Use sizeof(type) not sizeof(type *) new_node = (struct node *) malloc(sizeof(struct node)); if (new_node == NULL) printf("error: malloc failed in add_to_front\n"); exit(exit_failure); new_node->value = v; new_node->next = front; front = new_node; int main() add_to_front(3); Adding a Node to the Front of List Local reference to the front of the list struct node *add_to_front(struct node *list, int v) struct node *new_node = malloc(sizeof(struct node)); if (new_node == NULL) printf("error: malloc failed in add_to_front\n"); exit(exit_failure); new_node->value = v; new_node->next = list; return new_node; int main() struct node *front = NULL; front = add_to_front(front, 3); 5
Traversing a List Algorithm Start at first element Manipulate data for element Move to next element Make sure you don t lose your list! Create a pointer that you use specifically for traversing the list Printing a List Global reference to the front of the list struct node *front; Maintain a second reference to void print_list() the front of the list for traversal. struct node *cur; for (cur = front; cur!= NULL; cur = cur->next) printf("%d ", cur->value); printf("\n"); int main() print_list(); 6
Printing a List Local reference to the front of the list void print_list(struct node *list) for (; list!= NULL; list = list->next) printf("%d ", list->value); printf("\n"); Parameter is pass by value! int main() struct node *front = NULL; print_list(front); Serves as local reference to the list in print_list function. The main front reference is not modified! Processing... (cont'd) Adding a new person to the end of the list? 7
Removing a Node from a List Removing a node from a list has three steps 1. Locate the node to be deleted 2. Alter the previous node so that it bypasses the deleted node 3. Free the memory to reclaim space of deleted node Current searching algorithm would get us to the node we want to delete Instead, we want to stop at the node BEFORE the one we want to delete Trailing pointer technique (see book Section 17.5) Removing a Node from the Back of List Global reference to the front of the list struct node *front; void remove_from_back() if (front == NULL) return; //empty list struct node *cur, *prev; for (cur = front, prev = NULL; cur->next!= NULL; prev = cur, cur = cur->next) ; //cur will point to last node of list if (prev == NULL) //special case where only one node front = front->next; //sets front to NULL else prev->next = cur->next; //sets prev->next to NULL free(cur); 8
Removing a Node from the Back of List Local reference to the front of the list struct node *remove_from_back(struct node *list) if (list == NULL) return list; //empty list struct node *cur, *prev; for (cur = list, prev = NULL; cur->next!= NULL; prev = cur, cur = cur->next) ; if (prev == NULL) //list has only one node list = list->next; else prev->next = cur->next; //point to NULL free(cur); return list; Processing (cont'd) Remove an item from the front of a list? 9
Specialized Data Structures More efficient on add/remove operations Sorted list Faster search can quit earlier if can t find value Stacks Add and remove from same end Queues Add at one end and remove from the other end Optimize speed of access by creating a doubly linked list and maintaining a reference to the front and back of the list Doubly Linked Lists A node maintains a pointer to the node before and after it in the list. struct node struct node *prev; int value; struct node *next; ; All list operations need to update appropriate prev and next pointers. Can maintain a pointer to the back of the list 10