Computer Science 112 Fundamentals of Programming II Linked





















![Defining [] (subscript for access) def __getitem__(self, i): """Precondition: 0 <= i < len(self) Defining [] (subscript for access) def __getitem__(self, i): """Precondition: 0 <= i < len(self)](https://slidetodoc.com/presentation_image_h2/87bb1901daf99b1452fca334550de1eb/image-22.jpg)







- Slides: 29
Computer Science 112 Fundamentals of Programming II Linked Lists
The List Clan Abstract. Collection Abstract. List. Interface Two. Way. Node * Linked. List Array
Insert into An Array List def insert(self, i, item: ( """ Inserts the item at position i""". # Resize array if necessary here. 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. inc. Mod. Count() No precondition on the index, can insert after the last item The index is normalized: 0 <= i <= len(self)
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
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
Problems with Linked Structures Appending, which is constant time for arrays, is linear for a singly linked structure new. Node head probe 5 4 3 2 1
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 new. Node head tail 5 4 3 2 1
Solution: A Tail Pointer new. Node = Node(1, None) if head == None: head = new. Node else: tail. next = new. Node tail = new. Node head tail 5 4 3 2 1
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
Other Linked Structures head D 1 D 2 D 3 D 4 A singly linked structure permits movement in one direction only head D 1 D 2 D 3 A doubly linked structure permits movement in both directions and simplifies some operations
Doubly Linked Structures head D 1 D 2 D 3 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
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
The Node Class class Two. Way. Node(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
Declaring an External Pointer class Two. Way. Node(object): def __init__(self, data, previous = None, next = None): self. data = data self. previous = previous self. next = next head = Two. Way. Node(None) head. previous = head. next = head
Appending a Node head. previous always points to the last node The last node’s next pointer always points back to head temp = Two. Way. Node("A", head. previous, head) # Step 1 temp head “A”
Appending a Node head. previous always points to the last node The last node’s next pointer always points back to head temp = Two. Way. Node("A", head. previous, head) head. previous. next = temp # Step 1 # Step 2 temp head “A”
Appending a Node head. previous always points to the last node The last node’s next pointer always points back to head temp = Two. Way. Node("A", head. previous, head) head. previous. next = temp head. previous = temp # Step 1 # Step 2 # Step 3 temp head “A”
Analysis 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 = Two. Way. Node("A", head. previous, head) head. previous. next = temp head. previous = temp # Step 1 # Step 2 # Step 3 temp head “A”
Data for Linked. List from node import Two. Way. Node from abstractlist import Abstract. List class Linked. List(Abstract. List): """A linked list implementation. """ # Constructor def __init__(self, source. Collection = None): """Sets the initial state of self, which includes the contents of source. Collection, if it's present. """ self. _head = Two. Way. Node(None) self. _head. previous = self. _head. next = self. _head Abstract. List. __init__(self, source. Collection) self. _head
Index-Based Operations • For __getitem__, __setitem__, insert, and pop • Need to locate the ith node in the linked structure • Define a helper method named _get. Node • Takes an index as an argument and returns the node at that position
Defining _get. Node def _get. Node(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: ith. Node = self. _get. Node(i) # Then access data, next, or previous in ith. Node
Defining [] (subscript for access) def __getitem__(self, i): """Precondition: 0 <= i < len(self) Returns the item at position i. Raises: Index. Error. """ if i < 0 or i >= len(self): raise Index. Error("List index out of range") ith. Node = self. _get. Node(i) return ith. Node. data Usage: item = lyst[i] What is the running time of [] for a linked list?
Insertion into a Linked List 2 self. _head 0 1 D 2 lyst. insert(1, D 3) 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!
Insertion into a Linked List 2 self. _head lyst. insert(1, D 3) 1. Get a pointer to the ith node 0 1 D 2 ith. Node
Insertion into a Linked List 2 self. _head lyst. insert(1, D 3) new. Node 0 1 D 2 D 3 ith. Node 1. Get a pointer to the ith node 2. Create a new node with the ith node’s previous as the previous and the ith node as the next
Insertion into a Linked List 2 self. _head lyst. insert(1, D 3) new. Node 0 1 D 2 D 3 ith. Node 1. Get a pointer to the ith node 2. Create a new node with the ith node’s previous as the previous and the ith node as the next 3. Reset the ith node’s previous. next to the new node
Insertion into a Linked List 2 self. _head lyst. insert(1, D 3) new. Node 0 1 D 2 D 3 ith. Node 1. Get a pointer to the ith node 2. Create a new node with the ith node’s previous as the previous and the ith node as the next 3. Reset the ith node’s previous. next to the new node 4. Reset the ith node’s previous to the new node
Defining insert def insert(self, i, item): """Inserts the item at position i. """ if i < 0: i = 0 elif i > len(self): i = len(self) ith. Node = self. _get. Node(i) ith. Node = Two. Way. Node(item, ith. Node. previous, ith. Node) ith. Node. previous. next = ith. Node. previous = ith. Node self. _size += 1 self. inc. Mod. Count() What is the running time of insert for a linked list?
For Wednesday List iterators