-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLinkedList.py
More file actions
209 lines (177 loc) · 6.49 KB
/
Copy pathLinkedList.py
File metadata and controls
209 lines (177 loc) · 6.49 KB
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
"""
linkedlist.py
A Linked List interface and implementation in Python
This version uses a cursor. Using indices is inherently inefficient and
hides the strengths of the linked list.
Cursors, immutable, are created by list methods.
auteur: James Heliotis
"""
from node import LinkedNode
class LinkedList:
__slots__ = '__front'
def __init__( self ):
""" Create an empty list.
"""
self.__front = None
def append( self, new_value ):
""" Add value to the end of the list.
List is modified.
:param new_value: the value to add
:return: None
"""
node = self.__front
newNode = LinkedNode( new_value )
if node == None:
self.__front = newNode
else:
while node.link != None:
node = node.link
node.link = newNode
def prepend( self, new_value ):
""" Add value to the beginning of the list.
List is modified.
:param new_value: the value to add
:return: None
"""
self.__front = LinkedNode( new_value, self.__front )
def start( self ):
""" Generate a cursor that refers to the beginning of the list.
List is unchanged.
:return: a cursor, possibly 'off' if list is empty
"""
return self.__front
def is_off( self, cursor ):
""" Is the cursor off the list?
:param cursor: the cursor (list position) to be tested
:return: True iff the cursor is not at a valid location in the list.
"""
return cursor == None
def get_value( self, cursor ):
""" Get the value at the location indicated by the cursor.
List is unchanged.
:pre: not self.is_off( cursor );
raises ValueError in event of violation
:param cursor: the list position of the desired value
:return: value stored at cursor's location
"""
if self.is_off( cursor ):
raise ValueError()
return cursor.value
def set_value( self, cursor, new_value ):
""" Change the value at the location indicated by the cursor.
List is modified.
:pre: not self.is_off( cursor )
:param cursor: the list position of the value to be changed
:return: None
"""
if self.is_off( cursor ):
raise ValueError()
cursor.value = new_value
def next_loc( self, cursor ):
""" Create a new cursor to the next position in the list, or
'off' if cursor is at the last position.
List is unmodified.
:pre: not self.is_off( cursor )
raises ValueError in event of violation
:param cursor: the list position
:return: the new cursor
"""
if self.is_off( cursor ):
raise ValueError()
return cursor.link
def insert( self, cursor, new_value ):
""" Place a new value in the list, just before the position
of the cursor. If the cursor is 'off', this method works
just like the append method.
List is modified.
The cursor still refers the location it did in the list
before this method was called.
:param cursor: the list position
:param new_value: the value to be placed before the cursor position
:return: None
"""
if cursor == self.__front:
self.prepend( new_value )
else:
node = self.__front
while node.link != cursor:
node = node.link
node.link = LinkedNode( new_value, cursor )
def size( self ):
""" Return the number of data elements in this list.
:post: result >= 0
"""
return self._size_to_end( self.__front )
def _size_to_end( self, node ):
if node == None:
return 0
else:
return 1 + self._size_to_end( node.link )
class _Iter:
__slots__ = 'cursor', 'the_list'
def __next__( self ):
if self.the_list.is_off( self.cursor ):
raise StopIteration()
else:
result = self.the_list.get_value( self.cursor )
self.cursor = self.the_list.next_loc( self.cursor )
return result
def __iter__( self ):
result = LinkedList._Iter()
result.the_list = self
result.cursor = self.start()
return result
def iter2( self ):
cursor = self.start()
while not self.is_off( cursor ):
yield self.get_value( cursor )
cursor = self.next_loc( cursor )
def iter3( self, action ):
cursor = self.start()
while not self.is_off( cursor ):
action( self.get_value( cursor ) )
cursor = self.next_loc( cursor )
def print_list( seq, msg ):
""" Print the contents of a list on a single line, first to last.
"""
print( "%s\n===============\n[%d] " % ( msg, seq.size() ), end="" )
cursor = seq.start()
while not seq.is_off( cursor ):
print( seq.get_value( cursor ), end=" " )
cursor = seq.next_loc( cursor )
print()
print( "%s\n===============\n[%d] " % ( msg, seq.size() ), end="" )
for element in seq:
print( element, end=" " )
print()
print( "%s\n===============\n[%d] " % ( msg, seq.size() ), end="" )
for element in seq.iter2():
print( element, end=" " )
print()
print( "%s\n===============\n[%d] " % ( msg, seq.size() ), end="" )
seq.iter3( lambda element: print( element, end=" " ) )
print()
def test():
# Create a list.
seq = LinkedList()
print_list( seq, "START" )
# Add values using append.
for even in 4, 6:
seq.append( even )
# Prepend a value
seq.prepend( 2 )
print_list( seq, "EVENS" )
# Weave additional elements in to the list.
odd = 1
cursor = seq.start()
while not seq.is_off( cursor ):
seq.insert( cursor, odd )
odd += 2
cursor = seq.next_loc( cursor )
seq.insert( cursor, odd )
print_list( seq, "UPTO7" )
# Test the set_value method.
seq.set_value( seq.start(), -1 )
print_list( seq, "NEGTV" )
if __name__ == "__main__":
test()