Presentation is loading. Please wait.

Presentation is loading. Please wait.

Fundamentals of Programming II Linked Lists

Similar presentations


Presentation on theme: "Fundamentals of Programming II Linked Lists"— Presentation transcript:

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


Download ppt "Fundamentals of Programming II Linked Lists"

Similar presentations


Ads by Google