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;
}
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