Skip to content

Commit acabb51

Browse files
committed
source code for chapter 7
1 parent 12e5672 commit acabb51

File tree

10 files changed

+729
-0
lines changed

10 files changed

+729
-0
lines changed

ch07/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__all__ = ['circular_queue', 'favorites_list', 'favorites_list_mtf', 'insertion_sort_positional',
2+
'linked_deque', 'linked_queue', 'linked_stack', 'positional_list']

ch07/circular_queue.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Copyright 2013, Michael H. Goldwasser
2+
#
3+
# Developed for use with the book:
4+
#
5+
# Data Structures and Algorithms in Python
6+
# Michael T. Goodrich, Roberto Tamassia, and Michael H. Goldwasser
7+
# John Wiley & Sons, 2013
8+
#
9+
# This program is free software: you can redistribute it and/or modify
10+
# it under the terms of the GNU General Public License as published by
11+
# the Free Software Foundation, either version 3 of the License, or
12+
# (at your option) any later version.
13+
#
14+
# This program is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
# GNU General Public License for more details.
18+
#
19+
# You should have received a copy of the GNU General Public License
20+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
22+
from ..exceptions import Empty
23+
24+
class CircularQueue:
25+
"""Queue implementation using circularly linked list for storage."""
26+
27+
#---------------------------------------------------------------------------------
28+
# nested _Node class
29+
class _Node:
30+
"""Lightweight, nonpublic class for storing a singly linked node."""
31+
__slots__ = '_element', '_next' # streamline memory usage
32+
33+
def __init__(self, element, next):
34+
self._element = element
35+
self._next = next
36+
37+
# end of _Node class
38+
#---------------------------------------------------------------------------------
39+
40+
def __init__(self):
41+
"""Create an empty queue."""
42+
self._tail = None # will represent tail of queue
43+
self._size = 0 # number of queue elements
44+
45+
def __len__(self):
46+
"""Return the number of elements in the queue."""
47+
return self._size
48+
49+
def is_empty(self):
50+
"""Return True if the queue is empty."""
51+
return self._size == 0
52+
53+
def first(self):
54+
"""Return (but do not remove) the element at the front of the queue.
55+
56+
Raise Empty exception if the queue is empty.
57+
"""
58+
if self.is_empty():
59+
raise Empty('Queue is empty')
60+
head = self._tail._next
61+
return head._element
62+
63+
def dequeue(self):
64+
"""Remove and return the first element of the queue (i.e., FIFO).
65+
66+
Raise Empty exception if the queue is empty.
67+
"""
68+
if self.is_empty():
69+
raise Empty('Queue is empty')
70+
oldhead = self._tail._next
71+
if self._size == 1: # removing only element
72+
self._tail = None # queue becomes empty
73+
else:
74+
self._tail._next = oldhead._next # bypass the old head
75+
self._size -= 1
76+
return oldhead._element
77+
78+
def enqueue(self, e):
79+
"""Add an element to the back of queue."""
80+
newest = self._Node(e, None) # node will be new tail node
81+
if self.is_empty():
82+
newest._next = newest # initialize circularly
83+
else:
84+
newest._next = self._tail._next # new node points to head
85+
self._tail._next = newest # old tail points to new node
86+
self._tail = newest # new node becomes the tail
87+
self._size += 1
88+
89+
def rotate(self):
90+
"""Rotate front element to the back of the queue."""
91+
if self._size > 0:
92+
self._tail = self._tail._next # old head becomes new tail

