Skip to content

Commit 8b41bfd

Browse files
committed
graph and priority queue
1 parent c49201f commit 8b41bfd

File tree

2 files changed

+383
-0
lines changed

2 files changed

+383
-0
lines changed

graph.py

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
from collections import deque
2+
3+
class Edge:
4+
def __init__(self, src, tgt):
5+
self.source = src
6+
self.target = tgt
7+
8+
def raw(self):
9+
return (self.source, self.target)
10+
11+
def flip(self):
12+
return Edge(self.target, self.source)
13+
14+
def __repr__(self):
15+
return repr(self.raw())
16+
17+
def __hash__(self):
18+
return hash(self.raw())
19+
20+
def __eq__(self, other):
21+
return self.raw() == other.raw()
22+
23+
################################################################################
24+
# Directed Adjacency List
25+
################################################################################
26+
27+
class DirectedAdjList:
28+
def __init__(self, edge_list=[], vertex_label=None,
29+
vertex_text=None,
30+
edge_label=None, edge_color=None):
31+
self.out = {}
32+
self.ins = {}
33+
self.vertex_label = vertex_label
34+
if vertex_text:
35+
self.vertex_text = vertex_text
36+
elif vertex_label:
37+
self.vertex_text = self.vertex_label
38+
else:
39+
self.vertex_text = lambda v: str(v)
40+
self.edge_label = edge_label
41+
self.edge_color = edge_color
42+
self.edge_set = set()
43+
for e in edge_list:
44+
if isinstance(e, Edge):
45+
self.add_edge(e.source, e.target)
46+
else:
47+
self.add_edge(e[0], e[1])
48+
49+
def edges(self):
50+
return self.edge_set
51+
52+
def vertices(self):
53+
#return range(0, self.num_vertices())
54+
return self.out.keys()
55+
56+
def num_vertices(self):
57+
return len(self.out)
58+
59+
def adjacent(self, u):
60+
self.add_vertex(u)
61+
return self.out[u]
62+
63+
def add_vertex(self, u):
64+
if u not in self.out:
65+
self.out[u] = []
66+
self.ins[u] = []
67+
68+
def add_edge(self, u, v):
69+
self.add_vertex(u)
70+
self.add_vertex(v)
71+
self.out[u].append(v)
72+
self.ins[v].append(u)
73+
edge = Edge(u,v)
74+
self.edge_set.add(edge)
75+
return edge
76+
77+
def out_edges(self, u):
78+
for v in self.out[u]:
79+
yield Edge(u, v)
80+
81+
def in_edges(self, v):
82+
for u in self.ins[v]:
83+
yield Edge(u, v)
84+
85+
def has_edge(self, u, v):
86+
return Edge(u,v) in self.edge_set
87+
88+
def remove_edge(self, u, v):
89+
self.out[u].remove(v)
90+
self.ins[v].remove(u)
91+
self.edge_set.remove(Edge(u,v))
92+
93+
def name(self, u):
94+
if self.vertex_label:
95+
return self.vertex_label(u)
96+
else:
97+
return str(u)
98+
99+
def named_edge(self, e):
100+
return (self.name(e.source), self.name(e.target))
101+
102+
def label(self, e):
103+
if self.edge_label:
104+
return self.edge_label(e)
105+
else:
106+
return ""
107+
108+
def color(self, e):
109+
if self.edge_color:
110+
return self.edge_color(e)
111+
else:
112+
return "black"
113+
114+
def show(self, engine='neato'):
115+
from graphviz import Digraph
116+
dot = Digraph(engine=engine)
117+
for u in self.vertices():
118+
dot.node(self.name(u), self.vertex_text(u))
119+
for e in self.edges():
120+
dot.edge(self.name(e.source), self.name(e.target), label=self.label(e),
121+
color=self.color(e), len='1.5')
122+
return dot
123+
124+
class UEdge(Edge):
125+
def raw(self):
126+
return set([self.source, self.target])
127+
128+
def __hash__(self):
129+
return hash(self.source) + hash(self.target)
130+
131+
def __eq__(self, other):
132+
return self.raw() == other.raw()
133+
134+
135+
################################################################################
136+
# Undirected Adjacency List
137+
################################################################################
138+
139+
class UndirectedAdjList(DirectedAdjList):
140+
141+
def add_edge(self, u, v):
142+
self.add_vertex(u)
143+
self.add_vertex(v)
144+
self.out[u].append(v)
145+
self.out[v].append(u)
146+
edge = UEdge(u,v)
147+
self.edge_set.add(edge)
148+
return edge
149+
150+
def remove_edge(self, u, v):
151+
self.out[u] = [w for w in self.out[u] if w != v]
152+
self.out[v] = [w for w in self.out[v] if w != u]
153+
self.edge_set.remove(UEdge(u,v))
154+
155+
def out_edges(self, u):
156+
for v in self.out[u]:
157+
yield UEdge(u, v)
158+
159+
def in_edges(self, v):
160+
for u in self.out[v]:
161+
yield UEdge(u,v)
162+
163+
def has_edge(self, u, v):
164+
return UEdge(u,v) in self.edge_set
165+
166+
def remove_edge(self, u, v):
167+
self.out[u] = [w for w in self.out[u] if w != v]
168+
self.edge_set.remove(UEdge(u,v))
169+
170+
def show(self):
171+
from graphviz import Graph
172+
dot = Graph(engine='neato')
173+
for u in self.vertices():
174+
dot.node(self.name(u))
175+
for e in self.edges():
176+
dot.edge(self.name(e.source), self.name(e.target), len='1.5')
177+
return dot
178+
179+
180+
################################################################################
181+
# Topological Sort
182+
################################################################################
183+
184+
def topological_sort(G: DirectedAdjList) -> DirectedAdjList:
185+
in_degree = {u: 0 for u in G.vertices()}
186+
for e in G.edges():
187+
in_degree[e.target] += 1
188+
queue = deque()
189+
for u in G.vertices():
190+
if in_degree[u] == 0:
191+
queue.append(u)
192+
topo = []
193+
while queue:
194+
u = queue.pop()
195+
topo.append(u)
196+
for v in G.adjacent(u):
197+
in_degree[v] -= 1
198+
if in_degree[v] == 0:
199+
queue.append(v)
200+
return topo
201+
202+
def transpose(G: DirectedAdjList) -> DirectedAdjList:
203+
G_t = DirectedAdjList()
204+
for e in G.edges():
205+
G_t.add_edge(e.target, e.source)
206+
return G_t

