-
Notifications
You must be signed in to change notification settings - Fork 0
/
linkedlist.py
182 lines (154 loc) · 6.68 KB
/
linkedlist.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!python
class Node(object):
def __init__(self, data):
"""Initialize this node with the given data."""
self.data = data
self.next = None
def __repr__(self):
"""Return a string representation of this node."""
return 'Node({!r})'.format(self.data)
class LinkedList(object):
def __init__(self, items=None):
"""Initialize this linked list and append the given items, if any."""
self.head = None # First node
self.tail = None # Last node
self.size = 0 # Length
# Append given items
if items is not None:
for item in items:
self.append(item)
def __str__(self):
"""Return a formatted string representation of this linked list."""
items = ['({!r})'.format(item) for item in self.items()]
return '[{}]'.format(' -> '.join(items))
def __repr__(self):
"""Return a string representation of this linked list."""
return 'LinkedList({!r})'.format(self.items())
def items(self):
"""Return a list (dynamic array) of all items in this linked list.
Best and worst case running time: O(n) for n items in the list (length)
because we always need to loop through all n nodes to get each item."""
items = [] # O(1) time to create empty list
# Start at head node
node = self.head # O(1) time to assign new variable
# Loop until node is None, which is one node too far past tail
while node is not None: # Always n iterations because no early return
items.append(node.data) # O(1) time (on average) to append to list
# Skip to next node to advance forward in linked list
node = node.next # O(1) time to reassign variable
# Now list contains items from all nodes
return items # O(1) time to return list
def is_empty(self):
"""Return a boolean indicating whether this linked list is empty. - 0(1)"""
return self.head is None
def length(self):
"""Return the length of this linked list by traversing its nodes.
Best and worst running time: O(n) for n nodes in the list
because we have to iterate over all n nodes and count 1 for each"""
# Loop through all nodes and count one for each
count = 0
node = self.head
while node is not None:
count += 1
node = node.next
return count
def append(self, item):
"""Insert the given item at the tail of this linked list.
Best and worst running timme: O(1) - only change the tail node"""
# Create new node to hold given item
# Append node after tail, if it exists
node = Node(item)
if self.is_empty():
self.head = node
else:
self.tail.next = node
# Update tail to new node regardless
self.tail = node
def prepend(self, item):
"""Insert the given item at the head of this linked list.
Best and worth case running time: O(1) because we only change
the first node and never loop through all nodes"""
# Create new node to hold given item
# Prepend node before head, if it exists
node = Node(item)
if self.head is None:
self.head = node
self.tail = node
else:
node.next = self.head
self.head = node
self.size += 1
def find(self, quality):
"""Return an item from this linked list satisfying the given quality.
Best case running time: O(1) if item is near the head of the list.
Worst case running time: O(n) if item is near the tail of the list or not
present, and we need to loop through all n nodes in the list"""
# Loop through all nodes to find item where quality(item) is True
# Check if node's data satisfies given quality function
node = self.head
while node is not None:
print(quality)
if quality(node.data):
print(node.data)
return node.data
node = node.next
return None
# Delete Code attribution: https://github.com/anselb/Tweet-Generator/blob/master/source/linkedlist.py
def delete(self, item):
"""Delete the given item from this linked list, or raise ValueError.
TODO: Best case running time: O(???) Why and under what conditions?
TODO: Worst case running time: O(???) Why and under what conditions?"""
# Loop through all nodes to find one whose data matches given item
# Update previous node to skip around node with matching data
# Otherwise raise error to tell user that delete has failed
# Hint: raise ValueError('Item not found: {}'.format(item))
current_node = self.head
deleted = False
previous = None
while current_node is not None:
if current_node.data == item and current_node is self.head and current_node is self.tail:
self.head = None
self.tail = None
deleted = True
elif current_node.data == item and current_node is self.head:
self.head = current_node.next
if self.head == self.tail:
self.tail = current_node.next
deleted = True
elif current_node.data == item and current_node is self.tail:
self.tail = previous
self.tail.next = None
if self.head == self.tail:
self.head = previous
deleted = True
elif current_node.data == item:
previous.next = current_node.next
deleted = True
previous = current_node
current_node = current_node.next
if not deleted:
raise ValueError('Item not found: {}'.format(item))
def test_linked_list():
ll = LinkedList()
print('list: {}'.format(ll))
print('\nTesting append:')
for item in ['A', 'B', 'C']:
print('append({!r})'.format(item))
ll.append(item)
print('list: {}'.format(ll))
print('head: {}'.format(ll.head))
print('tail: {}'.format(ll.tail))
print('length: {}'.format(ll.length()))
# Enable this after implementing delete method
delete_implemented = False
if delete_implemented:
print('\nTesting delete:')
for item in ['B', 'C', 'A']:
print('delete({!r})'.format(item))
ll.delete(item)
print('list: {}'.format(ll))
print('head: {}'.format(ll.head))
print('tail: {}'.format(ll.tail))
print('length: {}'.format(ll.length()))
if __name__ == '__main__':
test_linked_list()