Merge pull request #395 from FarhanKasmani/ExtraAlgortihms

Extra Algorithms added
This commit is contained in:
Harshil 2018-10-03 21:55:55 +02:00 committed by GitHub
commit e09bf504a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 431 additions and 0 deletions

View File

@ -0,0 +1,44 @@
# Finding Articulation Points in Undirected Graph
def computeAP(l):
n = len(l)
outEdgeCount = 0
low = [0] * n
visited = [False] * n
isArt = [False] * n
def dfs(root, at, parent, outEdgeCount):
if parent == root:
outEdgeCount += 1
visited[at] = True
low[at] = at
for to in l[at]:
if to == parent:
pass
elif not visited[to]:
outEdgeCount = dfs(root, to, at, outEdgeCount)
low[at] = min(low[at], low[to])
# AP found via bridge
if at < low[to]:
isArt[at] = True
# AP found via cycle
if at == low[to]:
isArt[at] = True
else:
low[at] = min(low[at], to)
return outEdgeCount
for i in range(n):
if not visited[i]:
outEdgeCount = 0
outEdgeCount = dfs(i, i, -1, outEdgeCount)
isArt[i] = (outEdgeCount > 1)
for x in range(len(isArt)):
if isArt[x] == True:
print(x, end=" ")
# Adjacency list of graph
l = {0:[1,2], 1:[0,2], 2:[0,1,3,5], 3:[2,4], 4:[3], 5:[2,6,8], 6:[5,7], 7:[6,8], 8:[5,7]}
computeAP(l)

View File

@ -0,0 +1,43 @@
# Check whether Graph is Bipartite or Not using BFS
# A Bipartite Graph is a graph whose vertices can be divided into two independent sets,
# U and V such that every edge (u, v) either connects a vertex from U to V or a vertex
# from V to U. In other words, for every edge (u, v), either u belongs to U and v to V,
# or u belongs to V and v to U. We can also say that there is no edge that connects
# vertices of same set.
def checkBipartite(l):
queue = []
visited = [False] * len(l)
color = [-1] * len(l)
def bfs():
while(queue):
u = queue.pop(0)
visited[u] = True
for neighbour in l[u]:
if neighbour == u:
return False
if color[neighbour] == -1:
color[neighbour] = 1 - color[u]
queue.append(neighbour)
elif color[neighbour] == color[u]:
return False
return True
for i in range(len(l)):
if not visited[i]:
queue.append(i)
color[i] = 0
if bfs() == False:
return False
return True
# Adjacency List of graph
l = {0:[1,3], 1:[0,2], 2:[1,3], 3:[0,2]}
print(checkBipartite(l))

31
Graphs/FindingBridges.py Normal file
View File

@ -0,0 +1,31 @@
# Finding Bridges in Undirected Graph
def computeBridges(l):
id = 0
n = len(l) # No of vertices in graph
low = [0] * n
visited = [False] * n
def dfs(at, parent, bridges, id):
visited[at] = True
low[at] = id
id += 1
for to in l[at]:
if to == parent:
pass
elif not visited[to]:
dfs(to, at, bridges, id)
low[at] = min(low[at], low[to])
if at < low[to]:
bridges.append([at, to])
else:
# This edge is a back edge and cannot be a bridge
low[at] = min(low[at], to)
bridges = []
for i in range(n):
if (not visited[i]):
dfs(i, -1, bridges, id)
print(bridges)
l = {0:[1,2], 1:[0,2], 2:[0,1,3,5], 3:[2,4], 4:[3], 5:[2,6,8], 6:[5,7], 7:[6,8], 8:[5,7]}
computeBridges(l)

View File

@ -0,0 +1,30 @@
# Finding longest distance in Directed Acyclic Graph using KahnsAlgorithm
def longestDistance(l):
indegree = [0] * len(l)
queue = []
longDist = [1] * len(l)
for key, values in l.items():
for i in values:
indegree[i] += 1
for i in range(len(indegree)):
if indegree[i] == 0:
queue.append(i)
while(queue):
vertex = queue.pop(0)
for x in l[vertex]:
indegree[x] -= 1
if longDist[vertex] + 1 > longDist[x]:
longDist[x] = longDist[vertex] + 1
if indegree[x] == 0:
queue.append(x)
print(max(longDist))
# Adjacency list of Graph
l = {0:[2,3,4], 1:[2,7], 2:[5], 3:[5,7], 4:[7], 5:[6], 6:[7], 7:[]}
longestDistance(l)

View File

@ -0,0 +1,32 @@
# Kahn's Algorithm is used to find Topological ordering of Directed Acyclic Graph using BFS
def topologicalSort(l):
indegree = [0] * len(l)
queue = []
topo = []
cnt = 0
for key, values in l.items():
for i in values:
indegree[i] += 1
for i in range(len(indegree)):
if indegree[i] == 0:
queue.append(i)
while(queue):
vertex = queue.pop(0)
cnt += 1
topo.append(vertex)
for x in l[vertex]:
indegree[x] -= 1
if indegree[x] == 0:
queue.append(x)
if cnt != len(l):
print("Cycle exists")
else:
print(topo)
# Adjacency List of Graph
l = {0:[1,2], 1:[3], 2:[3], 3:[4,5], 4:[], 5:[]}
topologicalSort(l)

View File