ch07/doubly_linked_base.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright 2013, Michael H. Goldwasser
2+
#
3+
# Developed for use with the book:
4+
#
5+
# Data Structures and Algorithms in Python
6+
# Michael T. Goodrich, Roberto Tamassia, and Michael H. Goldwasser
7+
# John Wiley & Sons, 2013
8+
#
9+
# This program is free software: you can redistribute it and/or modify
10+
# it under the terms of the GNU General Public License as published by
11+
# the Free Software Foundation, either version 3 of the License, or
12+
# (at your option) any later version.
13+
#
14+
# This program is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
# GNU General Public License for more details.
18+
#
19+
# You should have received a copy of the GNU General Public License
20+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
22+
class _DoublyLinkedBase:
23+
"""A base class providing a doubly linked list representation."""
24+
25+
#-------------------------- nested _Node class --------------------------
26+
# nested _Node class
27+
class _Node:
28+
"""Lightweight, nonpublic class for storing a doubly linked node."""
29+
__slots__ = '_element', '_prev', '_next' # streamline memory
30+
31+
def __init__(self, element, prev, next): # initialize node's fields
32+
self._element = element # user's element
33+
self._prev = prev # previous node reference
34+
self._next = next # next node reference
35+
36+
#-------------------------- list constructor --------------------------
37+
38+
def __init__(self):
39+
"""Create an empty list."""
40+
self._header = self._Node(None, None, None)
41+
self._trailer = self._Node(None, None, None)
42+
self._header._next = self._trailer # trailer is after header
43+
self._trailer._prev = self._header # header is before trailer
44+
self._size = 0 # number of elements
45+
46+
#-------------------------- public accessors --------------------------
47+
48+
def __len__(self):
49+
"""Return the number of elements in the list."""
50+
return self._size
51+
52+
def is_empty(self):
53+
"""Return True if list is empty."""
54+
return self._size == 0
55+
56+
#-------------------------- nonpublic utilities --------------------------
57+
58+
def _insert_between(self, e, predecessor, successor):
59+
"""Add element e between two existing nodes and return new node."""
60+
newest = self._Node(e, predecessor, successor) # linked to neighbors
61+
predecessor._next = newest
62+
successor._prev = newest
63+
self._size += 1
64+
return newest
65+
66+
def _delete_node(self, node):
67+
"""Delete nonsentinel node from the list and return its element."""
68+
predecessor = node._prev
69+
successor = node._next
70+
predecessor._next = successor
71+
successor._prev = predecessor
72+
self._size -= 1
73+
element = node._element # record deleted element
74+
node._prev = node._next = node._element = None # deprecate node
75+
return element # return deleted element

ch07/favorites_list.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Copyright 2013, Michael H. Goldwasser
2+
#
3+
# Developed for use with the book:
4+
#
5+
# Data Structures and Algorithms in Python
6+
# Michael T. Goodrich, Roberto Tamassia, and Michael H. Goldwasser
7+
# John Wiley & Sons, 2013
8+
#
9+
# This program is free software: you can redistribute it and/or modify
10+
# it under the terms of the GNU General Public License as published by
11+
# the Free Software Foundation, either version 3 of the License, or
12+
# (at your option) any later version.
13+
#
14+
# This program is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
# GNU General Public License for more details.
18+
#
19+
# You should have received a copy of the GNU General Public License
20+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
22+
from .positional_list import PositionalList
23+
24+
class FavoritesList:
25+
"""List of elements ordered from most frequently accessed to least."""
26+
27+
#------------------------------ nested _Item class ------------------------------
28+
class _Item:
29+
__slots__ = '_value', '_count' # streamline memory usage
30+
def __init__(self, e):
31+
self._value = e # the user's element
32+
self._count = 0 # access count initially zero
33+
34+
#------------------------------- nonpublic utilities -------------------------------
35+
def _find_position(self, e):
36+
"""Search for element e and return its Position (or None if not found)."""
37+
walk = self._data.first()
38+
while walk is not None and walk.element()._value != e:
39+
walk = self._data.after(walk)
40+
return walk
41+
42+
def _move_up(self, p):
43+
"""Move item at Position p earlier in the list based on access count."""
44+
if p != self._data.first(): # consider moving...
45+
cnt = p.element()._count
46+
walk = self._data.before(p)
47+
if cnt > walk.element()._count: # must shift forward
48+
while (walk != self._data.first() and
49+
cnt > self._data.before(walk).element()._count):
50+
walk = self._data.before(walk)
51+
self._data.add_before(walk, self._data.delete(p)) # delete/reinsert
52+
53+
#------------------------------- public methods -------------------------------
54+
def __init__(self):
55+
"""Create an empty list of favorites."""
56+
self._data = PositionalList() # will be list of _Item instances
57+
58+
def __len__(self):
59+
"""Return number of entries on favorites list."""
60+
return len(self._data)
61+
62+
def is_empty(self):
63+
"""Return True if list is empty."""
64+
return len(self._data) == 0
65+
66+
def access(self, e):
67+
"""Access element e, thereby increasing its access count."""
68+
p = self._find_position(e) # try to locate existing element
69+
if p is None:
70+
p = self._data.add_last(self._Item(e)) # if new, place at end
71+
p.element()._count += 1 # always increment count
72+
self._move_up(p) # consider moving forward
73+
74+
def remove(self, e):
75+
"""Remove element e from the list of favorites."""
76+
p = self._find_position(e) # try to locate existing element
77+
if p is not None:
78+
self._data.delete(p) # delete, if found
79+
80+
def top(self, k):
81+
"""Generate sequence of top k elements in terms of access count."""
82+
if not 1 <= k <= len(self):
83+
raise ValueError('Illegal value for k')
84+
walk = self._data.first()
85+
for j in range(k):
86+
item = walk.element() # element of list is _Item
87+
yield item._value # report user's element
88+
walk = self._data.after(walk)
89+
90+
def __repr__(self):
91+
"""Create string representation of the favorites list."""
92+
return ', '.join('({0}:{1})'.format(i._value, i._count) for i in self._data)
93+
94+
if __name__ == '__main__':
95+
fav = FavoritesList()
96+
for c in 'hello. this is a test of mtf': # well, not the mtf part...
97+
fav.access(c)
98+
k = min(5, len(fav))
99+
print('Top {0}) {1:25} {2}'.format(k, [x for x in fav.top(k)], fav))

