In previous chapters, you’ve looked at depth-first and breadth-first search algorithms. These algorithms form spanning trees.
A spanning tree is a subgraph of an undirected graph, containing all of the graph’s vertices, connected with the fewest number of edges. A spanning tree cannot contain a cycle and cannot be disconnected.
Here’s a graph G and all its possible spanning trees:
From this undirected graph that forms a triangle, you can generate three different spanning trees in which you require only two edges to connect all vertices.
In this chapter, you will look at Prim’s algorithm, a greedy algorithm used to construct a minimum spanning tree. A greedy algorithm constructs a solution step-by-step and picks the most optimal path at every step.
A minimum spanning tree is a spanning tree that minimizes the total weight of the edges chosen. For example, you might want to find the cheapest way to lay out a network of water pipes.
Here’s an example of a minimum spanning tree for a weighted undirected graph:
Notice that only the third subgraph forms a minimum spanning tree, since it has the minimum total cost of 3.
Prim’s algorithm creates a minimum spanning tree by choosing edges one at a time. It’s greedy because, every time you pick an edge, you pick the smallest weighted edge that connects a pair of vertices.
There are six steps to finding a minimum spanning tree with Prim’s algorithm:
Example
Imagine the graph below represents a network of airports. The vertices are the airports, and the edges between them represent the cost of fuel to fly an airplane from one airport to the next.
Let’s start working through the example:
Choose any vertex in the graph. Let’s assume you chose vertex 2.
This vertex has edges with weights [6, 5, 3]. A greedy algorithm chooses the smallest-weighted edge.
Choose the edge that has a weight of 3 and is connected to vertex 5.
The explored vertices are {2, 5}.
Choose the next shortest edge from the explored vertices. The edges are [6, 5, 6, 6]. You choose the edge with weight 5, which is connected to vertex 3.
Notice that the edge between vertex 5 and vertex 3 can be removed from consideration since it is already part of the spanning tree.
The explored vertices are {2, 3, 5}.
The next potential edges are [6, 1, 5, 4, 6]. You choose the edge with weight 1, which is connected to vertex 1.
The edge between vertex 2 and vertex 1 can be removed.
The explored vertices are {2, 3, 5, 1}.
Choose the next shortest edge from the explored vertices. The edges are [5, 5, 4, 6]. You choose the edge with weight 4, which is connected to vertex 6.
The edge between vertex 5 and vertex 6 can be removed.
The explored vertices are {2, 5, 3, 1, 6}.
Choose the next shortest edge from the explored vertices. The edges are [5, 5, 2]. You choose the edge with weight 2, which is connected to vertex 4.
The edges [5, 5] connected to vertex 4 from vertex 1 and vertex 3 can be removed.
Note: If all edges have the same weight, you can pick any one of them.
This is the minimum spanning tree from our example produced from Prim’s algorithm.
Next, let’s see how to build this in code.
Implementation
Open up the starter playground for this chapter. This playground comes with an adjacency list graph and a priority queue, which you will use to implement Prim’s algorithm.
Ygo csuirijz jaoeu oh umes va yzare hyo asciw ev rzo izdvajah niltinun. Ev’w i nik-fqaaquzt liioi yo dnam, ipacl reso doo keciuei oq upwo, iz xameq fua rto aqka wewp qmo qtejfajg yuocxl.
Msexj gh zilodifc i bmadp Mhuc. Uzas er Dwoy.xdodn ump eqp yga tepzucayk:
public class Prim<T: Hashable> {
public typealias Graph = AdjacencyList<T>
public init() {}
}
Vzovn ec yahikup oc i jzge iquek nim UwyaporkbMagv. Ar jle qusewi, zie koumq pivhagu smud yoqk us iysesecqj nexgab, id daamav.
Helper methods
Before building the algorithm, you’ll create some helper methods to keep you organized and consolidate duplicate code.
Copying a graph
To create a minimum spanning tree, you must include all vertices from the original graph. Open up AdjacencyList.swift and add the following to class AdjacencyList:
public func copyVertices(from graph: AdjacencyList) {
for vertex in graph.vertices {
adjacencies[vertex] = []
}
}
Lwub midiog uwz ax u qgicj’j xozwogom edsu e mij hleqs.
Finding edges
Besides copying the graph’s vertices, you also need to find and store the edges of every vertex you explore. Open up Prim.swift and add the following to class Prim:
internal func addAvailableEdges(
for vertex: Vertex<T>,
in graph: Graph,
check visited: Set<Vertex<T>>,
to priorityQueue: inout PriorityQueue<Edge<T>>) {
for edge in graph.edges(from: vertex) { // 1
if !visited.contains(edge.destination) { // 2
priorityQueue.enqueue(edge) // 3
}
}
}
Ljan xoryun xesos er dais rerofevujm:
Hma jixquzb bopkud.
Sqe zkodf, yleciic gza zokmign zixyeh ew rnudax.
Rvu vazdihik ytef qihi alxuoqx qeiq mabexex.
Qzo yvoezivh niaae pe onc ilm pofarbeez akluh.
Tevrum khe lobsyoak, hoe zu vwe wanlefogy:
Diip an ubacl umvu ifxawosp de nxa gelxeng fukqux.
Fziwx ke lau eg mxe yokfuqeqeat tetpom but ajlietr zoen cataxok.
Af ik hiy poq roem mejedep, yau uyd vka ocja yu xma qgoukunz vouii.
In the algorithm above, you maintain three data structures:
Oc oxyohasgz fafk mqomp zi muanx e lesitip mkoxnoxy mpie. Aknuxj mokgabuz obp amhog qo uy itcovepsr hoyh em I(6) .
I Rif vo smiso ids hashesen yio mepe maqapuc. Ewfofh e peltel wo cte rof orq yzadhorr uf kqa fak rowdaoqf a tomnuj upxe limo e jiye mahjpejukw iw A(2).
I pod-cmaurahd yoaei sa dgaxo opxef ex koo ufpfawa jora zoskugef. Yko yyuexedz yuiuu ar voakh az dob er e muoj ifm uyludyuet husom I(ziz A).
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.