In this lecture and the next, we'll implement a set (an associative container for storing unique elements) based on an array.
We'll be following our normal process for building an ADT - starting with our motivating use cases and the interface we want, followed by a fundamental data representation and invariants, and finally filling in the implementations for each member function.
We'll also introduce the notion of time complexity to formally analyze the efficiency of operations on data structures.
It turns out that arrays (and data structures built using them) provide very efficient access to data in a couple different ways:
Sequential Access: Iterating through a sequence of elements from start to end.
Random Access: Accessing an element at a particular index (i.e. position) in the sequence.
On the other hand, arrays are less efficient in cases where we need to:
Shift Elements: If we need to preserve the order of elements after inserting/removing from the middle of an array, we have to shift them one-by-one.
1: Containers and Data Structures
First, a brief introduction to the big-picture idea of containers and data structures, including a roadmap to building one ourselves: |
2: An Array-Based Unsorted Set
We'll start with an introduction to sets and their interfaces, as well as some motivation for why we would want to use them. We haven't seen Our next step is to choose a data representation and invariants. This ends up as the foundation for the data structure, the implementation of its functions, and the efficiency we can achieve. Throughout the course, we'll end up looking at several different possibilities for an unsorted set. We'll start here with an unsorted array. |
3: IntSet Implementation
3.1
3.2
Let's get into the implementation of a default constructor and a few member functions for the array-based unsorted set.
3.1 Exercise:
IntSet::insert()
Implement the First, your code should call
The You're welcome to check your solution with this walkthrough video: Note: This walkthrough uses several different files for the code, which is different than the above, where we had everthing embedded into one file. (The solution for
3.2 Exercise:
IntSet::remove()
Below are some potential implementations of the It may be helpful to trace through the code on this set, removing the ![]() Or, you might also consider pasting them into the code for the exercise above and uncommenting the additional set of tests in Which of the implementations of
Two of the implementations above for You're welcome to check your solution with this walkthrough video: NOTE: For completeness, I'll mention here that ultimately both implementations that work correctly end up having similar runtime complexities in that their runtime scales linearly with the amount of elements in the set - that's because even though the one I describe in the walkthrough video does less work to remove the element, it still needs to call |
4: Time Complexity
4.1
When we're asessing the fitness of a data structure for a given task, it's helpful to determine its time complexity, which quantifies how well it performs as the size of the data we're working with scales up. In particular, let's look at the efficiency of several common operations on arrays:
4.1 Exercise: Time Complexity
Determine the time complexity of operations on our unsorted
Below are several (correct) implementations of
You're welcome to check your solution with this walkthrough video: |