The implementation of the Dijkstra's Algorithm:
def dijkstra(g, s):
from priority_queue import PriorityQueue, less_than
result = []
class Record:
def __init__(self, v, parent = -1, cost = WEIGHT_LIMIT):
self.vertex = v
self.parent = parent
self.cost = cost
def __lt__(self, other):
return self.cost < other.cost
def get_key(self):
return self.vertex
key = property(get_key)
n = len(g)
sequence = [Record(i) for i in range(n)]
sequence[s].cost = 0
pq = PriorityQueue(less_than, sequence)
while pq:
u = pq.pop()
for v in g.adj(u.vertex):
nc = u.cost + v.weight
try:
if nc < pq[v.vertex].cost:
pq.modify(v.vertex, Record(v.vertex, u.vertex, nc))
except IndexError:
pass
result.append(u)
return result
def print_shortest_path_tree(result, s):
def get_shortest_path(dic, v, cache):
ret = cache[v]
if len(ret) == 0:
r = dic[v]
if r.parent != -1:
pret = get_shortest_path(dic, r.parent, cache)
ret = "%s->%s" % (pret, v)
else:
ret = str(v)
cache[v] = ret
return ret
n = len(result)
dic = {result[i].vertex: result[i] for i in range(n)}
cache = ["" for i in range(n)]
i = n - 1
while i >= 0:
get_shortest_path(dic, i, cache)
i -= 1
for i in range(n):
if i != s:
print("%s: %s" % (cache[i], dic[i].cost))
The class WeightedGraph:
class WeightedGraph:
class Edge:
def __init__(self, v, w):
self.vertex = v
self.weight = w
def __repr__(self):
return "%s(%s)" % (self.vertex, self.weight)
def __init__(self, v):
self.vertices = [None for i in range(v)]
self.empty_list = []
def add_edge(self, u, v, w = 1):
l = self.vertices[u]
e = WeightedGraph.Edge(v, w)
if l != None:
l.append(e)
else:
l = [e]
self.vertices[u] = l
def __bool__(self):
return len(self.vertices) > 0
__nonzero__ = __bool__
def __len__(self):
return len(self.vertices)
def number_of_edges(self):
e = 0
for l in self.vertices:
e += len(l)
return e
def adj(self, v):
l = self.vertices[v]
if l == None:
l = self.empty_list
return l
def __repr__(self):
ret = ""
v = len(self.vertices)
i = 0
while i < v:
if self.vertices[i]:
if len(ret) > 0:
ret += "\n"
ret += ("%s: %s" % (i, self.vertices[i]))
i += 1
return ret
The class PriorityQueue:
from __future__ import print_function
import copy
def less_than(a, b): return a < b
def big_than(a, b): return a > b
def get_key(v):
ret = None
if isinstance(v, int) or isinstance(v, float) or isinstance(v, str):
ret = v
elif isinstance(v, list) or isinstance(v, tuple):
ret = v[0]
else:
ret = v.key
return ret
def sink(sequence, i, comparator, positions):
n = len(sequence)
if i >= 0 and i < n:
while True:
c = (i + 1) * 2
r = i
if c < n and comparator(sequence[c], sequence[r]):
r = c
c -= 1
if c < n and comparator(sequence[c], sequence[r]):
r = c
if r != i:
if positions != None:
positions[get_key(sequence[i])] = r
positions[get_key(sequence[r])] = i
sequence[i], sequence[r] = sequence[r], sequence[i]
i = r
else:
break
def rise(sequence, i, comparator, positions):
n = len(sequence)
if i >= 0 and i < n:
while i != 0:
p = (i - 1) // 2
if comparator(sequence[i], sequence[p]):
if positions != None:
positions[get_key(sequence[i])] = p
positions[get_key(sequence[p])] = i
sequence[i], sequence[p] = sequence[p], sequence[i]
i = p
else:
break
def make_heap(sequence, comparator):
n = len(sequence)
i = 1
while i < n:
rise(sequence, i, comparator, None)
i += 1
return sequence
class PriorityQueue:
def __init__(self, comparator, sequence):
self.comparator = comparator
self.elements = make_heap(sequence, self.comparator)
self.positions = {get_key(self.elements[i]): i for i in range(len(self.elements))}
def __len__(self):
return len(self.elements)
def __bool__(self):
return len(self.elements) > 0
__nonzero__ = __bool__
def __repr__(self):
return str(self.elements)
def top(self):
if self.elements:
return self.elements[0]
raise IndexError("The priority queue is empty")
def pop(self):
ret = None
n = len(self.elements)
if n > 0:
ret = self.elements[0]
if n > 1:
self.elements[0] = self.elements[n - 1]
self.elements.pop(-1)
sink(self.elements, 0, self.comparator, self.positions)
else:
self.elements = []
else:
raise IndexError("The priority queue is empty")
return ret
def modify(self, key, value):
i = self.positions.get(key)
if i != None:
old_value = self.elements[i]
self.elements[i] = value
del self.positions[key]
self.positions[get_key(value)] = i
if self.comparator(old_value, value):
sink(self.elements, i, self.comparator, self.positions)
else:
rise(self.elements, i, self.comparator, self.positions)
else:
raise IndexError("The specific element %s is not in the priority queue" % key)
def __getitem__(self, key):
i = self.positions.get(key)
if i != None:
return self.elements[i]
else:
raise IndexError("The specific element %s is not in the priority queue" % key)
if __name__ == "__main__":
sequence = [7, 2, 5, 8, 1, 0, 3, 9]
pq = PriorityQueue(less_than, copy.copy(sequence))
result = []
while pq:
e = pq.pop()
result.append(e)
assert result == sorted(sequence)
pq = PriorityQueue(less_than, copy.copy(sequence))
pq.modify(0, -1)
print(pq)
pq.modify(9, -2)
print(pq)
pq.modify(-2, 10)
print(pq)
pq.modify(-1, 20)
print(pq)