Graphs are one of the most powerful and flexible data structures used in computer science. They model relationships and connections among a set of entities, making them suitable for representing a wide range of real-world systems such as social networks, transportation grids, web pages, and much more.
A graph is composed of two main components:
Graphs can be represented in multiple ways in Python. The most common representations are:
This representation uses a dictionary where keys are nodes and values are lists of adjacent nodes.
graph = {
'A': ['B', 'C'],
'B': ['D'],
'C': ['E'],
'D': ['F'],
'E': [],
'F': []
}
A 2D array (matrix) is used where a cell [i][j] is marked if there is an edge from node i to j.
# For graph with 4 nodes: A, B, C, D
adj_matrix = [
[0, 1, 1, 0], # A
[0, 0, 0, 1], # B
[0, 0, 0, 1], # C
[0, 0, 0, 0] # D
]
This representation uses a list of edges represented as tuples or lists of pairs.
edges = [
('A', 'B'),
('A', 'C'),
('B', 'D'),
('C', 'E'),
('D', 'F')
]
To encapsulate graph operations, it's often useful to create a class:
class Graph:
def __init__(self):
self.graph = {}
def add_edge(self, u, v):
if u not in self.graph:
self.graph[u] = []
self.graph[u].append(v)
def display(self):
for node in self.graph:
print(f"{node} -> {self.graph[node]}")
DFS explores as far as possible along each branch before backtracking. It uses a stack (can be recursive).
def dfs(graph, start, visited=None):
if visited is None:
visited = set()
visited.add(start)
print(start)
for neighbor in graph.get(start, []):
if neighbor not in visited:
dfs(graph, neighbor, visited)
BFS explores all neighbors of a node before moving to the next level. It uses a queue.
from collections import deque
def bfs(graph, start):
visited = set()
queue = deque([start])
while queue:
node = queue.popleft()
if node not in visited:
print(node)
visited.add(node)
queue.extend(graph.get(node, []))
def has_cycle_undirected(graph, node, visited, parent):
visited.add(node)
for neighbor in graph[node]:
if neighbor not in visited:
if has_cycle_undirected(graph, neighbor, visited, node):
return True
elif neighbor != parent:
return True
return False
def has_cycle_directed(graph):
visited = set()
rec_stack = set()
def visit(node):
if node in rec_stack:
return True
if node in visited:
return False
visited.add(node)
rec_stack.add(node)
for neighbor in graph.get(node, []):
if visit(neighbor):
return True
rec_stack.remove(node)
return False
for node in graph:
if visit(node):
return True
return False
Topological sort gives a linear ordering of vertices such that for every directed edge u β v, u comes before v.
def topological_sort(graph):
visited = set()
stack = []
def dfs(node):
if node not in visited:
visited.add(node)
for neighbor in graph.get(node, []):
dfs(neighbor)
stack.append(node)
for node in graph:
dfs(node)
return stack[::-1]
Used to find the shortest path in a weighted graph from a source node to all other nodes.
import heapq
def dijkstra(graph, start):
distances = {node: float('inf') for node in graph}
distances[start] = 0
pq = [(0, start)]
while pq:
current_distance, current_node = heapq.heappop(pq)
if current_distance > distances[current_node]:
continue
for neighbor, weight in graph[current_node]:
distance = current_distance + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(pq, (distance, neighbor))
return distances
NetworkX is a popular Python library for creating, manipulating, and studying the structure of graphs.
import networkx as nx
G = nx.DiGraph()
G.add_edge("A", "B")
G.add_edge("B", "C")
print(list(G.nodes))
print(list(G.edges))
# Visualizing
import matplotlib.pyplot as plt
nx.draw(G, with_labels=True)
plt.show()
def connected_components(graph):
visited = set()
components = []
def dfs(node, comp):
visited.add(node)
comp.append(node)
for neighbor in graph.get(node, []):
if neighbor not in visited:
dfs(neighbor, comp)
for node in graph:
if node not in visited:
comp = []
dfs(node, comp)
components.append(comp)
return components
class Node:
def __init__(self, val):
self.val = val
self.neighbors = []
def clone_graph(node, visited=None):
if not node:
return None
if visited is None:
visited = {}
if node in visited:
return visited[node]
clone = Node(node.val)
visited[node] = clone
for neighbor in node.neighbors:
clone.neighbors.append(clone_graph(neighbor, visited))
return clone
Graphs are indispensable in the field of computer science, with applications ranging from web search engines to social networks. Understanding how to represent, traverse, and analyze graphs is essential for writing efficient algorithms and solving complex problems. Whether you're using built-in data structures or external libraries like NetworkX, Python offers extensive tools to work with graphs effectively.
Python is commonly used for developing websites and software, task automation, data analysis, and data visualisation. Since it's relatively easy to learn, Python has been adopted by many non-programmers, such as accountants and scientists, for a variety of everyday tasks, like organising finances.
Learning Curve: Python is generally considered easier to learn for beginners due to its simplicity, while Java is more complex but provides a deeper understanding of how programming works.
The point is that Java is more complicated to learn than Python. It doesn't matter the order. You will have to do some things in Java that you don't in Python. The general programming skills you learn from using either language will transfer to another.
Read on for tips on how to maximize your learning. In general, it takes around two to six months to learn the fundamentals of Python. But you can learn enough to write your first short program in a matter of minutes. Developing mastery of Python's vast array of libraries can take months or years.
6 Top Tips for Learning Python
The following is a step-by-step guide for beginners interested in learning Python using Windows.
Best YouTube Channels to Learn Python
Write your first Python programStart by writing a simple Python program, such as a classic "Hello, World!" script. This process will help you understand the syntax and structure of Python code.
The average salary for Python Developer is βΉ5,55,000 per year in the India. The average additional cash compensation for a Python Developer is within a range from βΉ3,000 - βΉ1,20,000.
Copyrights © 2024 letsupdateskills All rights reserved