Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

created collection of advance concepts of python data structure like @cache usage please merge #102

Merged
merged 1 commit into from Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions DataStructurePython/Addition Without Operator/Addition.py
@@ -0,0 +1,22 @@
# Title : Python3 Program to add two numbers without using arithmetic operator


def Add(a, b):

# Iterate till there is no carry
while b != 0:

# carry now contains common set bits of x and y
carry = a & b

# Sum of bits of x and y where at least one of the bits is not set
a = a ^ b

# Carry is shifted by one so that adding it to x gives the required sum
b = carry << 1

return a


# Declear Print statement and Pass Parameter on them i.e Print(Add(20,10))
print(Add(10, 20))
8 changes: 8 additions & 0 deletions DataStructurePython/Anagram/Anagram.py
@@ -0,0 +1,8 @@
# Checking if two words are anagrams or not
# or without having to import anything
def is_anagram(str1, str2):
return sorted(str1) == sorted(str2)


print(is_anagram('geek', 'eegk'))
print(is_anagram('geek', 'peek'))
119 changes: 119 additions & 0 deletions DataStructurePython/Cache/LRUCache.py
@@ -0,0 +1,119 @@

'''
LRU Cache Implementation :
https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)

Extensively tested implementation for LRU (Least Recently Used)
Cache DS from scratch, without using any external library,
collection or container. This implementation uses a doubly
linked list and a simple hash-map.
'''


class Node:
"""
Structure of a node in the doubly linked list
"""
def __init__(self, key: int, data: int):
self.key = key
self.data = data
self.prev = None
self.next = None


class LRUCache:
def __init__(self, capacity: int):
self.hmap = {} # key = int, value = Node

# Dummy Nodes
self.head = Node(None, None)
self.head.prev = None
self.tail = Node(None, None)
self.tail.next = None
self.head.next = self.tail
self.tail.prev = self.head

self.size = 0
self.capacity = capacity

def get(self, key: int) -> int:
"""
Access an item from the cache
"""
if len(self.hmap) == 0 or key not in self.hmap:
return -1
this_node = self.hmap[key]
self.__moveToHead(this_node)
return this_node.data

def put(self, key: int, value: int) -> None:
"""
Add or Update an item in the cache
"""
if key in self.hmap:
this_node = self.hmap[key]
this_node.data = value
self.__moveToHead(this_node)
else:
new_node = Node(key, value)
self.hmap[key] = new_node
self.__addFirst(new_node)
self.size += 1

if self.size > self.capacity:
self.__removeLRUEntry()

def __removeLRUEntry(self):
"""
Evicts the least recently used item from cache
"""
tail_node = self.__popTail()
del self.hmap[tail_node.key]
self.size -= 1

def __addFirst(self, node):
"""
Adds a node at the beginning of the linked list
"""
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next = node

def __removeNode(self, node):
"""
Removes a node from the doubly linked list
"""
oldprev, oldnext = node.prev, node.next
oldprev.next = oldnext
oldnext.prev = oldprev

def __moveToHead(self, node):
"""
Removes the node and puts it at the beginning of the cache (list)
"""
self.__removeNode(node)
self.__addFirst(node)

def __popTail(self):
"""
Removes and returns the element pointed by the tail of the list
"""
rem = self.tail.prev
self.__removeNode(rem)
return rem

def display(self):
"""
Prints the elements in the cache in order
"""
p = self.head.next
while p.next:
print("[Key:{0}, Value:{1}]".format(p.key, p.data), end=" ")
p = p.next
print("")

# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
52 changes: 52 additions & 0 deletions DataStructurePython/Graph/Directed_Acyclic_Graph.py
@@ -0,0 +1,52 @@

import networkx as nx
from matplotlib import pyplot as plt


class DAG:

def __init__(self):
self.graph = nx.DiGraph()

def addEdges(self, edges):
"""Function to add one edge at a time and
check if the graph is acyclic post insertion"""
self.graph.add_edge(edges)
if nx.is_directed_acyclic_graph(self.graph):
pass
else:
raise "Unable to insert " + str(edges) + "This is an Acyclic graph"
self.graph.remove_edge(edges)

