Skip to content

Commit 0b86e90

Browse files
authored
Merge from master (#1)
* Added naive string search algorithm (TheAlgorithms#715) * Organize graph algorithms (TheAlgorithms#719) * organized graph algorithms * all graph algorithms in Graphs/ folder * all graph algorithms are in one folder * Rename number theory/factorial_python.py to maths/factorial_python.py * Added extended euclidean algorithm (TheAlgorithms#720) * Added extended euclidean algorithm * Fixed extended euclidean algorithm * fix comma spelling from coma to comma (TheAlgorithms#722) * Delete Maths/find_hcf.py (TheAlgorithms#636) * fixed balanced_parentheses, Added infix-prefix & postfix evaluation (TheAlgorithms#621) * Create infix_to_prefix_conversion.py * Create postfix_evaluation.py * Update balanced_parentheses.py * Update heap.py (TheAlgorithms#726) Added comments for the better understanding of heap. * Update basic_binary_tree.py (TheAlgorithms#725) I have added the comments for better understanding. * Fix '__bool__' method (TheAlgorithms#735) The method returns the truth when the stack is empty * added wiggle_sort.py (TheAlgorithms#734) * Wiggle_sort * Rename Wiggle_Sort to wiggle_sort.py * Create Searching in sorted matrix (TheAlgorithms#738) * Create Searching in sorted matrix * Rename Searching in sorted matrix to searching_in_sorted_matrix.py * reduce indentation (TheAlgorithms#741) * More matrix algorithms (TheAlgorithms#745) * added matrix minor * added matrix determinant * added inverse,scalar multiply, identity, transpose * Bitmasking and DP added (TheAlgorithms#705) * Added Trafid Cipher (TheAlgorithms#746) * Create is_Palindrome (TheAlgorithms#740) * Update basic_binary_tree.py (TheAlgorithms#748) * feature to add input (TheAlgorithms#749) * Add lowest common ancestor to data structures (TheAlgorithms#732) * add longest common ancestor in data structures * add lowest common ancestor to data structures * implementation of tower_of_hanoi algorithm (TheAlgorithms#756) * Add animation for heap sort * Updated Euler problem 21 sol1.py * Rename is_Palindrome to is_Palindrome.py (TheAlgorithms#752) * Some directories had a capital in their name [fixed]. Added a recursive factorial algorithm. (TheAlgorithms#763) * Renaming directories * Adding a recursive factorial algorithm * Created a generalized algo to edmonds karp (TheAlgorithms#724) Edmonds Karp algorithm is traditionally with only one source and one sink. What do you do if you have multiple sources and sinks? This algorithm is a generalized algorithm that regardless of however many sinks and sources you have, will allow you to use this algorithm. It does this by using the traditional algorithm but adding an artificial source and sink that allows with "infinite" weight. * variable in function should be lowercase (TheAlgorithms#768) * Adding quick sort where random pivot point is chosen (TheAlgorithms#774) * Added an O(1) solution to problem 002 (TheAlgorithms#776) * Added an O(1) solution to problem 002 * Removed comments from sol3.py that were accidentally added to sol4.py * Update README.md * Update Directed and Undirected (Weighted) Graph.py * update 'sorted' to 'ascending sorted' in comments (TheAlgorithms#789) To avoid confusion all 'sorted' to 'ascending sorted' in comments * fix: replaced outdated url (TheAlgorithms#791) http://www.lpb-riannetrujillo.com/blog/python-fractal/ moved to http://www.riannetrujillo.com/blog/python-fractal/ * add-binary-exponentiation (TheAlgorithms#790) * [FIX] maths/PrimeCheck (TheAlgorithms#796) Current implementation is buggy and hard to read. * Negative values were raising a TypeError due to `math.sqrt` * 1 was considered prime, it is not. * 2 was considered not prime, it is. The implementation has been corrected to fix the bugs and to enhance readability. A docstring has been added with the definition of a prime number. A complete test suite has been written, it tests the 10 first primes, a negative value, 0, 1 and some not prime numbers. closes TheAlgorithms#795 * Update README.md * Added page-rank algorithm implementation (TheAlgorithms#780) * Added page-rank algorithm implementation * changed init variables * Added Huffman Coding Algorithm (TheAlgorithms#798) * More elegant coding for merge_sort_fastest (TheAlgorithms#804) * More elegant coding for merge_sort_fastest * More elegant coding for merge_sort * Fix typo (TheAlgorithms#806) * added eulerian path and circuit finding algorithm (TheAlgorithms#787) * enhancement (TheAlgorithms#803) * Update graph.py (TheAlgorithms#809) * Implement check_bipartite_graph using DFS. (TheAlgorithms#808) * Use ==/!= to compare str, bytes, and int literals (TheAlgorithms#767) * Travis CI: Add more flake8 tests * Use ==/!= to compare str, bytes, and int literals ./project_euler/problem_17/sol1.py:25:7: F632 use ==/!= to compare str, bytes, and int literals if i%100 is not 0: ^ * Use ==/!= to compare str, bytes, and int literals * Update sol1.py * Created shortest path using bfs (TheAlgorithms#794) * Created shortest path using bfs * Interpolation search - fix endless loop bug, divide 0 bug and update description (TheAlgorithms#793) * fix endless loop bug, divide 0 bug and update description fix an endless bug, for example, if collection = [10,30,40,45,50,66,77,93], item = 67. fix divide 0 bug, when right=left it is not OK to point = left + ((item - sorted_collection[left]) * (right - left)) // (sorted_collection[right] - sorted_collection[left]) update 'sorted' to 'ascending sorted' in description to avoid confusion * delete swap files * delete 'address' and add input validation * Update bucket_sort.py (TheAlgorithms#821) * Some simplification * Add NQueens backtracking search implementation (TheAlgorithms#504) * fix spelling on line 44 of bucket sort (TheAlgorithms#824) * change besd to best * Removed the (incorrectly named) redundant file graph_list.py and renamed graph.py to graph_list.py (TheAlgorithms#820) * fix empty list validation and code data structures (TheAlgorithms#826) * fix empty list validation and code data structures * Update bucket_sort.py TheAlgorithms#826 (review)
1 parent 2b27086 commit 0b86e90

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+1688
-246
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ install:
1616
- pip install flake8 # pytest # add another testing frameworks later
1717
before_script:
1818
# stop the build if there are Python syntax errors or undefined names
19-
- flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
19+
- flake8 . --count --select=E9,F63,F72,F82 --show-source --statistics
2020
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
2121
- flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
2222
script:
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Eulerian Path is a path in graph that visits every edge exactly once.
2+
# Eulerian Circuit is an Eulerian Path which starts and ends on the same
3+
# vertex.
4+
# time complexity is O(V+E)
5+
# space complexity is O(VE)
6+
7+
8+
# using dfs for finding eulerian path traversal
9+
def dfs(u, graph, visited_edge, path=[]):
10+
path = path + [u]
11+
for v in graph[u]:
12+
if visited_edge[u][v] == False:
13+
visited_edge[u][v], visited_edge[v][u] = True, True
14+
path = dfs(v, graph, visited_edge, path)
15+
return path
16+
17+
18+
# for checking in graph has euler path or circuit
19+
def check_circuit_or_path(graph, max_node):
20+
odd_degree_nodes = 0
21+
odd_node = -1
22+
for i in range(max_node):
23+
if i not in graph.keys():
24+
continue
25+
if len(graph[i]) % 2 == 1:
26+
odd_degree_nodes += 1
27+
odd_node = i
28+
if odd_degree_nodes == 0:
29+
return 1, odd_node
30+
if odd_degree_nodes == 2:
31+
return 2, odd_node
32+
return 3, odd_node
33+
34+
35+
def check_euler(graph, max_node):
36+
visited_edge = [[False for _ in range(max_node + 1)] for _ in range(max_node + 1)]
37+
check, odd_node = check_circuit_or_path(graph, max_node)
38+
if check == 3:
39+
print("graph is not Eulerian")
40+
print("no path")
41+
return
42+
start_node = 1
43+
if check == 2:
44+
start_node = odd_node
45+
print("graph has a Euler path")
46+
if check == 1:
47+
print("graph has a Euler cycle")
48+
path = dfs(start_node, graph, visited_edge)
49+
print(path)
50+
51+
52+
def main():
53+
G1 = {
54+
1: [2, 3, 4],
55+
2: [1, 3],
56+
3: [1, 2],
57+
4: [1, 5],
58+
5: [4]
59+
}
60+
G2 = {
61+
1: [2, 3, 4, 5],
62+
2: [1, 3],
63+
3: [1, 2],
64+
4: [1, 5],
65+
5: [1, 4]
66+
}
67+
G3 = {
68+
1: [2, 3, 4],
69+
2: [1, 3, 4],
70+
3: [1, 2],
71+
4: [1, 2, 5],
72+
5: [4]
73+
}
74+
G4 = {
75+
1: [2, 3],
76+
2: [1, 3],
77+
3: [1, 2],
78+
}
79+
G5 = {
80+
1: [],
81+
2: []
82+
# all degree is zero
83+
}
84+
max_node = 10
85+
check_euler(G1, max_node)
86+
check_euler(G2, max_node)
87+
check_euler(G3, max_node)
88+
check_euler(G4, max_node)
89+
check_euler(G5, max_node)
90+
91+
92+
if __name__ == "__main__":
93+
main()
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
class FlowNetwork:
2+
def __init__(self, graph, sources, sinks):
3+
self.sourceIndex = None
4+
self.sinkIndex = None
5+
self.graph = graph
6+
7+
self._normalizeGraph(sources, sinks)
8+
self.verticesCount = len(graph)
9+
self.maximumFlowAlgorithm = None
10+
11+
# make only one source and one sink
12+
def _normalizeGraph(self, sources, sinks):
13+
if sources is int:
14+
sources = [sources]
15+
if sinks is int:
16+
sinks = [sinks]
17+
18+
if len(sources) == 0 or len(sinks) == 0:
19+
return
20+
21+
self.sourceIndex = sources[0]
22+
self.sinkIndex = sinks[0]
23+
24+
# make fake vertex if there are more
25+
# than one source or sink
26+
if len(sources) > 1 or len(sinks) > 1:
27+
maxInputFlow = 0
28+
for i in sources:
29+
maxInputFlow += sum(self.graph[i])
30+
31+
32+
size = len(self.graph) + 1
33+
for room in self.graph:
34+
room.insert(0, 0)
35+
self.graph.insert(0, [0] * size)
36+
for i in sources:
37+
self.graph[0][i + 1] = maxInputFlow
38+
self.sourceIndex = 0
39+
40+
size = len(self.graph) + 1
41+
for room in self.graph:
42+
room.append(0)
43+
self.graph.append([0] * size)
44+
for i in sinks:
45+
self.graph[i + 1][size - 1] = maxInputFlow
46+
self.sinkIndex = size - 1
47+
48+
49+
def findMaximumFlow(self):
50+
if self.maximumFlowAlgorithm is None:
51+
raise Exception("You need to set maximum flow algorithm before.")
52+
if self.sourceIndex is None or self.sinkIndex is None:
53+
return 0
54+
55+
self.maximumFlowAlgorithm.execute()
56+
return self.maximumFlowAlgorithm.getMaximumFlow()
57+
58+
def setMaximumFlowAlgorithm(self, Algorithm):
59+
self.maximumFlowAlgorithm = Algorithm(self)
60+
61+
62+
class FlowNetworkAlgorithmExecutor(object):
63+
def __init__(self, flowNetwork):
64+
self.flowNetwork = flowNetwork
65+
self.verticesCount = flowNetwork.verticesCount
66+
self.sourceIndex = flowNetwork.sourceIndex
67+
self.sinkIndex = flowNetwork.sinkIndex
68+
# it's just a reference, so you shouldn't change
69+
# it in your algorithms, use deep copy before doing that
70+
self.graph = flowNetwork.graph
71+
self.executed = False
72+
73+
def execute(self):
74+
if not self.executed:
75+
self._algorithm()
76+
self.executed = True
77+
78+
# You should override it
79+
def _algorithm(self):
80+
pass
81+
82+
83+
84+
class MaximumFlowAlgorithmExecutor(FlowNetworkAlgorithmExecutor):
85+
def __init__(self, flowNetwork):
86+
super(MaximumFlowAlgorithmExecutor, self).__init__(flowNetwork)
87+
# use this to save your result
88+
self.maximumFlow = -1
89+
90+
def getMaximumFlow(self):
91+
if not self.executed:
92+
raise Exception("You should execute algorithm before using its result!")
93+
94+
return self.maximumFlow
95+
96+
class PushRelabelExecutor(MaximumFlowAlgorithmExecutor):
97+
def __init__(self, flowNetwork):
98+
super(PushRelabelExecutor, self).__init__(flowNetwork)
99+
100+
self.preflow = [[0] * self.verticesCount for i in range(self.verticesCount)]
101+
102+
self.heights = [0] * self.verticesCount
103+
self.excesses = [0] * self.verticesCount
104+
105+
def _algorithm(self):
106+
self.heights[self.sourceIndex] = self.verticesCount
107+
108+
# push some substance to graph
109+
for nextVertexIndex, bandwidth in enumerate(self.graph[self.sourceIndex]):
110+
self.preflow[self.sourceIndex][nextVertexIndex] += bandwidth
111+
self.preflow[nextVertexIndex][self.sourceIndex] -= bandwidth
112+
self.excesses[nextVertexIndex] += bandwidth
113+
114+
# Relabel-to-front selection rule
115+
verticesList = [i for i in range(self.verticesCount)
116+
if i != self.sourceIndex and i != self.sinkIndex]
117+
118+
# move through list
119+
i = 0
120+
while i < len(verticesList):
121+
vertexIndex = verticesList[i]
122+
previousHeight = self.heights[vertexIndex]
123+
self.processVertex(vertexIndex)
124+
if self.heights[vertexIndex] > previousHeight:
125+
# if it was relabeled, swap elements
126+
# and start from 0 index
127+
verticesList.insert(0, verticesList.pop(i))
128+
i = 0
129+
else:
130+
i += 1
131+
132+
self.maximumFlow = sum(self.preflow[self.sourceIndex])
133+
134+
def processVertex(self, vertexIndex):
135+
while self.excesses[vertexIndex] > 0:
136+
for neighbourIndex in range(self.verticesCount):
137+
# if it's neighbour and current vertex is higher
138+
if self.graph[vertexIndex][neighbourIndex] - self.preflow[vertexIndex][neighbourIndex] > 0\
139+
and self.heights[vertexIndex] > self.heights[neighbourIndex]:
140+
self.push(vertexIndex, neighbourIndex)
141+
142+
self.relabel(vertexIndex)
143+
144+
def push(self, fromIndex, toIndex):
145+
preflowDelta = min(self.excesses[fromIndex],
146+
self.graph[fromIndex][toIndex] - self.preflow[fromIndex][toIndex])
147+
self.preflow[fromIndex][toIndex] += preflowDelta
148+
self.preflow[toIndex][fromIndex] -= preflowDelta
149+
self.excesses[fromIndex] -= preflowDelta
150+
self.excesses[toIndex] += preflowDelta
151+
152+
def relabel(self, vertexIndex):
153+
minHeight = None
154+
for toIndex in range(self.verticesCount):
155+
if self.graph[vertexIndex][toIndex] - self.preflow[vertexIndex][toIndex] > 0:
156+
if minHeight is None or self.heights[toIndex] < minHeight:
157+
minHeight = self.heights[toIndex]
158+
159+
if minHeight is not None:
160+
self.heights[vertexIndex] = minHeight + 1
161+
162+
if __name__ == '__main__':
163+
entrances = [0]
164+
exits = [3]
165+
# graph = [
166+
# [0, 0, 4, 6, 0, 0],
167+
# [0, 0, 5, 2, 0, 0],
168+
# [0, 0, 0, 0, 4, 4],
169+
# [0, 0, 0, 0, 6, 6],
170+
# [0, 0, 0, 0, 0, 0],
171+
# [0, 0, 0, 0, 0, 0],
172+
# ]
173+
graph = [[0, 7, 0, 0], [0, 0, 6, 0], [0, 0, 0, 8], [9, 0, 0, 0]]
174+
175+
# prepare our network
176+
flowNetwork = FlowNetwork(graph, entrances, exits)
177+
# set algorithm
178+
flowNetwork.setMaximumFlowAlgorithm(PushRelabelExecutor)
179+
# and calculate
180+
maximumFlow = flowNetwork.findMaximumFlow()
181+
182+
print("maximum flow is {}".format(maximumFlow))

Graphs/pagerank.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
'''
2+
Author: https://github.com/bhushan-borole
3+
'''
4+
'''
5+
The input graph for the algorithm is:
6+
7+
A B C
8+
A 0 1 1
9+
B 0 0 1
10+
C 1 0 0
11+
12+
'''
13+
14+
graph = [[0, 1, 1],
15+
[0, 0, 1],
16+
[1, 0, 0]]
17+
18+
19+
class Node:
20+
def __init__(self, name):
21+
self.name = name
22+
self.inbound = []
23+
self.outbound = []
24+
25+
def add_inbound(self, node):
26+
self.inbound.append(node)
27+
28+
def add_outbound(self, node):
29+
self.outbound.append(node)
30+
31+
def __repr__(self):
32+
return 'Node {}: Inbound: {} ; Outbound: {}'.format(self.name,
33+
self.inbound,
34+
self.outbound)
35+
36+
37+
def page_rank(nodes, limit=3, d=0.85):
38+
ranks = {}
39+
for node in nodes:
40+
ranks[node.name] = 1
41+
42+
outbounds = {}
43+
for node in nodes:
44+
outbounds[node.name] = len(node.outbound)
45+
46+
for i in range(limit):
47+
print("======= Iteration {} =======".format(i+1))
48+
for j, node in enumerate(nodes):
49+
ranks[node.name] = (1 - d) + d * sum([ ranks[ib]/outbounds[ib] for ib in node.inbound ])
50+
print(ranks)
51+
52+
53+
def main():
54+
names = list(input('Enter Names of the Nodes: ').split())
55+
56+
nodes = [Node(name) for name in names]
57+
58+
for ri, row in enumerate(graph):
59+
for ci, col in enumerate(row):
60+
if col == 1:
61+
nodes[ci].add_inbound(names[ri])
62+
nodes[ri].add_outbound(names[ci])
63+
64+
print("======= Nodes =======")
65+
for node in nodes:
66+
print(node)
67+
68+
page_rank(nodes)
69+
70+
71+
if __name__ == '__main__':
72+
main()

Maths/find_hcf.py

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)