171 lines
4.8 KiB
Plaintext
171 lines
4.8 KiB
Plaintext
|
|
{
|
||
|
|
"cells": [
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"# Graph Implementation Using Adjacency Lists\n",
|
||
|
|
"for an undirected graph. \n",
|
||
|
|
"© Joe James, 2019."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"### Vertex Class\n",
|
||
|
|
"The Vertex class has a constructor that sets the name of the vertex (in our example, just a letter), and creates a new empty set to store neighbors.\n",
|
||
|
|
"\n",
|
||
|
|
"The add_neighbor method adds the name of a neighboring vertex to the neighbors set. This set automatically eliminates duplicates."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 25,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"class Vertex:\n",
|
||
|
|
" def __init__(self, n):\n",
|
||
|
|
" self.name = n\n",
|
||
|
|
" self.neighbors = set()\n",
|
||
|
|
" \n",
|
||
|
|
" def add_neighbor(self, v):\n",
|
||
|
|
" self.neighbors.add(v)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"### Graph Class\n",
|
||
|
|
"The Graph class uses a dictionary to store vertices in the format, vertex_name:vertex_object.\n",
|
||
|
|
" \n",
|
||
|
|
"Adding a new vertex to the graph, we first check if the object passed in is a vertex object, then we check if it already exists in the graph. If both checks pass, then we add the vertex to the graph's vertices dictionary.\n",
|
||
|
|
"\n",
|
||
|
|
"When adding an edge, we receive two vertex names, we first check if both vertex names are valid, then we add each to the other's neighbors set.\n",
|
||
|
|
"\n",
|
||
|
|
"To print the graph, we iterate through the vertices, and print each vertex name (the key) followed by its sorted neighbors list."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 26,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"class Graph:\n",
|
||
|
|
" vertices = {}\n",
|
||
|
|
" \n",
|
||
|
|
" def add_vertex(self, vertex):\n",
|
||
|
|
" if isinstance(vertex, Vertex) and vertex.name not in self.vertices:\n",
|
||
|
|
" self.vertices[vertex.name] = vertex\n",
|
||
|
|
" return True\n",
|
||
|
|
" else:\n",
|
||
|
|
" return False\n",
|
||
|
|
" \n",
|
||
|
|
" def add_edge(self, u, v):\n",
|
||
|
|
" if u in self.vertices and v in self.vertices:\n",
|
||
|
|
" self.vertices[u].add_neighbor(v)\n",
|
||
|
|
" self.vertices[v].add_neighbor(u)\n",
|
||
|
|
" return True\n",
|
||
|
|
" else:\n",
|
||
|
|
" return False\n",
|
||
|
|
" \n",
|
||
|
|
" def print_graph(self):\n",
|
||
|
|
" for key in sorted(list(self.vertices.keys())):\n",
|
||
|
|
" print(key, sorted(list(self.vertices[key].neighbors)))"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"### Test Code\n",
|
||
|
|
"Here we create a new Graph object. We create a new vertex named A. We add A to the graph. Then we add new vertex B to the graph. Then we iterate from A to K and add a bunch of vertices to the graph. Since the add_vertex method checks for duplicates, A and B are not added twice."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 27,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"g = Graph()\n",
|
||
|
|
"a = Vertex('A')\n",
|
||
|
|
"g.add_vertex(a)\n",
|
||
|
|
"g.add_vertex(Vertex('B'))\n",
|
||
|
|
"for i in range(ord('A'), ord('K')):\n",
|
||
|
|
" g.add_vertex(Vertex(chr(i)))"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"An edge consists of two vertex names. Here we iterate through a list of edges and add each to the graph. \n",
|
||
|
|
"\n",
|
||
|
|
"This print_graph method doesn't give a very good visualization of the graph, but it does show the neighbors for each vertex."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 28,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"A ['B', 'E']\n",
|
||
|
|
"B ['A', 'F']\n",
|
||
|
|
"C ['G']\n",
|
||
|
|
"D ['E', 'H']\n",
|
||
|
|
"E ['A', 'D', 'H']\n",
|
||
|
|
"F ['B', 'G', 'I', 'J']\n",
|
||
|
|
"G ['C', 'F', 'J']\n",
|
||
|
|
"H ['D', 'E', 'I']\n",
|
||
|
|
"I ['F', 'H']\n",
|
||
|
|
"J ['F', 'G']\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"edges = ['AB', 'AE', 'BF', 'CG', 'DE', 'DH', 'EH', 'FG', 'FI', 'FJ', 'GJ', 'HI']\n",
|
||
|
|
"for edge in edges:\n",
|
||
|
|
" g.add_edge(edge[0], edge[1])\n",
|
||
|
|
"\n",
|
||
|
|
"g.print_graph()"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": null,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": []
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"metadata": {
|
||
|
|
"kernelspec": {
|
||
|
|
"display_name": "Python 3",
|
||
|
|
"language": "python",
|
||
|
|
"name": "python3"
|
||
|
|
},
|
||
|
|
"language_info": {
|
||
|
|
"codemirror_mode": {
|
||
|
|
"name": "ipython",
|
||
|
|
"version": 3
|
||
|
|
},
|
||
|
|
"file_extension": ".py",
|
||
|
|
"mimetype": "text/x-python",
|
||
|
|
"name": "python",
|
||
|
|
"nbconvert_exporter": "python",
|
||
|
|
"pygments_lexer": "ipython3",
|
||
|
|
"version": "3.7.0"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"nbformat": 4,
|
||
|
|
"nbformat_minor": 2
|
||
|
|
}
|