Skip to content

Commit e584c0a

Browse files
committed
source code for chapter 9
1 parent ef33598 commit e584c0a

File tree

6 files changed

+384
-0
lines changed

6 files changed

+384
-0
lines changed

ch09/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__all__ = ['adaptable_heap_priority_queue', 'heap_priority_queue', 'sorted_priority_queue', 'unsorted_priority_queue']
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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 .heap_priority_queue import HeapPriorityQueue
23+
24+
class AdaptableHeapPriorityQueue(HeapPriorityQueue):
25+
"""A locator-based priority queue implemented with a binary heap."""
26+
27+
#------------------------------ nested Locator class ------------------------------
28+
class Locator(HeapPriorityQueue._Item):
29+
"""Token for locating an entry of the priority queue."""
30+
__slots__ = '_index' # add index as additional field
31+
32+
def __init__(self, k, v, j):
33+
super().__init__(k,v)
34+
self._index = j
35+
36+
#------------------------------ nonpublic behaviors ------------------------------
37+
# override swap to record new indices
38+
def _swap(self, i, j):
39+
super()._swap(i,j) # perform the swap
40+
self._data[i]._index = i # reset locator index (post-swap)
41+
self._data[j]._index = j # reset locator index (post-swap)
42+
43+
def _bubble(self, j):
44+
if j > 0 and self._data[j] < self._data[self._parent(j)]:
45+
self._upheap(j)
46+
else:
47+
self._downheap(j)
48+
49+
#------------------------------ public behaviors ------------------------------
50+
def add(self, key, value):
51+
"""Add a key-value pair."""
52+
token = self.Locator(key, value, len(self._data)) # initiaize locator index
53+
self._data.append(token)
54+
self._upheap(len(self._data) - 1)
55+
return token
56+
57+
def update(self, loc, newkey, newval):
58+
"""Update the key and value for the entry identified by Locator loc."""
59+
j = loc._index
60+
if not (0 <= j < len(self) and self._data[j] is loc):
61+
raise ValueError('Invalid locator')
62+
loc._key = newkey
63+
loc._value = newval
64+
self._bubble(j)
65+
66+
def remove(self, loc):
67+
"""Remove and return the (k,v) pair identified by Locator loc."""
68+
j = loc._index
69+
if not (0 <= j < len(self) and self._data[j] is loc):
70+
raise ValueError('Invalid locator')
71+
if j == len(self) - 1: # item at last position
72+
self._data.pop() # just remove it
73+
else:
74+
self._swap(j, len(self)-1) # swap item to the last position
75+
self._data.pop() # remove it from the list
76+
self._bubble(j) # fix item displaced by the swap
77+
return (loc._key, loc._value)

ch09/heap_priority_queue.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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 .priority_queue_base import PriorityQueueBase
23+
from ..exceptions import Empty
24+
25+
class HeapPriorityQueue(PriorityQueueBase): # base class defines _Item
26+
"""A min-oriented priority queue implemented with a binary heap."""
27+
28+
#------------------------------ nonpublic behaviors ------------------------------
29+
def _parent(self, j):
30+
return (j-1) // 2
31+
32+
def _left(self, j):
33+
return 2*j + 1
34+
35+
def _right(self, j):
36+
return 2*j + 2
37+
38+
def _has_left(self, j):
39+
return self._left(j) < len(self._data) # index beyond end of list?
40+
41+
def _has_right(self, j):
42+
return self._right(j) < len(self._data) # index beyond end of list?
43+
44+
def _swap(self, i, j):
45+
"""Swap the elements at indices i and j of array."""
46+
self._data[i], self._data[j] = self._data[j], self._data[i]
47+
48+
def _upheap(self, j):
49+
parent = self._parent(j)
50+
if j > 0 and self._data[j] < self._data[parent]:
51+
self._swap(j, parent)
52+
self._upheap(parent) # recur at position of parent
53+
54+
def _downheap(self, j):
55+
if self._has_left(j):
56+
left = self._left(j)
57+
small_child = left # although right may be smaller
58+
if self._has_right(j):
59+
right = self._right(j)
60+
if self._data[right] < self._data[left]:
61+
small_child = right
62+
if self._data[small_child] < self._data[j]:
63+
self._swap(j, small_child)
64+
self._downheap(small_child) # recur at position of small child
65+
66+
#------------------------------ public behaviors ------------------------------
67+
def __init__(self):
68+
"""Create a new empty Priority Queue."""
69+
self._data = []
70+
71+
def __len__(self):
72+
"""Return the number of items in the priority queue."""
73+
return len(self._data)
74+
75+
def add(self, key, value):
76+
"""Add a key-value pair to the priority queue."""
77+
self._data.append(self._Item(key, value))
78+
self._upheap(len(self._data) - 1) # upheap newly added position
79+
80+
def min(self):
81+
"""Return but do not remove (k,v) tuple with minimum key.
82+
83+
Raise Empty exception if empty.
84+
"""
85+
if self.is_empty():
86+
raise Empty('Priority queue is empty.')
87+
item = self._data[0]
88+
return (item._key, item._value)
89+
90+
def remove_min(self):
91+
"""Remove and return (k,v) tuple with minimum key.
92+
93+
Raise Empty exception if empty.
94+
"""
95+
if self.is_empty():
96+
raise Empty('Priority queue is empty.')
97+
self._swap(0, len(self._data) - 1) # put minimum item at the end
98+
item = self._data.pop() # and remove it from the list;
99+
self._downheap(0) # then fix new root
100+
return (item._key, item._value)

