Demo - Singly-linked list data structure

Here is an example implementation of a singly-linked list:

// SinglyLinkedListNode.h /* NOTE: In the class SinglyLinkedListNode, a destructor is generally not needed for the node itself because it only contains raw pointers that need explicit release. The node's memory and its management (creation and deletion) are typically handled by the containing data structure, like the SinglyLinkedList class in our example. */ // Kevin Roark #ifndef SinglyLinkedListNode_h #define SinglyLinkedListNode_h // Create a generic node for the singly linked list template <typename T> class SinglyLinkedListNode { public: T value; // Store the value of the node SinglyLinkedListNode* next; // Pointer to the next node // Node constructor SinglyLinkedListNode(T value) { this->value = value; // Set the node's value this->next = nullptr; // Initialize next node pointer to null } // Destructor is not needed for this node as the memory // is managed by the containing data structure. }; #endif /* SinglyLinkedListNode_h */
// SinglyLinkedList.h // Kevin Roark #ifndef SinglyLinkedList_h #define SinglyLinkedList_h #include "SinglyLinkedListNode.h" #include <iostream> using namespace std; // Generic singly linked list class template <typename T> class SinglyLinkedList { private: SinglyLinkedListNode<T>* head; // Pointer to the head of the list public: // Constructor SinglyLinkedList() : head(nullptr) {} // Destructor to clean up all the nodes ~SinglyLinkedList() { clear(); // Use a helper function for clean-up } // Method to clear the entire list void clear() { while (head) { SinglyLinkedListNode<T>* nodeToDelete = head; head = head->next; delete nodeToDelete; } } // Insert a new node at the head of the list void insertAtHead(T value) { SinglyLinkedListNode<T>* newNode = new SinglyLinkedListNode<T>(value); newNode->next = head; head = newNode; } // Insert a new node at the tail of the list void insertAtTail(T value) { SinglyLinkedListNode<T>* newNode = new SinglyLinkedListNode<T>(value); if (!head) { head = newNode; } else { SinglyLinkedListNode<T>* current = head; while (current->next) { current = current->next; } current->next = newNode; } } // Insert a node at a specific position void insertAtPosition(int position, T value) { if (position < 0) { cout << "Invalid position." << endl; return; } SinglyLinkedListNode<T>* newNode = new SinglyLinkedListNode<T>(value); if (position == 0) { newNode->next = head; head = newNode; return; } SinglyLinkedListNode<T>* temp = head; for (int i = 0; temp != nullptr && i < position - 1; i++) { temp = temp->next; } if (!temp) { cout << "Position is out of bounds." << endl; delete newNode; return; } newNode->next = temp->next; temp->next = newNode; } // Remove a node at a specific position void removeFromPosition(int position) { if (head == nullptr || position < 0) { cout << "List is empty or invalid position." << endl; return; } if (position == 0) { SinglyLinkedListNode<T>* nodeToDelete = head; head = head->next; delete nodeToDelete; return; } SinglyLinkedListNode<T>* temp = head; for (int i = 0; temp != nullptr && i < position - 1; i++) { temp = temp->next; } if (!temp || !temp->next) { cout << "Position is out of bounds." << endl; return; } SinglyLinkedListNode<T>* nodeToDelete = temp->next; temp->next = temp->next->next; delete nodeToDelete; } // Print the values of the list void printList() const { SinglyLinkedListNode<T>* current = head; while (current) { cout << current->value << " "; current = current->next; } cout << endl; } }; #endif /* SinglyLinkedList_h */
// Author: Kevin Roark //Date: //Purpose - demonstrate a Linked List // Include necessary libraries #include <iostream> #include "SinglyLinkedList.h" using namespace std; // Main function to demonstrate the use of the Singly Linked List with both integers and strings int main() { // Create a new singly linked list of integers SinglyLinkedList<int> myList; // Insert elements at the head and tail for integers myList.insertAtHead(1); // Insert 1 at the head of the list myList.insertAtHead(2); // Insert 2 at the head of the list myList.insertAtTail(3); // Insert 3 at the tail of the list myList.insertAtHead(10); // Insert 10 at the head of the list myList.insertAtTail(8); // Insert 8 at the tail of the list // Display the current state of the integer linked list cout << "Integer Linked List: " << endl; myList.printList(); // Print the list // Demonstrating insertions at specific positions for integers cout << "\nNow, let's insert integer nodes at specific positions and print the list: " << endl; myList.insertAtPosition(0, 15); // Insert 15 at the beginning (position 0) myList.insertAtPosition(1, 20); // Insert 20 at second position (position 1) myList.insertAtPosition(5, 30); // Insert 30 at fifth position (position 5) myList.printList(); // Print the updated list // Demonstrating removal from a specific position for integers cout << "\nNow, let's remove the integer node at position 5 and print the list: " << endl; myList.removeFromPosition(5); // Remove node at position 5 myList.printList(); // Print the updated list // Create a new singly linked list of strings SinglyLinkedList<string> myStringList; // Insert elements into the string linked list myStringList.insertAtHead("Alice"); // Insert "Alice" at the head of the list myStringList.insertAtHead("Kevin"); // Insert "Kevin" at the head of the list myStringList.insertAtTail("Sam"); // Insert "Sam" at the tail of the list myStringList.insertAtHead("Diana"); // Insert "Diana" at the head of the list myStringList.insertAtTail("Sally"); // Insert "Sally" at the tail of the list // Display the current state of the string linked list cout << "\nString Linked List: " << endl; myStringList.printList(); // Print the list // Demonstrating insertions at specific positions for strings cout << "\nNow, let's insert string nodes at specific positions and print the list: " << endl; myStringList.insertAtPosition(0, "Frank"); // Insert "Frank" at the beginning (position 0) myStringList.insertAtPosition(1, "Grace"); // Insert "Grace" at second position (position 1) myStringList.insertAtPosition(5, "Fred"); // Insert "Fred" at fifth position (position 5) myStringList.printList(); // Print the updated list // Demonstrating removal from a specific position for strings cout << "\nNow, let's remove the string node at position 5 and print the list: " << endl; myStringList.removeFromPosition(5); // Remove node at position 5 myStringList.printList(); // Print the updated list // Clear both lists and display their final state myList.clear(); cout << "\nCleared the integer list. Final state: " << endl; myList.printList(); // Should display nothing as the list is cleared myStringList.clear(); cout << "\nCleared the string list. Final state: " << endl; myStringList.printList(); // Should display nothing as the list is cleared return 0; }

 

image-20241020-144443.png

 

In this example, we define a SinglyLinkedListNode class to represent a node in the list, which has a value and a reference to the next node. We then define a SinglyLinkedList class to represent the list itself, which has a reference to the head of the list. We provide member functions to insert nodes at the head and the tail of the list, add, remove and to print the list.

 

Singly-linked lists have several advantages, such as fast insertion and deletion of elements at the head of the list. However, they have some disadvantages, such as slower access to elements at arbitrary positions and the need to traverse the list to find the tail.

2024 - Programming 3 / Data Structures - Author: Dr. Kevin Roark