Lecture 4-5:�Arrays & Linked Lists
Announcement
Goal:�Searching
Recursion
Array & Linked List
Stack & Queue
2024/10/13(MON) – Quiz 1
2
Arrays
3
Internal Implementation: Memory
3
10
a = 3
b = 10
b += 7
17
c = 1234567890L
1234567890
4
Array Resizing
Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
Value | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | -0 | 0 |
Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
Value | -7 | 15 | 2 | 6 | -1 | 5 | 4 | 10 | -4 | 21 |
L
Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
Value | -7 | 15 | 2 | 6 | -1 | 5 | 4 | 10 | -4 | 21 |
10 |
0 |
10 |
3 |
Create a new long array O(1)
Create(copy) a new long array O(N)
Add a new element O(1)
5
Internal Implementation: Memory
3
10
17
1234567890
1
2
3
4
5
a.append(6)
This is not ideal, since we do not have to know how memory space is being used at every moment!
O(1)
O(N)
6
Arrays
Array�(Fixed length)
List�(Dynamic length)
Resizing
Shifting
Copying
7
Array Resizing
8
Linked Lists
9
Linked Lists
3
10
17
1234567890
1
2
3
4
5
l.append(5)
1
2
7
3
4
5
4
5
5
7
2
13579246810
l.append(7)
l.append(2)
10
Linked Lists
class Node():
def __init__(self, x):
self.item = x
self.next = None
a = Node(5)
b = Node(6)
a.next = b
5
a
6
b
print(a.item)
print(a.next.item)
5
6
item
next
11
Review: Python Object Reference
p = Node(5)
p = Node(6)
p.item
q.item
5
6
q = p
6
6
q = Node(9)
6
9
p = None
Error!
9
q = p
Error!
Error!
12
Singly Linked List
5
a
6
item
next
3
7
at position i
13
Singly Linked List
class Node():
def __init__(self, x):
self.item = x
self.next = None
class LinkedList():
def __init__(self):
self.first = None
def insert(self, x, i):
# insert x at [i]
def get(self, i):
# get item at [i]
def delete(self, i):
# delete item at [i]
5
first
6
item
next
14
Inserting an Item at position i
Example:�insert “4” at position 2.
5
first
6
item
next
3
7
4
curr
curr
15
Inserting an Item at position i
def insert(self, x, i):
# insert x at [i]
new_node = Node(x)
pos = 0
curr = self.first
while pos < i - 1:
curr = curr.next
pos += 1
new_node.next = curr.next
curr.next = new_node
class Node():
def __init__(self, x):
self.item = x
self.next = None
5
first
6
item
next
3
7
4
curr
curr
new_node
Step 1
Step 2
Step 3
Step 4
16
Does this work at the end?
Example:�insert “4” at position 4.
5
first
6
item
next
3
7
4
curr
curr
curr
curr
17
Does this work at the beginning?
Example:�insert “4” at position 0.
5
first
6
item
next
3
7
4
curr
curr
curr
curr
i - 1 = -1 😨
18
Inserting an Item at position i
Check: does this work when we insert the very first item (that is, does it work when self.first = None)?
def insert(self, x, i):
# insert x at [i]
if i == 0:
new_node = Node(x)
new_node.next = self.first
self.first = new_node
else:
new_node = Node(x)
pos = 0
curr = self.first
while pos < i - 1:
curr = curr.next
pos += 1
new_node.next = curr.next
curr.next = new_node
19
Inserting an Item at position i
Check: what happens with our code if i > last position?
It will crash here, when it tries to access None.next
We should prevent this, instead of letting the users to be responsible!
def insert(self, x, i):
# insert x at [i]
if i == 0:
new_node = Node(x)
new_node.next = self.first
self.first = new_node
else:
new_node = Node(x)
pos = 0
curr = self.first
while pos < i - 1:
curr = curr.next
pos += 1
new_node.next = curr.next
curr.next = new_node
7
curr
…
None
20
Size Variable
def insert(self, x, i):
# insert x at [i]
� if i == 0:
new_node = Node(x)
new_node.next = self.first
self.first = new_node
else:
new_node = Node(x)
pos = 0
curr = self.first
while pos < i - 1:
curr = curr.next
pos += 1
new_node.next = curr.next
curr.next = new_node
From 0 to current length (item count)
if i > size: return
elif i <= size:
21
Size Variable
class LinkedList():
def __init__(self):
self.first = None
self.size = 0
def insert(self, x, i):
# insert x at [i]
def get(self, i):
# get item at [i]
def delete(self, i):
# delete item at [i]
def insert(self, x, i):
# insert x at [i]� if i == 0:
new_node = Node(x)
new_node.next = self.first
self.first = new_node
self.size += 1
elif i <= self.size:
new_node = Node(x)
pos = 0
curr = self.first
while pos < i - 1:
curr = curr.next
pos += 1
new_node.next = curr.next
curr.next = new_node
self.size += 1
O(1)
22
Retrieving an Item at position i – Homework
def get(self, i):
# get item at [i]
# TODO(students): implement!
return ?
23
Deleting an Item at position i
Example:�delete item at position 2.
This node is no longer accessible. “3” is no longer in your list!
5
first
6
item
next
3
7
curr
curr
24
Deleting an Item at position i
def delete(self, i):
# delete item at [i]
pos = 0
curr = self.first
while pos < i - 1:
curr = curr.next
pos += 1�
curr.next = curr.next.next
self.size -= 1
class Node():
def __init__(self, x):
self.item = x
self.next = None
5
first
6
item
next
3
7
curr
curr
Any edge case here?
Step 2
Step 1
25
Does this work at the end?
Example:�delete item at position 3.
5
first
6
item
next
3
7
curr
26
Does this work at the beginning?
Example:�delete item at position 0.
Again, we need special treatment when we delete the first one!
This condition is never satisfied.
5
first
item
next
curr
i - 1 = -1 😨
def delete(self, i):
# delete item at [i]
pos = 0
curr = self.first
while pos < i - 1:
curr = curr.next
pos += 1�
curr.next = curr.next.next
self.size -= 1
if i == 0:
self.first = self.first.next
else:
...
27
Time Complexity
Happen when?
Task | Worst case | Average case | Best case |
Insertion | | | |
Retrieval | | | |
Deletion | | | |
O(N)
O(N)
O(N)
O(N)
O(N)
O(N)
O(1)
O(1)
O(1)
28
Doubly Linked List
29
Comparison
30
Applications of Linked Lists��Code: https://colab.research.google.com/drive/16mXIWEEsKeH52HPPdpVA7EEvDTckGWnH?usp=sharing
31
Application Questions
5
7
2
8
2
4
9
32
Application Questions
33
Application Questions
5
7
2
8
2
4
9
9
4
2
8
2
7
5
34
Application Questions
5
7
2
8
2
4
9
35