➡️ Click here to view the autograder workflow
In this lab, you will implement two versions of an unordered list Abstract Data Type (ADT): one using an array and the other using a linked list. Both implementations will share the same interface but will differ in their internal implementation. You will also implement iterators for both versions to facilitate traversal of the lists in a manner consistent with C++ Standard Library conventions.
Additionally, you will create separate drivers (ArrayListDriver.cpp
and LinkedListDriver.cpp
) for each implementation. These drivers must demonstrate the functionality of the ADT methods with two different data types: one primitive type such as int
or std::string
, and one user-defined type, specifically the Customer
class provided in the lab. The drivers should also create Customer
objects from the Customers.txt
file and use them in the list.
This assignment strengthens your understanding of templates, iterators, dynamic memory management, and algorithm efficiency.
- Templated classes
- Array-based and linked list-based data structures
- Iterator implementation for traversal
- Dynamic memory management (linked list)
- Operator overloading for iterators
By completing this lab, you will:
- Implement templated unordered lists in C++ with two underlying structures: arrays and linked lists.
- Create iterators for both implementations to traverse the lists efficiently.
- Handle edge cases, such as accessing elements beyond the list boundaries.
- Demonstrate ADT functionality with two data types.
- Understand the differences in performance and memory usage between arrays and linked lists.
- Adhere to modern C++ coding practices, including exception safety and proper commenting.
60 points autograded, 40 points hand graded.
Points | Requirements |
---|---|
20 | ArrayADTList Methods Implementation |
20 | LinkedADTList Methods Implementation |
10 | ArrayADTList Iterator Implementation |
10 | LinkedADTList Iterator Implementation |
10 | Driver Demonstrating Primitive Data Type Usage |
10 | Driver Demonstrating Customer Object Usage |
20 | Good Coding Practices (Including Documenting Comments) |
Both lists have the exact same interface the prototype methods are:
You may not change the interface. The implementation however is completely up to you.
Constructor Your constructor should set the initial state of the object correctly setting defaults for all properties.
Destructor A destructor is required in the linked list version to ensure that memory leaks are not created when the ADT is deleted.
int getLength(); Returns the length of the list.
void putItem(const DataType &item); Inserts the value of the item into the list. Throws a FullError if the list is full. Note: FullError is only needed in the array implementation. Make sure you understand why.
bool getItem(const DataType &item, DataType &found_item); Finds the item in the list and assigns the value to the found_item. Returns true if the item is in the list and false if it is not.
bool isFull(); Returns true if the list is full, false if it is not.
void makeEmpty(); Sets the list to empty.
bool deleteItem(const int &item); Removes the item from the list.Returns true if the item was in the list and false if it was not.
Iterator begin(); Returns an Iterator object pointing to the first item in the list.
Iterator end(); Returns an Iterator object pointing to the last item in the list.
Note: the order of your list does not matter, but it must have an order for the begin and end methods to function.
For the linked list version only you need to add :
- A Copy Constructor
- An Assignment operator
- Destructor
You don't need any of these for the Array version. Be sure you understand why.
The Interface (public methods) are set, but you are free to add as many private methods as you'd like to make you code more readable and/or efficient.
-
Declare a Class Template:
- Define a templated class
ArrayADTList<DataType>
.
- Define a templated class
-
Core Methods:
- Implement the following member functions:
int getLength() const;
void putItem(const DataType& item);
bool getItem(const DataType& item, DataType& found_item) const;
bool isFull() const;
void makeEmpty();
bool deleteItem(const DataType& item);
- Implement the following member functions:
-
Iterator Implementation:
- Define a nested
Iterator
class that:- Supports dereferencing (
operator*
), pre-increment (operator++
), and equality comparison (operator==
,operator!=
). - Traverses the array using internal pointers or indices.
- Throws a std::out_of_range exception if operator* is called when the iterator is at the end of the list.
- Supports dereferencing (
- Add
begin()
andend()
methods toArrayADTList
to return appropriate iterators.
- Define a nested
-
Declare a Class Template:
- Define a templated class
LinkedADTList<DataType>
.
- Define a templated class
-
Core Methods:
- Implement the following member functions:
int getLength() const;
void putItem(const DataType& item);
bool getItem(const DataType& item, DataType& found_item) const;
void makeEmpty();
bool deleteItem(const DataType& item);
- Implement the following member functions:
-
Rule of Three:
- Implement:
- A destructor to release dynamically allocated memory.
- A copy constructor for deep copying.
- An assignment operator.
- Implement:
-
Iterator Implementation:
- Define a nested
Iterator
class that:- Supports dereferencing (
operator*
), pre-increment (operator++
), and equality comparison (operator==
,operator!=
). - Traverses the linked list by following node pointers.
- Throws a std::out_of_range exception if operator* is called when the iterator is at the end of the list.
- Supports dereferencing (
- Add
begin()
andend()
methods toLinkedADTList
to return appropriate iterators.
- Define a nested
The typename
keyword is necessary in certain contexts to clarify that a name refers to a type rather than a static member or value. We'll need to use it for the definition of our templated methods that return an LinkedADTList<DataType>::Iterator
.
-
Dependent Names:
- Syntax:
typename LinkedADTList<DataType>::Iterator
LinkedADTList<DataType>
depends on the template parameterDataType
, meaning its definition is not fully known until the template is instantiated. Withouttypename
, the compiler cannot determine whetherIterator
is a type or a static member ofLinkedADTList
.
- Syntax:
-
Disambiguation:
- The compiler needs
typename
to explicitly understand thatIterator
is a type. Without it, the compiler might assumeIterator
is a value or static member, leading to a compilation error.
- The compiler needs
-
Where
typename
is Needed:- You must use
typename
before a dependent type name in the scope of a template class when defining methods or using nested types. Specifically when returning an Itorator from our templated class :typename LinkedADTList<DataType>::Iterator& LinkedADTList<DataType>::Iterator::operator++() { // your code goes here }
- You must use
The typename
keyword resolves ambiguity for the compiler, ensuring it interprets the identifier as a type in template-dependent contexts.
For each implementation, create a separate driver file:
-
Primitive Data Type:
- Demonstrate the functionality of the
ArrayADTList
class using a simple data type, such asint
orstd::string
.
- Demonstrate the functionality of the
-
Customer Class:
- Demonstrate the
ArrayADTList
class using theCustomer
object. - Load
Customer
objects from the providedCustomers.txt
file.
- Demonstrate the
-
Primitive Data Type:
- Demonstrate the functionality of the
LinkedADTList
class using a simple data type, such asint
orstd::string
.
- Demonstrate the functionality of the
-
Customer Class:
- Demonstrate the
LinkedADTList
class using theCustomer
object. - Load
Customer
objects from the providedCustomers.txt
file.
- Demonstrate the
#include "ArrayADTList.h"
#include "LinkedADTList.h"
#include "Customer.h"
#include <iostream>
#include <fstream>
int main() {
ArrayADTList<int> arrayList;
LinkedADTList<Customer> linkedList;
// Demonstrate with integers
arrayList.putItem(10);
arrayList.putItem(20);
arrayList.putItem(30);
for (auto it = arrayList.begin(); it != arrayList.end(); ++it) {
std::cout << *it << " ";
}
// Load customers from file
std::ifstream customerFile("Customers.txt");
std::string line;
while (std::getline(customerFile, line)) {
Customer customer(line);
linkedList.putItem(customer);
}
for (const LinkedADTList<Customer>::Iterator& customer : linkedList) {
std::cout << customer << "\n";
}
return 0;
}
-
Driver Requirements:
- Your drivers (
ArrayListDriver.cpp
andLinkedListDriver.cpp
) should demonstrate all implemented features of bothArrayADTList
andLinkedADTList
using two data types. - Copy the output from each driver to the corresponding text files:
ArrayADTListDriverOutput.txt
andLinkedADTListDriverOutput.txt
.
- Your drivers (
-
Style Guidelines:
- Follow clean coding practices.
- Use Doxygen-style comments for all classes and methods.
-
Code Submission:
- Push your completed code to the provided GitHub repository.
-
GitHub Repository URL:
- Submit the URL of your GitHub repository in the lab assignment on Canvas.
The Interface (public methods) are set, but you are free to add as many private methods as you'd like to make you code more readable and/or efficient.
You don't need ether of these for the Array version. Be sure you understand why.
- The array version will need a MAX size, set it based on the maximum number of customers you will be loading.
- Watch out for infinite loops.
- Know what your special cases are, like is the list empty with trying to add or remove an element.
- Watch out for infinite loops.
- It's easy to create a memory leak and the tests will not test for that. Be sure that for every 'new' in your code you has 'delete' where that node is deleted.
- Order matters! When you are looping over the linked list and/or deleting an item out of the linked list think about the order in which you do each step so that you are not setting the pointers incorrectly or trying to access memory you've already deleted.
- Know what your special cases are, like is the list empty with trying to add or remove an element.
- Doxygen-style Documenting comments are required for all classes and methods in the header file.
- Comment tricky parts of the code, deleteItem, getNextItem and others can have complicated code, explain what your code is doing.
- You need to make sure your efficiency is as good as the examples we reviewed in class. You should not be moving around large amounts of data in the Array version or traversing the linked list more than is needed.
- Memory leaks are a real danger in the linked list version know where and when they can happen.