Home CS61A: Lecture 21
Post
Cancel

CS61A: Lecture 21

Lecture

Composition

  • A linked list is a recursive data structure that represents a sequence.

    List Efficiency - Fast

  • Appending, assigning, and list comprehensions are fast
    • The reason that appending is so fast, is because of the way that lists are represented in the python interpreter.
    • A list is a contiguous block of memory that actually has some additional reserved space within it for list appending
      • When this space runs out, python will move the list contents to a memory space with more capacity.
  • Assiging is also very fast, because we can very quickly calculate the memory address to update a value through the list index.
  • List comprehension is fast because the python interpreter pre-allocates the amount of memory required for the list, and just fills in the values.

List Efficiency - Slow

  • Inserting (beginning/middle), slicing, and adding lists are slow:
  • Slicing lists is slow because it creates a copy of a list.
  • Inserting is slow as well. Whenever an element is inserted into a list, every value after the element must be shifted forward once in the list, which slows down the program.
  • Adding two lists also does not change the original lists, it makes a new list instead, which requires us to reconstruct both lists again.

Linked List Structure

  • Linked Lists are not built into python, so we must create it ourselves.
  • A linked list is either:
    • Empty
    • The first value and the rest of the linked list. Thus, a linked list is a pair of values.
  • The reason that we would use a linked-list is because operations such as insertion are much faster than a regular list, because we could just adjust the attributes of the Link instances.
  • Implementation:
1
2
3
4
5
6
class Link:
    empty = ()
    def __init__(self, first, rest=empty):
        assert rest is Link.empty or isinstance(rest, Link)
        self.first = first
        self.rest = rest
  • To move forward in a linked list, we just set the linked list to the rest.
1
2
3
4
5
from linked_list import Link
s = Link(1, Link(2, Link(3)))
print("Before moving:", s)
s = s.rest
print("After moving:", s)
1
2
Before moving: (1->2->3)
After moving: (2->3)
  • We may also embed a linked list within a linked list
1
2
3
s = Link(3, Link(Link(4, Link(5)), Link(6)))

print(s.rest.first.rest.first)
1
5
  • Ex: Create a function that inserts a v after each v in a linked list ll.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def double(ll, v):
    """Insert another v after each v in linked list ll.
    
    >>> ll = Link(2, Link(7, Link(1, Link(8, Link(2, Link(8))))))
    >>> double_link(s, 8)
    >>> print(ll)
    (2->7->1->8->8->2->8->8)
    """
    while ll is not Link.empty:
        if ll.first == v:
            ll.rest = Link(v, ll.rest)
            ll = ll.rest.rest
        else:
            ll = ll.rest

ll1 = Link(2, Link(7, Link(1, Link(8, Link(2, Link(8))))))
double(ll1, 8)
print(ll1)
1
(2->7->1->8->8->2->8->8)
  • Ex: Create a copy of a linked list
1
2
3
4
5
6
7
8
def copy_linked_list(ll):
    if ll is Link.empty:
        return ll
    return Link(ll.first, copy_linked_list(ll.rest))

s = Link(3, Link(Link(4, Link(5)), Link(6)))
t = copy_linked_list(s)
s is t
1
False
  • Ex: Create a slice of a linked list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def slice_linked_list(ll, start, end):
    assert start >= 0 and end >= 0
    if start == end or ll is Link.empty:
        return Link.empty
    elif start == 0:
        return Link(ll.first, slice_linked_list(ll.rest, start, end-1))
    return slice_linked_list(ll.rest, start-1, end-1)


s = Link(1, Link(2, Link(3, Link(4))))
t = slice_linked_list(s, 2, 4)
t
    

1
Link(3, Link(4))
This post is licensed under CC BY 4.0 by the author.

CS61A: Attributes

CS61A: Inheritance