-
Notifications
You must be signed in to change notification settings - Fork 0
/
positional_list.py
173 lines (152 loc) · 5.28 KB
/
positional_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
from doubly_linked_list import _DoublyLinkedBase
class PositionalList(_DoublyLinkedBase):
"""
A sequential container of elements allowing positional access
"""
#-------------------Nested Position class-----------------------
class Position:
"""
An abstraction representing the location of a single element
"""
def __init__(self, container, node):
"""
Constructor - should not be onvoked by user
"""
self._container = container
self._node = node
def element(self):
"""
returns: the element stored at this position
"""
return self._node._element
def __eq__(self, other):
"""
returns: True if other is a Position representing the same location
"""
return type(self) is type(other) and self._node is other._node
def __ne__(self, other):
"""
returns: True if other does not represent the same location
"""
return not(self == other)
#-----------------------Utility methods-------------------------------
def _validate(self, p):
"""
return: position p's node, or raises an error if p is invalid
"""
if not isinstance(p, self.Position):
raise TypeError('p is not a Position type')
if p._container is not self:
raise ValueError('p does not belong to this container')
if p._node._next is None: # _next set to None is default for defunct nodes
raise ValueError('p is no longer valid')
return p._node
def _make_position(self, node):
"""
returns: a Position instance for the given node
"""
if node is self._head or node is self._tail:
return None
else:
return self.Position(self, node)
#------------------------------Accessors------------------------------------
def first(self):
"""
returns: the first Position in the list or None if empty
"""
return self._make_position(self._head._next)
def last(self):
"""
returns: the last Position in the list or None if empty
"""
return self._make_position(self._tail._prev)
def before(self, p):
"""
returns: the Position before Position p or None if p i first
"""
node = self._validate(p)
return self._make_position(node._prev)
def after(self, p):
"""
returns: the Position after Position p or None if p is last
"""
node = self._validate(p)
return self._make_position(node._next)
def __iter__(self):
"""
Generates a forward iteration of the elements in the list
"""
cursor = self.first()
while cursor is not None:
yield cursor.element()
cursor = self.after(cursor)
#-------------------------Mutators----------------------------
def _insert_between(self, e, predecessor, successor):
"""
Adds an element between two existing nodes
returns: a new Position
"""
node = super()._insert_between(e, predecessor, successor)
return self._make_position(node)
def add_first(self, e):
"""
Adds an element to the front of the list
returns: a new Position
"""
node = super()._insert_between(e, self._head, self._head._next)
return self._make_position(node)
def add_last(self, e):
"""
Adds an element to the end of the list
returns: a new Position
"""
node = super()._insert_between(e, self._tail._prev, self._tail)
return self._make_position(node)
def add_before(self, p, e):
"""
Adds an element after a given Position
returns: a new Postion
"""
original = self._validate(p)
return self._insert_between(e, original._prev, original)
def add_after(self, p, e):
"""
Adds an element after a given Position
returns: a new Postion
"""
original = self._validate(p)
return self._insert_between(e, original, original._next)
def delete(self, p):
"""
Removes the Position p
returns: p's element
"""
node = self._validate(p)
return self._delete_node(node)
def replace(self, p, e):
"""
Replaces the element at Position p with e
returns: the element formerly at p
"""
original = self._validate(p)
old_value = original._element
original._element = e
return old_value
def sort(self):
"""
Sorts the items in the PositionalList into non-decreasing order
Using insertion sort
"""
if self._size > 1:
index = self.first()
while index != self.last():
j = self.after(index)
value = j.element()
if value > index.element():
index = j
else:
i = index
while i != self.first() and self.before(i).element() > value:
i = self.before(i)
self.delete(j)
self.add_before(i, value)