Professional Documents
Culture Documents
Lecture 5 - Linked Structures
Lecture 5 - Linked Structures
CIS-275
Linked Structures
● After arrays, linked structures are the most commonly used data structure in
computer science.
○ Linked structures are often called linked lists.
● When we design more complex data structures, such as stacks and queues, we will
often use either an array or a linked list to internally store the structure’s data.
● Linked Lists and arrays each have pros and cons, which we will discuss at the end of
this lecture.
class Node():
""" Represents a singly linked Node """
● When the client creates a Node object, they can initialize it to point to another Node,
but by default it will point to nothing.
node1 = None
node1
Chapter 4 Arrays and Linked Structures 11
Defining a Singly Linked Node Class
● Consider our Node class. What does the following client code do?
node1
Chapter 4 Arrays and Linked Structures 12
Defining a Singly Linked Node Class
● What does the second line of code do?
node1 = None
node2 = Node("A")
node1
Chapter 4 Arrays and Linked Structures 13
Defining a Singly Linked Node Class
● What does the second line of code do?
node1 = None
node2 = Node("A") # Create a variable that references a Node object.
● The reference variable node2 is set to reference a new Node object in memory.
● This object contains two attributes: the string “A” as its data and an empty link.
○ Recall that if we don’t pass a second argument, the Node’s _next attribute is
assigned None by default.
node2
node1 A
node2
node1 A
node1 B A
node3 node2
node1 B A
node1 B A
C B A
C B A
C B A
Head
C B A
Chapter 4 Arrays and Linked Structures 22
Generating a Singly Linked List
● In the 1st step, we assign a new Node to head. Its data is “A” and its next is None.
head = Node("A")
Head
A
Chapter 4 Arrays and Linked Structures 23
Generating a Singly Linked List
● In the 2nd step, we assign a new Node to head. Its data is “B” and its next is “A”.
● Note: The right side of = is evaluated first. When we pass head to the constructor, it is
still referencing “A”.
○ Therefore, the constructor points the new Node’s next to “A”.
○ After the constructor returns, the = operator points head to the new Node, “B”
head
B A
Chapter 4 Arrays and Linked Structures 24
Generating a Singly Linked List
● In the 3rd step, we assign a new Node to head. Its data is “C” and its next is “B”.
● We have now built a proper linked list with 3 Nodes and a single external pointer.
head
C B A
Chapter 4 Arrays and Linked Structures 25
Generating a Singly Linked List
● Let’s write a loop that creates a linked list with the values 1 through 5.
head = None
for count in range(1, 6):
head = Node(count, head)
● In the first iteration of the loop, we create a Node with 1 as its data.
○ head currently references None, so None is assigned to this Node’s next.
● In the second iteration, we create a Node with 2 as its data.
○ Its next is pointed to the Node containing 1.
○ head is then pointed to the new Node containing 2.
● etc...
head
5 4 3 2 1
Chapter 4 Arrays and Linked Structures 28
Traversing a Linked List
head = None
for count in range(1, 6):
head = Node(count, head)
● In the first iteration of the while loop, the data of the first Node in the list is printed.
● head is then updated to point to the next Node in the list.
● This process continues until head references the Node containing “1”.
● After printing 1, head is updated to head.next, which is None, and the loop ends.
head
5 4 3 2 1
Chapter 4 Arrays and Linked Structures 29
Traversing a Linked List
head = None
for count in range(1, 6):
head = Node(count, head)
● Consider this code. Suppose we wanted to print the list a second time.
○ How would we do this?
● Consider this code. Suppose we wanted to print the list a second time.
○ How would we do this? We couldn’t!
● In the first iteration of the while loop, ‘5’ is printed.
● head is then updated to point to ‘4’.
head
5 4 3 2 1
Chapter 4 Arrays and Linked Structures 31
Traversing a Linked List
head = None
for count in range(1, 6):
head = Node(count, head)
head
5 4 3 2 1
Chapter 4 Arrays and Linked Structures 32
Traversing a Linked List
head = None
for count in range(1, 6):
head = Node(count, head)
head
4 3 2 1
Chapter 4 Arrays and Linked Structures 33
Traversing a Linked List
head = None
for count in range(1, 6):
head = Node(count, head)
● In the final iteration of the while loop, “1” is the only remaining Node.
● The statement head = head.next sets head to reference None.
head
1
Chapter 4 Arrays and Linked Structures 34
Traversing a Linked List
head = None
for count in range(1, 6):
head = Node(count, head)
● This while loop prints the list while also deleting it!
● Can we change this code to still traverse the list but not delete it (while also saving the
external pointer to the start of the list)?
head
probe = head
while probe is not None:
print(probe.data)
probe = probe.next
probe = head
while probe is not None:
print(probe.data)
probe = probe.next
● Consider this code which allows the user to create a linked list of names.
● After they have finished, what steps do we need to take to see if the user entered a
specific name (i.e. “Steve”)?
# End of loop: we have traversed whole list and 'target' was not found
return False
def main():
head = None
while True:
name = input("Enter a name or 'q' to stop: ")
if name == 'q':
break
head = Node(name, head)
print(is_in_list(head, "Steve"))
● What steps do we need to take in the following code to add a new Node containing
“Cypress College” to the beginning of this list?
head = None
???
● What steps do we need to take in the following code to add a new Node containing
“Cypress College” to the beginning of this list?
head = None
head = Node( "Cypress College", head)
● Simply create a new Node whose _next points to None. Then, set head to point to it.
● Since head already references None, we can pass that instead.
Chapter 4 Arrays and Linked Structures 46
Inserting at the Beginning of a non-empty List
● Suppose the list is not empty:
● What statement would add a new Node containing “D2” to the beginning of this list?
● What statement would add a new Node containing “D2” to the beginning of this list?
● Create a new Node and set its next to point the current front of the linked list.
● Then, set head to point to this new Node, making it the new front.
● Note that this statement is the same as adding to the beginning of an empty list!
● This simple function takes care of both possible scenarios in a single line of code.
○ If my_list points to the first Node in a list, the new Node we create will have its
_next set to point to it.
○ Otherwise, it will be set to point to None (which is what we want: the first Node of
a linked list with one Node should have a next which points to None).
● Recall that if a parameter is pointed to a different object inside a function, the argument
variable is not updated.
● Note also that add_to_list returns the updated my_list parameter.
● We need to assign this return value to head after the function ends.
○ The linked list is currently empty (the same steps apply as inserting at the front):
# Loop ends when probe points to last Node in list. Update its next to point to the new Node
probe.next = new_node
return my_list
● This function updates its parameter to point to the Node after the one it is currently
pointing to (assuming the parameter doesn’t initially point to None).
● What will the following client code print?
● This function updates its parameter to point to the Node after the one it is currently
pointing to (assuming the parameter doesn’t initially point to None).
● What will the following client code print? 2 1
def remove_at_end(my_list):
""" Removes the final Node from my_list (if it is not empty) """
if my_list is None or my_list.next is None:
# list is empty or only has one node. Return 'None' to indicate the list is now empty
return None
● If the list only has a single Node in it, we can return None to indicate that the list is
empty after the removal.
● Note: We could raise an Error if the client tries to remove from an empty list, but for
now we can skip that.
def remove_at_end(my_list):
""" Removes the final Node from my_list (if it is not empty) """
if my_list is None or my_list.next is None:
# list is empty or only has one node. Return 'None' to indicate the list is now empty
return None
else:
# list has two or more nodes. Find the node before the last one.
probe = my_list
while probe.next.next != None:
probe = probe.next
probe.next = None
return my_list
● If the list has two or more Nodes, we probe to find the second-to-last Node. We then
set its _next to None, making it the new last Node.
● Add the new Node after the one probe points to.
● To do this, we point the new Node’s _next to the Node currently pointed to by probe,
then we point probe’s _next to the new Node.
Chapter 4 Arrays and Linked Structures 74
Inserting at Any Position
def add_to_index(my_list, val_to_add, index):
if index == 0:
● Is there anything that can go
return add_to_list(my_list, val_to_add) wrong with this function?
else:
probe = my_list
cur_index = 0
while cur_index < index - 1:
probe = probe.next
cur_index += 1
# Insert new node after node at position index - 1
probe.next = Node(val_to_add, probe.next)
return my_list
● During traversal, if probe.next is ever None, we’ve reached the end of the list
without finding the target index.
● At this point, we can raise an Error.
Chapter 4 Arrays and Linked Structures 77
Example: Inserting at Index 2
The next few slides will demonstrate how the while
loop we just wrote works.
● Suppose we have a linked list with 3 items and
cur_index 0 the client wants to add “D4” to index 2.
index 2 ● In step 1, we begin traversing the list.
● cur_index is not index - 1, so we are not
at the Node before index 2 yet.
○ A Linked List?
my_array D1 D2 D3 D4
○ A Linked List? O(n), average case. We have to start at head and traverse the list
until we reach the desired index.
■ It is average case, because if the index is 1, it runs in O(1) time.
my_array D1 D2 D3 D4
○ A Linked List?
my_array D1 D2 D3 D4
my_array D1 D2 D3 D4
○ A Linked List?
my_array D1 D2 D3 D4
○ A Linked List? O(1), every-time case. All we need to do is set head to the new
Node.
my_array D1 D2 D3 D4
○ A Linked List?
my_array D1 D2 D3 D4
○ A Linked List? O(n), every-time case. We need to traverse to the end of the list
over n Nodes.
my_array D1 D2 D3 D4