ch07/favorites_list_mtf.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright 2013, Michael H. Goldwasser
2+
#
3+
# Developed for use with the book:
4+
#
5+
# Data Structures and Algorithms in Python
6+
# Michael T. Goodrich, Roberto Tamassia, and Michael H. Goldwasser
7+
# John Wiley & Sons, 2013
8+
#
9+
# This program is free software: you can redistribute it and/or modify
10+
# it under the terms of the GNU General Public License as published by
11+
# the Free Software Foundation, either version 3 of the License, or
12+
# (at your option) any later version.
13+
#
14+
# This program is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
# GNU General Public License for more details.
18+
#
19+
# You should have received a copy of the GNU General Public License
20+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
22+
from .favorites_list import FavoritesList
23+
from .positional_list import PositionalList
24+
25+
class FavoritesListMTF(FavoritesList):
26+
"""List of elements ordered with move-to-front heuristic."""
27+
28+
# we override _move_up to provide move-to-front semantics
29+
def _move_up(self, p):
30+
"""Move accessed item at Position p to front of list."""
31+
if p != self._data.first():
32+
self._data.add_first(self._data.delete(p)) # delete/reinsert
33+
34+
# we override top because list is no longer sorted
35+
def top(self, k):
36+
"""Generate sequence of top k elements in terms of access count."""
37+
if not 1 <= k <= len(self):
38+
raise ValueError('Illegal value for k')
39+
40+
# we begin by making a copy of the original list
41+
temp = PositionalList()
42+
for item in self._data: # positional lists support iteration
43+
temp.add_last(item)
44+
45+
# we repeatedly find, report, and remove element with largest count
46+
for j in range(k):
47+
# find and report next highest from temp
48+
highPos = temp.first()
49+
walk = temp.after(highPos)
50+
while walk is not None:
51+
if walk.element()._count > highPos.element()._count:
52+
highPos = walk
53+
walk = temp.after(walk)
54+
# we have found the element with highest count
55+
yield highPos.element()._value # report element to user
56+
temp.delete(highPos) # remove from temp list
57+
58+
if __name__ == '__main__':
59+
fav = FavoritesListMTF()
60+
for c in 'hello. this is a test of mtf':
61+
fav.access(c)
62+
k = min(5, len(fav))
63+
print('Top {0}) {1:25} {2}'.format(k, [x for x in fav.top(k)], fav))

ch07/insertion_sort_positional.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright 2013, Michael H. Goldwasser
2+
#
3+
# Developed for use with the book:
4+
#
5+
# Data Structures and Algorithms in Python
6+
# Michael T. Goodrich, Roberto Tamassia, and Michael H. Goldwasser
7+
# John Wiley & Sons, 2013
8+
#
9+
# This program is free software: you can redistribute it and/or modify
10+
# it under the terms of the GNU General Public License as published by
11+
# the Free Software Foundation, either version 3 of the License, or
12+
# (at your option) any later version.
13+
#
14+
# This program is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
# GNU General Public License for more details.
18+
#
19+
# You should have received a copy of the GNU General Public License
20+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
22+
def insertion_sort(L):
23+
"""Sort PositionalList of comparable elements into nondecreasing order."""
24+
if len(L) > 1: # otherwise, no need to sort it
25+
marker = L.first()
26+
while marker != L.last():
27+
pivot = L.after(marker) # next item to place
28+
value = pivot.element()
29+
if value > marker.element(): # pivot is already sorted
30+
marker = pivot # pivot becomes new marker
31+
else: # must relocate pivot
32+
walk = marker # find leftmost item greater than value
33+
while walk != L.first() and L.before(walk).element() > value:
34+
walk = L.before(walk)
35+
L.delete(pivot)
36+
L.add_before(walk, value) # reinsert value before walk

0 commit comments

Comments
 (0)