Data Structures and Algorithms
Last Modified: 2/12/2025
2 Linked Lists
A linked list is a linear collection of data elements whose order is not given by their physical placement in memory. Instead, each element points to the next.
In the implementation we use a sentinel code. Sentinel code make it easier to reason about code, and also give you specific goals to strive for in making sure your code works.
2.1 Singly Linked List
Singly linked lists contain nodes which have a ‘value’ field as well as ‘next’ field, which points to the next node in line of nodes.
97 collapsed lines
import java.util.Iterator;
public class SLList<T> implements Iterable<T> {
/** * Node class for SLList */ public static class Node<T> { public T item; public Node<T> next;
public Node(T i, Node<T> n) { item = i; next = n; } }
private final Node<T> sentinel; private int size;
/** * Default Constructor for SLList */ public SLList() { sentinel = new Node<>(null, null); size = 0; }
/** * Constructor for SLList with one element * * @param x element to be added */ public SLList(T x) { sentinel = new Node<>(null, null); sentinel.next = new Node<>(x, null); size = 1; }
/** * Add element to the front of the list * * @param x element to be added */ public void addFirst(T x) { sentinel.next = new Node<>(x, sentinel.next); size += 1; }
/** * Add element to the end of the list * * @param x element to be added */ public void addLast(T x) { size += 1; Node<T> p = sentinel; while (p.next != null) { p = p.next; } p.next = new Node<>(x, null); }
/** * Return the size of the list * * @return size of the list */ public int size() { return size; }
/** * Iterator implementation for SLList */ public Iterator<T> iterator() { return new SLListIterator(); }
private class SLListIterator implements Iterator<T> { private Node<T> p;
public SLListIterator() { p = sentinel.next; }
public boolean hasNext() { return p != null; }
public T next() { T returnItem = p.item; p = p.next; return returnItem; } }}
132 collapsed lines
#ifndef SLLIST_H#define SLLIST_H
#include <iterator>
template <typename T>class SLList {public: template <typename U> struct Node { U item; Node* next;
Node(U i, Node<U>* n) : item(i), next(n) {} };
private: Node<T>* sentinel; int size;
public: SLList(); explicit SLList(T x); void addFirst(T x); void addLast(T x); [[nodiscard]] int getSize() const; class iterator; iterator begin(); iterator end();};
template <typename T>class SLList<T>::iterator {public: using iterator_category = std::forward_iterator_tag; using value_type = T; using difference_type = std::ptrdiff_t; using pointer = T*; using reference = T&;
private: Node<T>* current;
public: explicit iterator(Node<T>* node) : current(node) {} T& operator*() const; T* operator->() const; iterator& operator++(); bool operator==(const iterator& other) const; bool operator!=(const iterator& other) const;};
template <typename T>SLList<T>::SLList() : sentinel(new Node<T>(T(), nullptr)), size(0) {}
template <typename T>SLList<T>::SLList(T x) : sentinel(new Node<T>(T(), nullptr)), size(1) { sentinel->next = new Node<T>(x, nullptr);}
/** * Add element to the front of the list */template <typename T>void SLList<T>::addFirst(T x) { sentinel->next = new Node<T>(x, sentinel->next); size++;}
/** * Add element to the end of the list */template <typename T>void SLList<T>::addLast(T x) { size++; Node<T>* p = sentinel; while (p->next != nullptr) { p = p->next; } p->next = new Node<T>(x, nullptr);}
/** * Return the size of the list */template <typename T>int SLList<T>::getSize() const { return size;}
/** * Iterator implementation for SLList */template <typename T>typename SLList<T>::iterator SLList<T>::begin() { return iterator(sentinel->next);}
template <typename T>typename SLList<T>::iterator SLList<T>::end() { return iterator(nullptr);}
template <typename T>T& SLList<T>::iterator::operator*() const { return current->item;}
template <typename T>T* SLList<T>::iterator::operator->() const { return &(current->item);}
template <typename T>typename SLList<T>::iterator& SLList<T>::iterator::operator++() { if (current) { current = current->next; } return *this;}
template <typename T>bool SLList<T>::iterator::operator==(const iterator& other) const { return current == other.current;}
template <typename T>bool SLList<T>::iterator::operator!=(const iterator& other) const { return !(*this == other);}
#endif // SLLIST_H
45 collapsed lines
class Node: """Represents a node in the singly linked list.""" def __init__(self, item, next_node): """Initializes a Node with an item and the next node.""" self.item = item self.next = next_node
class SLList: """Represents a singly linked list.""" def __init__(self, x=None): """ Initializes an SLList. If x is provided, initializes the list with one element x. Uses a sentinel node at the front. """ self.sentinel = Node(None, None) self.size_val = 0
if x is not None: self.sentinel.next = Node(x, None) self.size_val = 1
def add_first(self, item): """Adds an item to the front of the list.""" self.sentinel.next = Node(item, self.sentinel.next) self.size_val += 1
def add_last(self, item): """Adds an item to the end of the list.""" self.size_val += 1 p = self.sentinel while p.next is not None: p = p.next p.next = Node(item, None)
def size(self): """Returns the number of items in the list.""" return self.size_val
def __iter__(self): """Returns an iterator for the SLList.""" p = self.sentinel.next while p is not None: yield p.item p = p.next