I'm a sophomore in computer science who's working on a linked list class for his DSA class. I believe this code can be improved, but I'm not sure how because everything got really messy really fast. Thanks.
List.hpp:
// This is a blueprint for all list-like data structures.
// It won't specify how the operations are carried out.
#ifndef LIST_HPP
#define LIST_HPP
#include <cassert>
#include <initializer_list>
template <typename T>
class List
{
public:
List()
{}
virtual ~List()
{}
List(const List&)
{}
virtual void insert(int pos, const T& item) = 0;
virtual void append(const T& item) = 0;
virtual T remove(const int pos) = 0;
virtual int size() const = 0;
virtual T& operator[](const int pos) = 0;
// The const overload is called only when used on const object.
virtual const T& operator[](const int pos) const = 0;
};
#endif // LIST_HPP
LinkedList.hpp:
#ifndef LINKEDLIST_HPP
#define LINKEDLIST_HPP
#include "List.hpp"
#include "Node.hpp"
#include <iostream>
template <typename T>
class LinkedList: public List<T>
{
private:
Node<T>* m_head{nullptr};
Node<T>* m_tail{nullptr};
int m_size{};
public:
LinkedList() = default;
LinkedList(std::initializer_list<T> i_list)
{
for (const auto& item : i_list)
{
append(item);
}
}
~LinkedList()
{
// Start from the beginning.
Node<T>* temp = m_head;
// Traverse the list while deleting previous elements.
while (temp != nullptr)
{
temp = temp->next; // Move forward.
delete m_head; // Delete the previous element.
m_head = temp; // m_head moved one forward.
}
}
auto head() const
{
return m_head;
}
auto tail() const
{
return m_tail;
}
bool empty() const
{
return m_size == 0;
}
int size() const
{
return m_size;
}
void prepend(const T& item)
{
// Create a node holding our item and pointing to the head.
auto new_item = new Node<T>{item, m_head};
// If the head is the last element
// (meaning it is the only element),
// it'll be the tail.
if (m_head == nullptr)
{
m_tail = m_head;
}
m_head = new_item;
m_size++;
}
void append(const T& item)
{
// Create a node with no pointer.
auto new_item = new Node<T>{item};
if (m_tail == nullptr)
{
// If the list is empty, set the new item as the head as well.
m_head = new_item;
m_tail = new_item;
}
else
{
// Otherwise, update the current tail's next pointer to the new item and move the tail.
m_tail->next = new_item;
m_tail = new_item;
}
m_size++;
}
void insert(const int pos, const T& item)
{
// If the position is the beginning of the list, prepend the new node.
if (pos == 0)
{
prepend(item);
}
// If the position is beyond the end of the list, append the new node.
else if (pos >= m_size)
{
append(item);
}
else
{
// Create a new node.
auto new_item = new Node<T>{item};
// Starting from the head, go to the one previous position.
auto temp = m_head;
int i{};
for (; i < pos - 1; ++i)
{
temp = temp->next;
}
new_item = temp->next;
temp->next->next = new_item->next;
m_size++;
}
}
void remove_front()
{
Node<T>* temp = m_head;
if (temp != nullptr)
{
return;
}
m_head = m_head->next; // Move m_head one element forward.
delete temp; // Get rid of the previous element.
--m_size;
}
void remove_back()
{
Node<T>* temp = m_head;
if (temp == nullptr)
{
return;
}
// If the list's size is 1.
if (temp == m_tail)
{
delete temp;
m_head = m_tail = nullptr;
--m_size;
return;
}
// Traverse to one past the end.
while (temp->next != m_tail)
{
temp = temp->next;
}
m_tail = temp;
temp = temp->next;
delete temp;
m_tail->next = nullptr;
--m_size;
}
T remove(const int pos)
{
Node<T>* temp = m_head;
int i{};
for (; i < pos - 1; ++i)
{
temp = temp->next;
}
auto to_removed = temp->next;
temp->next = temp->next->next;
T removed_data = to_removed->data; // Retrieve the data before deleting the node.
delete to_removed;
return removed_data;
}
T& operator[](const int pos)
{
Node<T>* temp = m_head;
int i{};
for (; i != pos; ++i)
{
temp = temp->next;
}
return temp->data;
}
const T& operator[](const int pos) const
{
Node<T>* temp = m_head;
int i{};
for (; i != pos; ++i)
{
temp = temp->next;
}
return temp->data;
}
};
template <typename T>
std::ostream& operator<<(std::ostream& os, const LinkedList<T>& list)
{
for (auto begin = list.head(); begin != nullptr; begin = begin->next)
{
os << begin->data << ' ';
}
return os;
}
#endif // LINKEDLIST_HPP
main.cpp:
#include "LinkedList.hpp"
#include <iostream>
int main()
{
LinkedList<int> l{1,2,4};
for (int i{}; i < 10; ++i)
{
l.append(i * i);
}
std::cout << l << "\n";
}
```