Skip to content

Linked Lists

A linked list is either empty or a first value and the rest of the linked list.

Linked List Class

We use object system to implement linked lists in Python

python
class Link:
    empty = ()
    
    def __init__(self, first, rest=empty):
        assert rest is Link.empty or isinstance(rest, Link)
        self.first = first
        self.rest = rest
    def __getitem__(self, i):
        if i == 0:
            return self.first
        else:
            return self.rest[i-1]
    def __len__(self):
        return 1 + len(self.rest)
    
    def __repr__(self):
        if self.rest is self.empty:
            rest = ''
        else:
            rest = ', ' + repr(self.rest)
        return f'Link({self.first}{rest})'
        

s = Link(3, Link(4, Link(5)))
>>> def join_link(s, separator):
        if s is Link.empty:
            return ""
        elif s.rest is Link.empty:
            return str(s.first)
        else:
            return str(s.first) + separator + join_link(s.rest, separator)
>>> join_link(s, ", ")
'3, 4, 5'
  • For __len__, the base case is reached when self.rest evaluates to the empty tuple, Link.empty, which has a length of 0.

Processing

python
def range_link(begin, end):
    """Return a Link containing consecutive integers from start to end.
    
    >>> range_lilnk(3, 6)
    Link(3, Link(4, Link(5)))
    """
    if start >= end:
        return List.empty
    else:
        return Link(start, range_link(start+1, end))


def map_link(f, s):
    """Return a Link contains f(x) for each x in Link s.
    
    >>> map_link(square, range_link(3, 6))
    Link(9, Link(16, Link(25)))
    """
    if s is Link.empty:
        return s
    else:
        return Link(f(s.first), map_link(f, s.rest))


def filter_link(f, s):
    """Return a Link that contains only the elements of x of Links s for which f(x) is a true value.
    
    >>> filter_link(odd, range_link(3, 6))
    Link(3, Link(5))
    """
    if s is Link.empty:
        return s
    filtered_rest = filter_link(f, s.rest)
    if f(s.first):
	    return Link(s.first, filtered_rest)
	else:
	    return filtered_rest

Mutating

Linked list object instance can be mutated through mutating List.first and List.rest.

The rest of a linked list can contain the linked list as a sub-list. Do not mutate directly the List, which might leads to recursive definition.

python
s = Link(1, Link(2, Link(3)))
s.first = 5
t = s.rest
t.rest = s # It is mutating s because t.rest is s.rest.rest

To copy a linked list, use Link(List.first, List.rest)