def AddSetofEdges(self, listt):
"""Function to all a list of edges and
check is the graph is an DAG for furthur details refer networkx"""
self.graph.add_edges_from(listt)
if nx.is_directed_acyclic_graph(self.graph):
pass
else:
raise "This is an acyclic graph check your edges"
self.graph.remove_edge(listt)

def Visualise(self, location="home"):
"""It uses Matplotlib to visualise the DAG .
The graph is stored in a PNG format . So name the file accourdingly
eg
>>> DAG.Visualise(home / img.png)"""
if self.graph is None:
return "There is no graph consider adding edges to visualise"
plt.tight_layout()
nx.draw_networkx(self.graph, arrows=True, node_size=800)
plt.savefig(location, format="PNG")
plt.clf()
return "Graph generated"


graph = DAG()


graph.AddSetofEdges([("root", "a"), ("a", "b"),
("a", "e"), ("b", "c"),
("b", "d"), ("d", "e")])

graph.Visualise("Python/DataStructure/Graph/Dag.png")
137 changes: 137 additions & 0 deletions DataStructurePython/Graph/Graph.py
@@ -0,0 +1,137 @@
"""
Simple implementation of unweighted and weighted Graphs.

Both are implemented using adjacency lists.
The weighted graph implementation stores the target edges of a single
starting node of the adjacency list using a list of tuples (index, weight).

Example:
>>> graph = WeightedGraph(5) # directed weighted graph
>>> graph.add_edge(0, 1, weight=4)
>>> graph.add_edge(0, 2, weight=3)
>>> graph.add_edge(2, 3, weight=1)
>>> graph.add_edge(3, 4, weight=5)
>>> graph.add_edge(4, 1, weight=2)
>>> print(graph)
0: 1 (weight: 4) 2 (weight: 3)
1:
2: 3 (weight: 1)
3: 4 (weight: 5)
4: 1 (weight: 2)

This example input is equivalent to:
>>> graph.edges = [
>>> [(1, 4), (2, 3)],
>>> [],
>>> [(3, 1)],
>>> [(4, 5)],
>>> [(1, 2)]
>>> ]
>>>
"""


class UnweightedGraph:
def __init__(self, vertices, directed=True):
self.vertices = vertices
self.directed = directed
self.edges = [[] for _ in range(vertices)]

def __str__(self):
output = ""

for i in range(0, self.vertices):
output += f"{i}: "

for j in range(0, len(self.edges[i])):
output += f"{self.edges[i][j]} "

output += "\n"

return output

def has_vertex(self, vertex):
return 0 <= vertex < self.vertices

def has_edge(self, start, dest):
if self.has_vertex(start) and self.has_vertex(dest):
if dest in self.edges[start]:
return True

return False

def add_edge(self, start, dest):
if self.has_edge(start, dest):
return False

self.edges[start].append(dest)
if not self.directed:
self.edges[dest].append(start)

return True


class WeightedGraph:
def __init__(self, vertices, directed=True):
self.vertices = vertices
self.directed = directed
self.edges = [[] for _ in range(vertices)]

def __str__(self):
output = ""

for i in range(0, self.vertices):
output += f"{i}: "

for j in range(0, len(self.edges[i])):
output += f"{self.edges[i][j][0]} "
output += f"(weight: {self.edges[i][j][1]}) "

output += "\n"

return output

def has_vertex(self, vertex):
return 0 <= vertex < self.vertices

def has_edge(self, start, dest, weight):
if self.has_vertex(start) and self.has_vertex(dest):
if (dest, weight) in self.edges[start]:
return True

return False

def add_edge(self, start, dest, weight):
if self.has_edge(start, dest, weight):
return False

self.edges[start].append((dest, weight))
if not self.directed:
self.edges[dest].append((start, weight))

return True


def main():

# Basic driver code to demonstrate functionality

ugraph = UnweightedGraph(5)
ugraph.add_edge(0, 1)
ugraph.add_edge(0, 2)
ugraph.add_edge(0, 3)
ugraph.add_edge(2, 4)
ugraph.add_edge(1, 2)
print(ugraph)

wgraph = WeightedGraph(5)
wgraph.add_edge(0, 2, weight=3)
wgraph.add_edge(0, 3, weight=2)
wgraph.add_edge(1, 3, weight=4)
wgraph.add_edge(2, 1, weight=1)
wgraph.add_edge(4, 3, weight=6)
print(wgraph)


if __name__ == "__main__":
main()