Download presentation
Presentation is loading. Please wait.
1
Fundamentals of Programming II Linked Lists
Computer Science 112 Fundamentals of Programming II Linked Lists
2
The List Clan AbstractCollection AbstractList ListInterface *
TwoWayNode LinkedList ArrayList Array
3
Insert into An Array List
def insert(self, i, item): """Inserts the item at position i.""" self._resize() if i < 0: i = 0 elif i > len(self): i = len(self) if i < len(self): for j in range(len(self), i, -1): self._items[j] = self._items[j - 1] self._items[i] = item self._size += 1 self.incModCount() No precondition on the index, can insert after the last item The index is normalized: 0 <= i <= len(self)
4
Problems with Arrays Must waste memory, especially if the structure is less than half full When the structure becomes full, must grow memory to resize, which is O(n) in memory and running time Insertions and removals are O(n) on average, due to shifting of items
5
Linked Structures to the Rescue
Uses memory only as needed, physical size grows or shrinks with logical size in constant time Insertions and removals require no shifting of items
6
Problems with Linked Structures
Appending, which is constant time for arrays, is linear for a singly linked structure newNode 1 head probe 5 4 3 2
7
Solution: Add a Tail Pointer
Maintain a tail pointer, which is either None or points to the last node in the structure tail is a second external pointer, which is None when the structure is empty newNode 1 head tail 5 4 3 2
8
Solution: A Tail Pointer
newNode = Node(1, None) if head == None: head = newNode else: tail.next = newNode tail = newNode newNode 1 head tail 5 4 3 2
9
Other Problems Links only go one in one direction, so movement in the other direction is difficult and expensive Insertions and removals require access to the previous node’s next field tail pointer won’t help to remove the last node Insertions and removals at the head of the structure are special cases that complicate the code
10
Other Linked Structures
head D1 D2 D3 D4 A singly linked structure permits movement in one direction only head D1 D2 D3 A doubly linked structure permits movement in both directions and simplifies some operations
11
Doubly Linked Structures
head D1 D2 D3 A circular, doubly linked structure with a dummy header node permits movement in both directions allows constant-time access to the head or tail eliminates special cases in code when access is at the beginning or the end of the structure
12
An Empty Structure head
When there are no data, there is a single dummy header node Its two links point ahead and back to itself Its data field is None
13
The Node Class P D N Strictly a utility class
class TwoWayNode(object): def __init__(self, data, previous = None, next = None): self.data = data self.previous = previous self.next = next P D N Strictly a utility class No need for accessor or mutator methods
14
Declaring an External Pointer
class TwoWayNode(object): def __init__(self, data, previous = None, next = None): self.data = data self.previous = previous self.next = next head = TwoWayNode(None) head.previous = head.next = head head
15
Appending a Node temp head “A”
head.previous always points to the last node The last node’s next pointer always points back to head temp = TwoWayNode("A", head.previous, head) # Step 1 temp head “A”
16
Appending a Node temp head “A”
head.previous always points to the last node The last node’s next pointer always points back to head temp = TwoWayNode("A", head.previous, head) # Step 1 head.previous.next = temp # Step 2 temp head “A”
17
Appending a Node temp head “A”
head.previous always points to the last node The last node’s next pointer always points back to head temp = TwoWayNode("A", head.previous, head) # Step 1 head.previous.next = temp # Step 2 head.previous = temp # Step 3 temp head “A”
18
Analysis temp head “A” No loop is needed to locate the last node
Append is a constant time operation! No if statements are needed to check for special cases temp = TwoWayNode("A", head.previous, head) # Step 1 head.previous.next = temp # Step 2 head.previous = temp # Step 3 temp head “A”
19
Data for LinkedList self._head from node import TwoWayNode
from abstractlist import AbstractList class LinkedList(AbstractList): """A linked list implementation.""" # Constructor def __init__(self, sourceCollection = None): """Sets the initial state of self, which includes the contents of sourceCollection, if it's present.""" self._head = TwoWayNode(None) self._head.previous = self._head.next = self._head AbstractList.__init__(self, sourceCollection) self._head
20
Index-Based Operations
For __getitem__, __setitem__, insert, and pop Need to locate the ith node in the linked structure Define a helper method named _getNode Takes an index as an argument and returns the node at that position
21
Defining _getNode Usage: def _getNode(self, i):
"""Helper method: returns a pointer to the node at position i.""" probe = self._head.next while i > 0: probe = probe.next i -= 1 return probe Usage: ithNode = self._getNode(i) # Then access data, next, or previous in ithNode
22
Defining [] (subscript for access)
def __getitem__(self, i): """Precondition: 0 <= i < len(self) Returns the item at position i. Raises: IndexError.""" if i < 0 or i >= len(self): raise IndexError("List index out of range") ithNode = self._getNode(i) return ithNode.data Usage: item = lyst[i] What is the running time of [] for a linked list?
23
Insertion into a Linked List
2 1 self._head D1 D2 lyst.insert(1, D3) The data nodes have virtual index positions, starting at 0 The header node has a virtual index position of the length of the list No special cases of insertions at head or tail, no if statements!
24
Insertion into a Linked List
2 1 self._head D1 D2 lyst.insert(1, D3) ithNode Get a pointer to the ith node
25
Insertion into a Linked List
2 1 self._head D1 D2 lyst.insert(1, D3) ithNode newNode D3 Get a pointer to the ith node Create a new node with the ith node’s previous as the previous and the ith node as the next
26
Insertion into a Linked List
2 1 self._head D1 D2 lyst.insert(1, D3) ithNode newNode D3 Get a pointer to the ith node Create a new node with the ith node’s previous as the previous and the ith node as the next Reset the ith node’s previous.next to the new node
27
Insertion into a Linked List
2 1 self._head D1 D2 lyst.insert(1, D3) ithNode newNode D3 Get a pointer to the ith node Create a new node with the ith node’s previous as the previous and the ith node as the next Reset the ith node’s previous.next to the new node Reset the ith node’s previous to the new node
28
Defining insert What is the running time of insert for a linked list?
def insert(self, i, item): """Inserts the item at position i.""" if i < 0: i = 0 elif i > len(self): i = len(self) ithNode = self._getNode(i) ithNode = TwoWayNode(item, ithNode.previous, ithNode) ithNode.previous.next = ithNode ithNode.previous = ithNode self._size += 1 self.incModCount() What is the running time of insert for a linked list?
29
For Wednesday List iterators
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.