1 / 50

Computer Science 112

Computer Science 112. Fundamentals of Programming II Introduction to Linked Structures. Basic Array Operations. Constructor: Array(size, fillValue = None ) Length: len (a) Access: a[index] Replacement: a[index] = newValue Iteration: for value in a :

Download Presentation

Computer Science 112

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Computer Science 112 Fundamentals of Programming II Introduction to Linked Structures

  2. Basic Array Operations Constructor: Array(size, fillValue = None) Length: len(a) Access: a[index] Replacement: a[index] = newValue Iteration: for value in a: Search: value in a Elements can be of any type [] has a precondition on the index

  3. Problems With Arrays • Insertions and deletions require shifting elements, an O(n) operation • Length is fixed at instantiation, resizing requires new memory and transfer of elements

  4. Why We Have These Problems • Array cells map to adjacent cells in memory, to support constant-time access • There is a one-to-one correspondence between the logical structure of the sequence of elements and the underlying memory storage • If we can decouple the logical sequence and the memory representation, we might solve these problems

  5. Linked Structures D1 D2 D3 D4 A linked structure allows us to represent a sequence of elements independently of their positions in memory Linked structures support insertions, deletions, and traversals, but not random access Storage is allocated for each new element, as needed, from an area of memory called the system heap

  6. Linked Structures A linked structure consists of a unique external link.

  7. Linked Structures D1 D2 D3 • A linked structure consists of a unique external link. • This link is either empty or points to a node. • A node contains two parts: • a data element • a link to the next node

  8. Linked Structures D1 D2 D3 D4 • A linked structure consists of a unique external link. • This link is either empty or points to a node. • A node contains two parts: • a data element • a link to the next node • The last node in a linked structure contains an empty link

  9. Arrays and Computer Memory The variable numbers contains the address of the first cell in the array The array cells are adjacent in memory 0 1 2 2 0 656 ... ... numbers 656 657 658 659 660 3 6 5 3 0 1 2 3 4 6 5 Memory address of numbers[2] = base address in numbers + 2 = 656 + 2 = 658 0 2 ... ... 65534 65535 10 9

  10. Nodes and Computer Memory 0 1 2 2 numbers 3 6 5 1 0 1 2 65534 ... ... 656 657 658 659 660 6 658 5 The variable numbers contains the address of the first node in the linked structure 0 2 ... ... 65534 65535 3 656

  11. Nodes and Computer Memory 0 1 2 2 numbers 3 6 5 1 0 1 2 65534 ... ... 656 657 658 659 660 6 658 5 The address of the second node is contained in the previous node’s next link 0 2 ... ... 65534 65535 3 656

  12. Nodes and Computer Memory 0 1 2 2 numbers 3 6 5 1 0 1 2 65534 ... ... 656 657 658 659 660 6 658 5 The last node’s next link is None, which is the memory address 0 0 2 ... ... 65534 65535 3 656

  13. An Empty External link When there are no data, there are no nodes and the external link is empty Links are sometimes called pointers or references References in Python are either None or refer to objects A node will be a new type of object

  14. Linked Structures D1 When a data element is inserted, we create a new node, set its data field to the data element, and set its link to None.

  15. A Node Class class Node(object): def__init__(self, data, next = None): self.data = data self.next = next Usually a utility class to be used within a client class No need for accessor or mutator methods The data can be any Python object The next is always either another node or None

  16. Declaring an External Pointer class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = None head just contains an empty link or None pointer head

  17. Adding a Node class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = Node("A", None) head contains a link or reference to a node head “A”

  18. Display the Data Element class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = Node("A", None) print(head.data) Displays the letter “A” head “A”

  19. Adding and Accessing a Second Node class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = Node("A", Node("B", None)) print(head.next.data) Displays the letter “B” head “A” “B”

  20. Type Exception on None class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = Node("A", None) print(head.next.data) Raises an exception: None has no data field head “A”

  21. Prepend 5 Data Elements class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = None for iin range(1, 6): head = Node(i, head) head

  22. Prepend 5 Data Elements class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = None for iin range(1, 6): head = Node(i, head) head 1

  23. Prepend 5 Data Elements class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = None for iin range(1, 6): head = Node(i, head) head 2 1

  24. Prepend 5 Data Elements class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = None for iin range(1, 6): head = Node(i, head) head 3 2 1

  25. Prepend 5 Data Elements class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = None for iin range(1, 6): head = Node(i, head) head 4 3 2 1

  26. Prepend 5 Data Elements class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = None for iin range(1, 6): head = Node(i, head) head 5 4 3 2 1

  27. Traverse the Structure class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = <prepend 5 elements> probe = head while probe != None: print(probe.data) probe = probe.next head probe 5 4 3 2 1

  28. Traverse the Structure class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = <prepend 5 elements> probe = head while probe != None: print(probe.data) probe = probe.next head probe 5 4 3 2 1

  29. Traverse the Structure class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = <prepend 5 elements> probe = head while probe != None: print(probe.data) probe = probe.next head probe 5 4 3 2 1

  30. Traverse the Structure class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = <prepend 5 elements> probe = head while probe != None: print(probe.data) probe = probe.next head probe 5 4 3 2 1

  31. Traverse the Structure class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = <prepend 5 elements> probe = head while probe != None: print(probe.data) probe = probe.next head probe 5 4 3 2 1

  32. Traverse the Structure class Node(object): def__init__(self, data, next = None): self.data = data self.next = next head = <prepend 5 elements> probe = head while probe != None: print(probe.data) probe = probe.next head probe 5 4 3 2 1

  33. Delete the First Element (Node) class Node(object): def__init__(self, data, next = None): self.data = data self.next = next if head != None: head = head.next head 5 4 3 2 1

  34. Delete the First Element (Node) class Node(object): def__init__(self, data, next = None): self.data = data self.next = next The deleted node cannot be referenced, so the garbage collector will return it to the system memory if head != None: head = head.next head 5 4 3 2 1

  35. Clear the Structure class Node(object): def__init__(self, data, next = None): self.data = data self.next = next The deleted nodes cannot be referenced, so the garbage collector will return them all to the system memory head = None head 5 4 3 2 1

  36. Memory as Needed • The logical size and the physical size of the structure are always the same • Memory is allocated for new nodes only when needed • Storage for deleted nodes is reclaimed by the system

  37. Analysis of Insert and Remove at the Head • Use of memory is always O(1) • No movement of data within the structure, just rearrange a couple of links, O(1) running time • Quite the opposite behavior of arrays

  38. Insert at the End (Append an Element) • If the head pointer is empty, just assign it a new node • Otherwise, • chain down the links until you reach the pointer to the last node • Set the last node’s next pointer to a new node

  39. Insert at the End (Append an Element) newNode = Node(1, None) if head == None: head = newNode else: probe = head whileprobe.next != None: probe = probe.next probe.next = newNode newNode 1 head probe 5 4 3 2

  40. Insert at the End (Append an Element) newNode = Node(1, None) if head == None: head = newNode else: probe = head whileprobe.next != None: probe = probe.next probe.next = newNode newNode 1 head probe 5 4 3 2

  41. Insert at the End (Append an Element) newNode = Node(1, None) if head == None: head = newNode else: probe = head whileprobe.next != None: probe = probe.next probe.next = newNode newNode 1 head probe 5 4 3 2

  42. Insert at the End (Append an Element) newNode = Node(1, None) if head == None: head = newNode else: probe = head whileprobe.next != None: probe = probe.next probe.next = newNode newNode 1 head probe 5 4 3 2

  43. Insert at the End (Append an Element) newNode = Node(1, None) if head == None: head = newNode else: probe = head whileprobe.next != None: probe = probe.next probe.next = newNode newNode 1 head probe 5 4 3 2

  44. Insert at (before) the ith Position i = 2 if head == Noneori == 0: head = Node(1, head) else: probe = head whilei > 1 andprobe.next != None: probe = probe.next i -= 1 probe.next = Node(1, probe.next) head probe 5 4 3 2 0 1 2 3

  45. Insert at the ith Position i = 2 if head == Noneori == 0: head = Node(1, head) else: probe = head whilei > 1 andprobe.next != None: probe = probe.next i -= 1 probe.next = Node(1, probe.next) head probe 5 4 3 2 0 1 2 3

  46. Insert at the ith Position i = 2 if head == Noneori == 0: head = Node(1, head) else: probe = head whilei > 1 andprobe.next != None: probe = probe.next i -= 1 probe.next = Node(1, probe.next) newNode 1 head probe 5 4 3 2 0 1 2 3

  47. Analysis of Insertions • Use of memory is O(1) • No movement of data within the structure, just rearrange a couple of links • Append at the end and insert at the ith position are both O(n), because we must chain down the links • Same behavior for removals, accesses, and replacements at the ith position

  48. Tradeoffs: Array or Linked Structure? numbers 5 4 3 2 0 1 2 3 4 numCount 4 numbers 5 4 3 2

  49. Tradeoffs • Arrays: • Constant-time access is good for binary search, implementing a dictionary, etc. • Uses less memory if the array is close to full • Linked structures: • Uses memory only as needed, never have to resize • Insertions and removals need no extra overhead to shift data elements • But accesses, replacements, insertions, and removals at arbitrary positions are linear time operations

  50. For Wednesday Interfaces and Implementations Chapter 5

More Related