ch09/priority_queue_base.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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 PriorityQueueBase:
25+
"""Abstract base class for a priority queue."""
26+
27+
#------------------------------ nested _Item class ------------------------------
28+
class _Item:
29+
"""Lightweight composite to store priority queue items."""
30+
__slots__ = '_key', '_value'
31+
32+
def __init__(self, k, v):
33+
self._key = k
34+
self._value = v
35+
36+
def __lt__(self, other):
37+
return self._key < other._key # compare items based on their keys
38+
39+
def __repr__(self):
40+
return '({0},{1})'.format(self._key, self._value)
41+
42+
#------------------------------ public behaviors ------------------------------
43+
def is_empty(self): # concrete method assuming abstract len
44+
"""Return True if the priority queue is empty."""
45+
return len(self) == 0
46+
47+
def __len__(self):
48+
"""Return the number of items in the priority queue."""
49+
raise NotImplementedError('must be implemented by subclass')
50+
51+
def add(self, key, value):
52+
"""Add a key-value pair."""
53+
raise NotImplementedError('must be implemented by subclass')
54+
55+
def min(self):
56+
"""Return but do not remove (k,v) tuple with minimum key.
57+
58+
Raise Empty exception if empty.
59+
"""
60+
raise NotImplementedError('must be implemented by subclass')
61+
62+
def remove_min(self):
63+
"""Remove and return (k,v) tuple with minimum key.
64+
65+
Raise Empty exception if empty.
66+
"""
67+
raise NotImplementedError('must be implemented by subclass')

ch09/sorted_priority_queue.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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 .priority_queue_base import PriorityQueueBase
23+
from ..ch07.positional_list import PositionalList
24+
from ..exceptions import Empty
25+
26+
class SortedPriorityQueue(PriorityQueueBase): # base class defines _Item
27+
"""A min-oriented priority queue implemented with a sorted list."""
28+
29+
#------------------------------ public behaviors ------------------------------
30+
def __init__(self):
31+
"""Create a new empty Priority Queue."""
32+
self._data = PositionalList()
33+
34+
def __len__(self):
35+
"""Return the number of items in the priority queue."""
36+
return len(self._data)
37+
38+
def add(self, key, value):
39+
"""Add a key-value pair."""
40+
newest = self._Item(key, value) # make new item instance
41+
walk = self._data.last() # walk backward looking for smaller key
42+
while walk is not None and newest < walk.element():
43+
walk = self._data.before(walk)
44+
if walk is None:
45+
self._data.add_first(newest) # new key is smallest
46+
else:
47+
self._data.add_after(walk, newest) # newest goes after walk
48+
49+
def min(self):
50+
"""Return but do not remove (k,v) tuple with minimum key.
51+
52+
Raise Empty exception if empty.
53+
"""
54+
if self.is_empty():
55+
raise Empty('Priority queue is empty.')
56+
p = self._data.first()
57+
item = p.element()
58+
return (item._key, item._value)
59+
60+
def remove_min(self):
61+
"""Remove and return (k,v) tuple with minimum key.
62+
63+
Raise Empty exception if empty.
64+
"""
65+
if self.is_empty():
66+
raise Empty('Priority queue is empty.')
67+
item = self._data.delete(self._data.first())
68+
return (item._key, item._value)

ch09/unsorted_priority_queue.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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 .priority_queue_base import PriorityQueueBase
23+
from ..ch07.positional_list import PositionalList
24+
from ..exceptions import Empty
25+
26+
class UnsortedPriorityQueue(PriorityQueueBase): # base class defines _Item
27+
"""A min-oriented priority queue implemented with an unsorted list."""
28+
29+
#----------------------------- nonpublic behavior -----------------------------
30+
def _find_min(self):
31+
"""Return Position of item with minimum key."""
32+
if self.is_empty(): # is_empty inherited from base class
33+
raise Empty('Priority queue is empty')
34+
small = self._data.first()
35+
walk = self._data.after(small)
36+
while walk is not None:
37+
if walk.element() < small.element():
38+
small = walk
39+
walk = self._data.after(walk)
40+
return small
41+
42+
#------------------------------ public behaviors ------------------------------
43+
def __init__(self):
44+
"""Create a new empty Priority Queue."""
45+
self._data = PositionalList()
46+
47+
def __len__(self):
48+
"""Return the number of items in the priority queue."""
49+
return len(self._data)
50+
51+
def add(self, key, value):
52+
"""Add a key-value pair."""
53+
self._data.add_last(self._Item(key, value))
54+
55+
def min(self):
56+
"""Return but do not remove (k,v) tuple with minimum key.
57+
58+
Raise Empty exception if empty.
59+
"""
60+
p = self._find_min()
61+
item = p.element()
62+
return (item._key, item._value)
63+
64+
def remove_min(self):
65+
"""Remove and return (k,v) tuple with minimum key.
66+
67+
Raise Empty exception if empty.
68+
"""
69+
p = self._find_min()
70+
item = self._data.delete(p)
71+
return (item._key, item._value)

0 commit comments

Comments
 (0)