@ -0,0 +1,111 @@
import sys
from collections import defaultdict
def PrimsAlgorithm(l):
nodePosition = []
def getPosition(vertex):
return nodePosition[vertex]
def setPosition(vertex, pos):
nodePosition[vertex] = pos
def topToBottom(heap, start, size, positions):
if start > size // 2 - 1:
return
else:
if 2 * start + 2 >= size:
m = 2 * start + 1
else:
if heap[2 * start + 1] < heap[2 * start + 2]:
m = 2 * start + 1
else:
m = 2 * start + 2
if heap[m] < heap[start]:
temp, temp1 = heap[m], positions[m]
heap[m], positions[m] = heap[start], positions[start]
heap[start], positions[start] = temp, temp1
temp = getPosition(positions[m])
setPosition(positions[m], getPosition(positions[start]))
setPosition(positions[start], temp)
topToBottom(heap, m, size, positions)
# Update function if value of any node in min-heap decreases
def bottomToTop(val, index, heap, position):
temp = position[index]
while(index != 0):
if index % 2 == 0:
parent = int( (index-2) / 2 )
else:
parent = int( (index-1) / 2 )
if val < heap[parent]:
heap[index] = heap[parent]
position[index] = position[parent]
setPosition(position[parent], index)
else:
heap[index] = val
position[index] = temp
setPosition(temp, index)
break
index = parent
else:
heap[0] = val
position[0] = temp
setPosition(temp, 0)
def heapify(heap, positions):
start = len(heap) // 2 - 1
for i in range(start, -1, -1):
topToBottom(heap, i, len(heap), positions)
def deleteMinimum(heap, positions):
temp = positions[0]
heap[0] = sys.maxsize
topToBottom(heap, 0, len(heap), positions)
return temp
visited = [0 for i in range(len(l))]
Nbr_TV = [-1 for i in range(len(l))] # Neighboring Tree Vertex of selected vertex
# Minimum Distance of explored vertex with neighboring vertex of partial tree formed in graph
Distance_TV = [] # Heap of Distance of vertices from their neighboring vertex
Positions = []
for x in range(len(l)):
p = sys.maxsize
Distance_TV.append(p)
Positions.append(x)
nodePosition.append(x)
TreeEdges = []
visited[0] = 1
Distance_TV[0] = sys.maxsize
for x in l[0]:
Nbr_TV[ x[0] ] = 0
Distance_TV[ x[0] ] = x[1]
heapify(Distance_TV, Positions)
for i in range(1, len(l)):
vertex = deleteMinimum(Distance_TV, Positions)
if visited[vertex] == 0:
TreeEdges.append((Nbr_TV[vertex], vertex))
visited[vertex] = 1
for v in l[vertex]:
if visited[v[0]] == 0 and v[1] < Distance_TV[ getPosition(v[0]) ]:
Distance_TV[ getPosition(v[0]) ] = v[1]
bottomToTop(v[1], getPosition(v[0]), Distance_TV, Positions)
Nbr_TV[ v[0] ] = vertex
return TreeEdges
# < --------- Prims Algorithm --------- >
n = int(input("Enter number of vertices: "))
e = int(input("Enter number of edges: "))
adjlist = defaultdict(list)
for x in range(e):
l = [int(x) for x in input().split()]
adjlist[l[0]].append([ l[1], l[2] ])
adjlist[l[1]].append([ l[0], l[2] ])
print(PrimsAlgorithm(adjlist))

70
Maths/BasicMaths.py Normal file
View File

@ -0,0 +1,70 @@
import math
def primeFactors(n):
pf = []
while n % 2 == 0:
pf.append(2)
n = int(n / 2)
for i in range(3, int(math.sqrt(n))+1, 2):
while n % i == 0:
pf.append(i)
n = int(n / i)
if n > 2:
pf.append(n)
return pf
def numberOfDivisors(n):
div = 1
temp = 1
while n % 2 == 0:
temp += 1
n = int(n / 2)
div = div * (temp)
for i in range(3, int(math.sqrt(n))+1, 2):
temp = 1
while n % i == 0:
temp += 1
n = int(n / i)
div = div * (temp)
return div
def sumOfDivisors(n):
s = 1
temp = 1
while n % 2 == 0:
temp += 1
n = int(n / 2)
if temp > 1:
s *= (2**temp - 1) / (2 - 1)
for i in range(3, int(math.sqrt(n))+1, 2):
temp = 1
while n % i == 0:
temp += 1
n = int(n / i)
if temp > 1:
s *= (i**temp - 1) / (i - 1)
return s
def eulerPhi(n):
l = primeFactors(n)
l = set(l)
s = n
for x in l:
s *= (x - 1)/x
return s
print(primeFactors(100))
print(numberOfDivisors(100))
print(sumOfDivisors(100))
print(eulerPhi(100))

46
Maths/SegmentedSieve.py Normal file
View File

@ -0,0 +1,46 @@
import math
def sieve(n):
in_prime = []
start = 2
end = int(math.sqrt(n)) # Size of every segment
temp = [True] * (end + 1)
prime = []
while(start <= end):
if temp[start] == True:
in_prime.append(start)
for i in range(start*start, end+1, start):
if temp[i] == True:
temp[i] = False
start += 1
prime += in_prime
low = end + 1
high = low + end - 1
if high > n:
high = n
while(low <= n):
temp = [True] * (high-low+1)
for each in in_prime:
t = math.floor(low / each) * each
if t < low:
t += each
for j in range(t, high+1, each):
temp[j - low] = False
for j in range(len(temp)):
if temp[j] == True:
prime.append(j+low)
low = high + 1
high = low + end - 1
if high > n:
high = n
return prime
print(sieve(10**6))

View File

@ -0,0 +1,24 @@
import math
n = int(input("Enter n: "))
def sieve(n):
l = [True] * (n+1)
prime = []
start = 2
end = int(math.sqrt(n))
while(start <= end):
if l[start] == True:
prime.append(start)
for i in range(start*start, n+1, start):
if l[i] == True:
l[i] = False
start += 1
for j in range(end+1,n+1):
if l[j] == True:
prime.append(j)
return prime
print(sieve(n))