![]() |
CITS2002 Systems Programming |
![]() |
![]() |
|||||
Dynamic data structuresInitially, we focused on scalar and array variables, whose size is known at compile-time.More recently, we've focused on arrays of values, whose required size was only known at run-time. In the case of dynamic arrays we've used C11 functions such as:
malloc(), calloc(), realloc(), and free()
to manage the required storage for us. An extension to this idea is the use of dynamic data structures - collections of data whose required size is not known until run-time. Again, we'll use C11's standard memory allocation functions whenever we require more memory. However, unlike our use of realloc() to grow (or shrink) a single data structure (there, an array), we'll see two significant differences:
To implement these ideas in C11, we'll develop data structures that contain pointers to other data structures. All code examples in this lecture are available from here: examples.zip
CITS2002 Systems Programming, Lecture 19, p1, 3rd October 2023.
A simple dynamic data structure - a stackWe'll commence with a simple stack - a data structure that maintains a simple list of items by adding new items, and removing existing items, from the head of the list.Such a data structure is also termed a first-in-last-out data structure, a FILO, because the first item added to the stack is the last item removed from it (not the sort of sequence you want while queueing for a bank's ATM!). Let's consider the appropriate type definition in C11:
CITS2002 Systems Programming, Lecture 19, p2, 3rd October 2023.
Adding items to our stack data structureAs a program's execution progresses, we'll need to add and remove data items from the data structure.The need to do this is not known until run-time, and data (perhaps read from file) will determine how large our stack eventually grows. As its name suggests, when we add items to our stack, we'll speak of pushing new items on the stack, and popping existing items from the stack, when removing them.
We use a NULL pointer to represent the condition of the stack being empty.
CITS2002 Systems Programming, Lecture 19, p3, 3rd October 2023.
Removing items from our stack data structureThe function pop_item now removes an item from the stack, and returns the actual data's value.In this example, the data held in each STACKITEM is just a single integer, but it could involve several fields of data. In that case, we may need more complex functions to return all of the data (perhaps using a structure or pass-by-reference parameters to the pop_item function). Again, we must ensure that we don't attempt to remove (pop) an item from an empty stack:
CITS2002 Systems Programming, Lecture 19, p4, 3rd October 2023.
Printing our stack data structureTo print out our whole data structure, we can't just use a standard C11 function as C11 doesn't know/understand our data structure. Thus we'll write our own function, print_stack, to traverse the stack and successively print each item, using printf. Again, we must check for the case of the empty stack:
CITS2002 Systems Programming, Lecture 19, p5, 3rd October 2023.
Using our stack in a Reverse Polish CalculatorLet's employ our stack data structure to evaluate basic integer arithmetic, as if using a Reverse Polish Calculator.Each integer read from lines of a file is pushed onto the stack, arithmetic operators pop 2 integers from the stack, perform some arithmetic, and push the result back onto the stack.
CITS2002 Systems Programming, Lecture 19, p6, 3rd October 2023.
Using our stack in a Reverse Polish Calculator, continuedCareful readers may have noticed that in some cases we don't actually need the integer variables val1 and val2.We can use the 2 results returned from pop_item as arguments to push_item:
CITS2002 Systems Programming, Lecture 19, p7, 3rd October 2023.
Problems with our stack data structureAs written, our stack data structure works, but may be difficult to deploy in a large program.In particular, the whole stack was represented by a single global pointer variable, and all functions accessed or modified that global variable.
Ideally we'd re-write all of our functions, push_item, push_item, and print_stack so that they received the required stack as a parameter, and used or manipulated that stack. Techniques on how, and why, to design and implement robust data structures are a focus of the unit CITS2200 Data Structures & Algorithms.
CITS2002 Systems Programming, Lecture 19, p8, 3rd October 2023.
Declaring a list of itemsLet's develop a similar data structure that, unlike the first-in-last-out (FILO) approach of the stack, provides first-in-first-out (FIFO) storage - much fairer for queueing at the ATM!We term such a data structure a list, and its datatype declaration is very similar to our stack:
As with the stack, we'll need to support empty lists, and will again employ a NULL pointer to represent it. This time, each data item to be stored in the list is string, and we'll often term such a structure as "a list of strings".
CITS2002 Systems Programming, Lecture 19, p9, 3rd October 2023.
Adding (appending) a new item to our listWhen adding (appending) new items to our list, we need to be careful about the special (edge) cases:
Such traversal can become expensive (in time) for very long lists.
CITS2002 Systems Programming, Lecture 19, p10, 3rd October 2023.
Removing an item from the head our listRemoving items from the head of our list, is much easier.Of course, we again need to be careful about the case of the empty list:
We say that the caller now owns the storage required to hold the string - even though the caller did not initially allocate that storage.
It will be up to the caller to deallocate that memory when no longer required.
CITS2002 Systems Programming, Lecture 19, p11, 3rd October 2023.
Problems with our list data structureAs written, our list data structure works, but also has a few problems:
We'll address all of these by developing a similar first-in-first-out (FIFO) data structure, which we'll name a queue.
CITS2002 Systems Programming, Lecture 19, p12, 3rd October 2023.
A general-purpose queue data structureLet's develop a first-in-first-out (FIFO) data structure that queues (almost) arbitrary data.We're hoping to address the main problems that were exhibited by the stack and list data structures:
Of note:
CITS2002 Systems Programming, Lecture 19, p13, 3rd October 2023.
Creating a new queueWe'd like our large programs to have more than a single queue - thus we don't want a single, global, variable, and we don't know until run-time how many queues we'll require.We thus need a function to allocate space for, and to initialize, a new queue:
CITS2002 Systems Programming, Lecture 19, p14, 3rd October 2023.
Deallocating space used by our queueIt's considered a good practice to always write a function that deallocates all space used in our own user-defined dynamic data structures.In the case of our queue, we need to deallocate 3 things:
CITS2002 Systems Programming, Lecture 19, p15, 3rd October 2023.
Adding (appending) new items to our queueFinally, we'll considered adding new items to our queue.Remember two of our objectives:
CITS2002 Systems Programming, Lecture 19, p16, 3rd October 2023.
Adding (appending) new items to our queue, continued
CITS2002 Systems Programming, Lecture 19, p17, 3rd October 2023.
Storing and searching ordered data - a binary treeEach of the previous self-referential data-structures stored their values in their order of arrival, and accessed or removed them in the same order or the reverse. The actual time of insertion is immaterial, with the relative times 'embedded' in the order of the elements.More common is to store data in a structure that embeds the relative magnitude or priority of the data. Doing so requires insertions to keep the data-structure ordered, but this makes searching much quicker as well. Let's consider the type definition and insertion of data into a binary tree in C11:
CITS2002 Systems Programming, Lecture 19, p18, 3rd October 2023.
Storing and searching ordered data - a binary tree, continuedKnowing that we've built the binary tree to maintain an order of its elements, we exploit this property to find elements:
CITS2002 Systems Programming, Lecture 19, p19, 3rd October 2023.
|