priority_queue.py

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
def swap(A, i, j):
2+
tmp = A[i]
3+
A[i] = A[j]
4+
A[j] = tmp
5+
6+
def less(x, y):
7+
return x < y
8+
9+
def less_key(x, y):
10+
return x.key < y.key
11+
12+
def update_position(obj, pos):
13+
obj.position = pos
14+
15+
def get_position(obj):
16+
return obj.position
17+
18+
def ignore_update(obj, pos):
19+
pass
20+
21+
class Heap:
22+
def __init__(self, data,
23+
less = less,
24+
update = ignore_update):
25+
self.data = data
26+
self.less = less
27+
self.update = update
28+
i = 0
29+
for obj in self.data:
30+
self.update(obj, i)
31+
i += 1
32+
build_max_heap(self)
33+
34+
def __repr__(self):
35+
return repr(self.data[:self.heap_size])
36+
37+
def maximum(self):
38+
return self.data[0]
39+
40+
def insert(self, obj):
41+
self.heap_size += 1
42+
if len(self.data) < self.heap_size:
43+
self.data.append(obj)
44+
else:
45+
self.data[self.heap_size - 1] = obj
46+
self.update(obj, self.heap_size - 1)
47+
heap_increase_key(self, self.heap_size - 1)
48+
49+
def extract_max(self):
50+
assert self.heap_size != 0
51+
max = self.data[0]
52+
self.data[0] = self.data[self.heap_size-1]
53+
self.update(self.data[0], 0)
54+
self.heap_size -= 1
55+
max_heapify(self, 0)
56+
return max
57+
58+
def left(i):
59+
return 2 * i + 1
60+
61+
def right(i):
62+
return 2 * (i + 1)
63+
64+
def parent(i):
65+
return (i-1) // 2
66+
67+
def heap_increase_key(H, i):
68+
while i > 0 and H.less(H.data[parent(i)], H.data[i]):
69+
swap(H.data, i, parent(i))
70+
H.update(H.data[i], i)
71+
H.update(H.data[parent(i)], parent(i))
72+
i = parent(i)
73+
74+
def max_heapify(H, i):
75+
l = left(i)
76+
r = right(i)
77+
if l < H.heap_size and H.less(H.data[i], H.data[l]):
78+
largest = l
79+
else:
80+
largest = i
81+
if r < H.heap_size and H.less(H.data[largest], H.data[r]):
82+
largest = r
83+
if largest != i:
84+
swap(H.data, i, largest)
85+
H.update(H.data[i], i)
86+
H.update(H.data[largest], largest)
87+
max_heapify(H, largest)
88+
89+
def build_max_heap(H):
90+
H.heap_size = len(H.data)
91+
last_parent = len(H.data) // 2
92+
for i in range(last_parent, -1, -1):
93+
max_heapify(H, i)
94+
95+
def heap_sort(H):
96+
build_max_heap(H)
97+
for i in range(len(H.data)-1, 0, -1):
98+
swap(H.data, 0, i)
99+
H.update(H.data[0], 0); H.update(H.data[i], i)
100+
H.heap_size -= 1
101+
max_heapify(H, 0)
102+
103+
class PriorityQueue:
104+
def __init__(self, less=less_key, update=update_position, get=get_position):
105+
self.heap = Heap([], less=less, update=update)
106+
self.get_position = get
107+
self.get_object = {}
108+
109+
def __repr__(self):
110+
return repr(self.heap)
111+
112+
def push(self, key):
113+
o = Obj(key)
114+
self.get_object[key] = o
115+
self.heap.insert(o)
116+
117+
def pop(self):
118+
return self.heap.extract_max().key
119+
120+
def increase_key(self, key):
121+
obj = self.get_object[key]
122+
heap_increase_key(self.heap, self.get_position(obj))
123+
124+
def empty(self):
125+
return self.heap.heap_size == 0
126+
127+
class Obj:
128+
def __init__(self, k):
129+
self.key = k
130+
self.position = -1
131+
132+
def __repr__(self):
133+
return str(self.key) + '@' + repr(self.position)
134+
135+
if __name__ == "__main__":
136+
# test build and extract_max
137+
L = [4,3,5,1,2]
138+
h = Heap(L)
139+
for i in range(5, 0, -1):
140+
assert h.extract_max() == i
141+
142+
# test insert
143+
L = [4,3,5,1,2]
144+
for k in L:
145+
h.insert(k)
146+
for i in range(5, 0, -1):
147+
assert h.extract_max() == i
148+
149+
# test sort
150+
L = [4,3,5,1,2]
151+
heap_sort(Heap(L))
152+
for i in range(0, 5):
153+
assert L[i] == i + 1
154+
155+
# Test priority queue
156+
# Q = PriorityQueue()
157+
# for i in range(1, 6):
158+
# Q.push(Obj(i))
159+
# for i in range(5, 0, -1):
160+
# assert Q.pop().key == i
161+
162+
L = {'a': 4, 'b': 3, 'c':5,'d':1,'e':2}
163+
def less(x, y):
164+
return L[x.key] < L[y.key]
165+
Q = PriorityQueue(less)
166+
for k, v in L.items():
167+
Q.push(k)
168+
169+
# test increase_key
170+
for k, v in L.items():
171+
L[k] = v + 2
172+
Q.increase_key(k)
173+
for i in range(5, 0, -1):
174+
k = Q.pop()
175+
assert L[k] == i + 2
176+
177+
print('passed all tests')

0 commit comments

Comments
 (0)