forked from Tom4hawk/FORG
-
Notifications
You must be signed in to change notification settings - Fork 0
/
List.py
249 lines (207 loc) · 8.79 KB
/
List.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
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# List.py
# $Id: List.py,v 1.8 2001/08/12 20:40:14 s2mdalle Exp $
# Written by David Allen <mda@idatar.com>
#
# This is a data structure similar to a doubly linked list, but with a few
# exceptions - it has to keep track of all nodes that have EVER been in the
# list, to cache old nodes for jumping around. It also has to know that when
# you insert a completely new item, it removes everything after the current
# slot in the list. This is because when you jump to a new document like in
# a web browser, you can't then hit the 'forward' button.
#
# The forward and back buttons in the program will correspond to methods in
# this object.
#
# Only put ListNode objects into this.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
###############################################################################
from ListNode import *
class ListException(Exception):
def __init__(self, message):
super(ListException, self).__init__(message)
class List:
def __init__(self):
self.front = ListNode()
self.back = ListNode()
self.front.setNext(self.back)
self.front.setPrev(None)
self.back.setPrev(self.front)
self.back.setNext(None)
self.current = self.front
return None
def goToFront(self):
"""Sets the current node to the first node in the list."""
self.current = self.front.next
return None
def goToBack(self):
"""Sets the current node to the last node in the list."""
self.current = self.back.prev
return None
def atEnd(self):
"""Predicate: Returns true if the current item is the last item in
the list."""
return self.current == self.back
def atFront(self):
"""Predicate: Returns true if the current item is the first item in
the list."""
return self.current == self.front
def itemsRemaining(self):
"""Predicate: Returns true if the current item is not the last
item"""
return not self.atEnd()
def isEmpty(self):
"""Predicate: Returns true if the list contains > 0 items."""
if self.front.getNext() == self.back:
return 1
else:
return None
def traverse(self, function):
"""Takes a function argument, returns a list which contains the result
of applying the function to each item in the list successivly. Sort
of like map() for this list particularly."""
n = self.front.getNext()
listresults = []
while n != self.back:
listresults.append(function(n))
n = n.getNext()
return listresults
def insertAfter(self, newnode, afterWhat):
"""Inserts newnode after afterWhat. afterWhat may actually be either
a ListNode in the list, or it may be the data inside a particular
ListNode. But it must be a reference to the *same* data, (or node)
not a reference to equivalent data (or node)."""
n = self.front.getNext()
if newnode.__class__ != ListNode:
raise ListException("newnode argument must be a ListNode")
while n != self.back.getPrev():
if afterWhat == n or afterWhat == n.getData():
nn = n.getNext()
newnode.setPrev(n)
newnode.setNext(nn)
afterWhat.setNext(newnode)
nn.setPrev(newnode)
return newnode
n = n.getNext()
raise ListException("cannot insert after nonexistent node.")
def removeReference(self, ref):
"""Removes ref from the list. Note this must be a reference to
something in the list, not just something that has the same data."""
n = self.front.getNext()
while n != self.back:
# We're going to be very forgiving and let the user pass us a
# reference to either the data contained in the ListNode object,
# or a reference to the ListNode object itself.
if n == ref or n.getData() == ref:
np = n.getPrev()
nn = n.getNext()
n.setNext(None) # Kill the links on the node we delete...
n.setPrev(None)
np.setNext(nn) # Update the links on the surrounding
nn.setPrev(np) # nodes...
return ref # Get out...we only remove the 1st one.
n = n.getNext() # Next item in the list.
raise ListException("Reference not found in list")
def countNodes(self, f=None):
"""Returns the number of nodes in the list."""
if f is None:
f = self.front
nodes = 0
n = f.getNext()
while n != self.back:
nodes = nodes + 1
n = n.getNext()
return nodes
def prepend(self, node):
"""Inserts the given node at the front of the list."""
self.current = self.front
return self.insert(node, truncate=0)
def postpend(self, node):
"""Inserts the given node at the very back of the list."""
self.current = self.back.getPrev()
return self.insert(node, 0)
def insert(self, node, truncate=1):
"""Inserts node as the next item in the list. If truncate is true,
then all subsequent elements are dropped, and the new node becomes
the last node in the list."""
if truncate:
node.setPrev(self.current)
node.setNext(self.back)
self.current.setNext(node)
self.current = node
return self.current
else:
oldnext = self.current.getNext()
node.setPrev(self.current)
node.setNext(oldnext)
self.current.setNext(node)
oldnext.setPrev(node)
self.current = node
return self.current
def getCurrent(self):
"""Returns the current node."""
return self.current
def removeCurrent(self):
"""Removes the current node. The current node then becomes the next
node in the list."""
if not self.current:
raise ListException("Error: Cannot delete NONE")
if self.current == self.front:
raise ListException("Cannot delete FRONT")
if self.current == self.back:
raise ListException("Cannot delete BACK")
one_before_this_one = self.current.getPrev()
one_after_this_one = self.current.getNext()
one_before_this_one.setNext(one_after_this_one)
one_after_this_one.setPrev(one_before_this_one)
self.current.setPrev(None)
self.current.setNext(None)
self.current.setData(None)
self.current = one_after_this_one
return self.current
def getFirst(self):
"""Returns the first item in the list. Does not change the current
node"""
first = self.front.next
if first == self.back:
raise ListException("The list is empty")
return first
def getLast(self):
"""Returns the last item in the list. Does not change the current
node"""
last = self.back.prev
if last == self.front:
raise ListException("The list is empty")
return last
def getNext(self):
"""Returns the next node in the list, and advances the current node."""
next = self.current.getNext()
if next == self.back or (next == None and next == self.back):
raise ListException("Already at the end of the list")
elif next == None:
raise ListException("getNext(): Null next field")
self.current = next
return self.current
def getPrev(self):
"""Returns the previous node in the list, which then becomes the
current node."""
prev = self.current.getPrev()
if prev == self.front or (prev == None and prev == self.front):
raise ListException("Already at the beginning of the list")
elif prev == None:
raise ListException("getPrev(): Null prev field.")
self.current = self.current.getPrev()
return self.current
# EOF