# Figure -- 05 -- greedy algorithm, Prim algorithm, kruskal algorithm

Tip: after the article is written, the directory can be generated automatically. Please refer to the help document on the right for how to generate it

# Greedy Algorithm

## Greedy algorithm - Definition:

#### Use the segmentation theorem to find one edge of the minimum spanning tree and repeat until all edges of the minimum spanning tree are found

• Greedy algorithm is the basic algorithm for calculating the minimum spanning tree of a graph. Its basic principle is the segmentation theorem,
• Use the segmentation theorem to find one edge of the minimum spanning tree and repeat until all edges of the minimum spanning tree are found.
• If a graph has V vertices, it needs to find V-1 edges to represent the minimum spanning tree of the graph. ## Greedy algorithm - principle:   ## Algorithm of minimum spanning tree

• There are many algorithms for calculating the minimum spanning tree of a graph, but these algorithms can be regarded as a special case of greedy algorithms,
• The difference between these algorithms is the way to save the segmentation and determine the cross cutting edge with the smallest weight.

# Prim algorithm

• We learn the first method to calculate the minimum spanning tree, called Prim algorithm, which adds an edge to a spanning tree at each step. At first, the tree has only one vertex, and then V-1 edges will be added to it. Each time, the next edge with the lowest weight connecting the vertex in the tree and the vertex not in the tree will be added to the tree.

## Segmentation rules:

• The vertices in the minimum spanning tree are regarded as a set, and the vertices not in the minimum spanning tree are regarded as another set. ## Algorithm API design ## Implementation principle of Prim algorithm

Prim algorithm always divides the vertices in the graph into two sets, the minimum spanning tree vertex and the non minimum spanning tree vertex. By constantly repeating some operations, you can gradually add the vertices in the non minimum spanning tree to the minimum spanning tree until all the vertices are added to the minimum spanning tree

• When designing the API, we use the minimum index priority queue to store the effective crosscutting edges of vertices in the tree and non vertices in the tree. How is it represented? We can let the index value of the minimum index priority queue represent the vertices of the graph, and let the value in the minimum index priority queue represent the edge weight from another vertex to the current vertex.

### 1. Initialization status

• In the initialization state, 0 is the only vertex in the minimum spanning tree by default, and other vertices are not in the minimum spanning tree. At this time, the crosscutting edge is the four edges 0-2,0-4,0-6,0-7 in the adjacency table of vertex 0. We only need to store the weight values of these edges at the indexes 2, 4, 6 and 7 of the index priority queue. ### 2. Find the edge with the smallest weight and add it to the tree

Now you just need to find the edge with the least weight from the four crosscutting edges, and then add the corresponding vertices. Therefore, the weight of the crosscutting edge 0-7 is the smallest, so the edge 0-7 is added. At this time, 0 and 7 belong to the vertices of the minimum spanning tree, and the others do not. Now the edges in the adjacent table of vertex 7 also become crosscutting edges, Two operations are required:

• The 0-7 edge is no longer a crosscutting edge and needs to be invalidated: it can be completed by calling the delMin() method of the minimum index priority queue;
• 2 and 4 vertices each have two connections pointing to the minimum spanning tree, and only one needs to be reserved:
The weight of 4-7 is less than that of 0-4, so keep 4-7 and call change(4,0.37) of the index priority queue,
The weight of 0-2 is less than that of 2-7, so keep 0-2 and no additional operation is required.

### 3. Repeat the above action,

• By repeating the above actions, we can add all vertices to the minimum spanning tree.

## Auxiliary class

#### 1.Edge - edge

```package graph.tu;

public class Edge implements Comparable<Edge> {
private final int v;//Vertex one
private final int w;//Vertex two
private final double weight;//The weight of the current edge

//Construct an edge object from vertices v and w and weight values
public Edge(int v, int w, double weight) {
this.v = v;
this.w = w;
this.weight = weight;
}

//Gets the weight value of the edge
public double weight(){
return weight;
}

//Gets a point on the edge
public int either(){
return v;
}

//Gets another vertex on the edge except vertex vertex
public int other(int vertex){
if (vertex==v){
return w;
}else{
return v;
}
}

@Override
public int compareTo(Edge that) {
//Use a traversal record to compare the results
int cmp;

if (this.weight()>that.weight()){
//If the weight value of the current edge is large, let cmp=1;
cmp = 1;
}else if (this.weight()<that.weight()){
//If the weight value of the current edge is small, let cmp=-1;
cmp=-1;
}else{
//If the weight value of the current edge is as large as that edge, let cmp=0
cmp = 0;
}

return cmp;
}
}

```

#### 2.EdgeWeightedGraph - weighted undirected graph

```package graph.tu;

import java.util.Queue;

public class EdgeWeightedGraph {
//Total number of vertices
private final int V;
//Total number of edges
private int E;

//Create a null weighted undirected graph with V vertices
public EdgeWeightedGraph(int v) {
//Number of initialization vertices
this.V = v;
//Number of initialization edges
this.E = 0;
for (int i = 0; i < adj.length; i++) {
}

}

//Gets the number of vertices in the graph
public int V() {
return V;
}

//Gets the number of edges in the graph
public int E() {
return E;
}

//Add an edge to the weighted undirected graph e
//You need to make edge e appear in the adjacency table of two vertices of edge e at the same time
int v = e.either();
int w = e.other(v);

//Number of sides + 1
E++;
}

//Gets all edges associated with the vertex v
}

//Gets all edges of a weighted undirected graph
public Queue<Edge> edges() {

//Create a queue object to store all the edges

//Traverse each vertex in the graph and find the adjacency table of the vertex, which stores each edge associated with the vertex

//Because this is an undirected graph, the same edge appears in the adjacency table of its associated two vertices at the same time. It is necessary to record an edge only once;
for(int v =0;v<V;v++){
//Traverse the adjacency table of v vertices and find each edge associated with v
for (Edge e : adj(v)) {

if (e.other(v)<v){
allEdges.offer(e);
}

}
}

return allEdges;
}
}

```

#### 3.IndexMinPriorityQueue - minimum priority queue

```package graph.tu;

public class IndexMinPriorityQueue<T extends Comparable<T>> {
//Elements in the storage heap
private T[] items;
//Save the index of each element in the items array. The pq array needs to be heap ordered
private int[] pq;
//Save the reverse order of qp, the value of pq as the index and the index of pq as the value
private int[] qp;
//Record the number of elements in the heap
private int N;

public IndexMinPriorityQueue(int capacity) {
this.items = (T[]) new Comparable[capacity+1];
this.pq = new int[capacity+1];
this.qp= new int[capacity+1];
this.N = 0;

//By default, no data is stored in the queue, so that all elements in qp are - 1;
for (int i = 0; i < qp.length; i++) {
qp[i]=-1;
}

}

//Gets the number of elements in the queue
public int size() {
return N;
}

//Determine whether the queue is empty
public boolean isEmpty() {
return N==0;
}

//Judge whether the element at index i in the heap is smaller than the element at index j
private boolean less(int i, int j) {

return items[pq[i]].compareTo(items[pq[j]])<0;
}

//Swap the values at the i and j indexes in the heap
private void exch(int i, int j) {
//Exchange data in pq
int tmp = pq[i];
pq[i] = pq[j];
pq[j] = tmp;

//Update data in qp
qp[pq[i]]=i;
qp[pq[j]] =j;

}

//Judge whether the element corresponding to k exists
public boolean contains(int k) {

return qp[k] !=-1;
}

//Index associated with the smallest element
public int minIndex() {

return pq;
}

//Insert an element into the queue and associate the index i
public void insert(int i, T t) {
//Judge whether i has been associated. If it has been associated, it will not be inserted

if (contains(i)){
return;
}
//Number of elements + 1
N++;
//Store the data in the i location corresponding to the items
items[i] = t;
//Store i in pq
pq[N] = i;
//i in pq is recorded by qp
qp[i]=N;

//Adjust the heap by floating it up

swim(N);

}

//Deletes the smallest element in the queue and returns the index associated with that element
public int delMin() {
//Gets the index associated with the smallest element
int minIndex = pq;

//Swap elements at index 1 and maximum index in pq
exch(1,N);
//Delete the corresponding content in qp
qp[pq[N]] = -1;
//Delete content at pq maximum index
pq[N]=-1;
//Delete the corresponding content in items
items[minIndex] = null;
//Number of elements - 1
N--;
sink(1);

return minIndex;
}

//Delete index i associated elements
public void delete(int i) {
//Find the index of i in pq
int k = qp[i];

//Swap the value at index k and the value at index N in pq
exch(k,N);
//Delete content in qp
qp[pq[N]] = -1;
//Delete content in pq
pq[N]=-1;
//Delete content in items
items[k]=null;
//Number of elements - 1
N--;
sink(k);
swim(k);
}

//Change the element associated with index i to t
public void changeItem(int i, T t) {
//Modify the element at i position in the items array to t
items[i] = t;
//Find where i appears in pq
int k = qp[i];
sink(k);
swim(k);
}

//Using the floating-up algorithm, the element at index k can be in a correct position in the heap
private void swim(int k) {
while(k>1){
if (less(k,k/2)){
exch(k,k/2);
}

k = k/2;
}
}

//Using the sinking algorithm, the element at index k can be in a correct position in the heap
private void sink(int k) {
while(2*k<=N){
//Find the smaller value in the child node
int min;
if (2*k+1<=N){
if (less(2*k,2*k+1)){
min = 2*k;
}else{
min = 2*k+1;
}
}else{
min = 2*k;
}
//Compare the current node with the smaller value
if (less(k,min)){
break;
}

exch(k,min);
k = min;
}
}

}

```

## Prim algorithm - PrimMST

```package graph.tu;

import java.util.Queue;

public class PrimMST {
//The index represents the vertex, and the value represents the shortest edge between the current vertex and the minimum spanning tree
private Edge[] edgeTo;
//The index represents the vertex, and the value represents the weight of the shortest edge between the current vertex and the minimum spanning tree
private double[] distTo;
//The index represents the vertex. If the current vertex is already in the tree, the value is true; otherwise, it is false
private boolean[] marked;
//Stores valid crosscutting edges between vertices in the tree and non vertices in the tree
private IndexMinPriorityQueue<Double> pq;

//According to a weighted undirected graph, the minimum spanning tree calculation object is created
public PrimMST(EdgeWeightedGraph G) {
//Initialize edgeTo
this.edgeTo = new Edge[G.V()];
//Initialize distTo
this.distTo = new double[G.V()];
for (int i = 0; i < distTo.length; i++) {
distTo[i] = Double.POSITIVE_INFINITY;
}
//Initialize marked
this.marked = new boolean[G.V()];
//Initialize pq
pq = new IndexMinPriorityQueue<Double>(G.V());

//By default, vertex 0 is allowed to enter the tree, but there is only one vertex 0 in the tree. Therefore, vertex 0 is not connected to other vertices by default, so let the value at the corresponding position of distTo store 0.0
distTo = 0.0;
pq.insert(0,0.0);

//Traverse the index minimum priority queue, get the vertex corresponding to the minimum and N cutting edges, and add the vertex to the minimum spanning tree
while (!pq.isEmpty()){
visit(G,pq.delMin());
}

}

//Add vertex v to the minimum spanning tree and update the data
private void visit(EdgeWeightedGraph G, int v) {
//Add vertex v to the minimum spanning tree
marked[v] = true;
//Update data
for (Edge e : G.adj(v)) {
//Get another vertex of edge e (current vertex is v)
int w = e.other(v);
//Judge whether another vertex is already in the tree. If it is in the tree, no processing will be done. If it is no longer in the tree, the data will be updated
if (marked[w]){
continue;
}

//Judge whether the weight of edge e is less than the weight from w vertex to the smallest edge already existing in the tree;
if (e.weight()<distTo[w]){
//Update data
edgeTo[w] = e;

distTo[w] = e.weight();

if (pq.contains(w)){
pq.changeItem(w,e.weight());
}else{
pq.insert(w,e.weight());
}

}

}

}

//Gets all edges of the minimum spanning tree
public Queue<Edge> edges() {
//Create queue object
//Traverse the edgeTo array to get each edge. If it is not null, it will be added to the queue
for (int i = 0; i < edgeTo.length; i++) {
if (edgeTo[i]!=null){
allEdges.offer(edgeTo[i]);
}
}
return allEdges;
}
}

```

## Test class  ```package graph.tu;

import java.util.Queue;

public class PrimMSTTest {
public static void main(String[] args) throws Exception{

//Prepare a weighted undirected graph
graph.tu.EdgeWeightedGraph G = new graph.tu.EdgeWeightedGraph(total);

for (int e = 1;e<=edgeNumbers;e++){
String line = br.readLine();//4 5 0.35

String[] strs = line.split(" ");

int v = Integer.parseInt(strs);
int w = Integer.parseInt(strs);

double weight = Double.parseDouble(strs);

//Building weighted undirected edges
Edge edge = new Edge(v, w, weight);

}

//Create a PrimMST object and calculate the minimum spanning tree in the weighted undirected graph
graph.tu.PrimMST primMST = new graph.tu.PrimMST(G);

//Gets all edges in the minimum spanning tree
Queue<Edge> edges = primMST.edges();

//Traverse and print all edges
for (Edge e : edges) {
int v = e.either();
int w = e.other(v);
double weight = e.weight();
System.out.println(v+"-"+w+" :: "+weight);

}

}
}

``` # kruskal Algorithm

## Main ideas:

#### The edges are processed according to their weights (from small to large), and the edges are added to the minimum spanning tree

• kruskal algorithm is another algorithm to calculate the minimum spanning tree of a weighted undirected graph. Its main idea is to deal with them according to the weight of edges (from small to large). The edges are added to the minimum spanning tree. The added edges will not form a ring with the edges that have been added to the minimum spanning tree until the tree contains V-1 edges.

## Differences between kruskal algorithm and prim algorithm:

• Prim algorithm constructs the minimum spanning tree one by one, and adds an edge to a tree at each step.
• kruskal algorithm constructs the minimum spanning tree side by side, but its segmentation rules are different. Every time it looks for the edge, it will connect two trees in a forest. If a weighted undirected graph is composed of V vertices, and each vertex forms an independent tree under initialization, then the V vertices correspond to V trees to form a forest. kruskal algorithm will merge the two trees into one tree every time until there is only one tree left in the whole forest. ## API design ## Implementation principle of kruskal algorithm

• When designing the API, a MinPriorityQueue pq is used to store all edges in the graph. Each time pq.delMin() is used to take out the edge with the smallest weight and obtain the two vertices V and W associated with the edge. uf.connect(v,w) is used to judge whether V and W are connected. If connected, it is proved that the two vertices are in the same tree, so this edge can no longer be added to the minimum spanning tree, Because adding an edge to any two vertices of a tree will form a ring, and the minimum spanning tree cannot have a ring. If it is not connected, the tree where vertex v is located and the tree where vertex W is located will be merged into a tree through uf.connect(v,w), and the edge will be added to the mst queue. In this way, if all edges are processed, Finally, all the edges of the minimum spanning tree are stored in mst.   ## Auxiliary class

#### 3.UF_Tree_Weighted -- union search set

```package graph.tu;

public class UF_Tree_Weighted {
//Record the node element and the identification of the group in which the element is located
private int[] eleAndGroup;
//Record and check the number of data groups in the set
private int count;

//It is used to store the number of nodes saved in the tree corresponding to each root node
private int[] sz;
//Initialize and query set
public UF_Tree_Weighted(int N){
//The number of initialization packets. By default, there are N packets
this.count = N;
//Initialize eleAndGroup array
this.eleAndGroup = new int[N];

//Initialize the element in eleAndGroup and the identifier of its group, make the index of eleAndGroup array as the element of each node of the query set, and make the value at each index (the identifier of the group in which the element is located) the index

for (int i = 0; i < eleAndGroup.length; i++) {
eleAndGroup[i] = i;
}

this.sz = new int[N];
//By default, the value at each index in sz is 1
for (int i = 0; i < sz.length; i++) {
sz[i] = 1;
}

}

//How many groups are there in the current query set
public int count(){
return count;
}

//Judge and check whether element p and element q in the set are in the same group
public boolean connected(int p,int q){
return find(p) == find(q);
}

//Identifier of the group in which the element p is located
public int find(int p){
while(true){

if (p == eleAndGroup[p]){
return p;
}

p = eleAndGroup[p];
}

}

//Merge the group of p element and the group of q element
public void union(int p,int q){
//Find the root node of the tree corresponding to the group of p and q elements

int pRoot = find(p);
int qRoot = find(q);

//If p and q are already in the same group, there is no need to merge
if (pRoot==qRoot){
return;
}

//To determine whether the tree size corresponding to proot or qroot is large, you need to merge the smaller trees into the larger trees

if (sz[pRoot]<sz[qRoot]){
eleAndGroup[pRoot] = qRoot;
sz[qRoot]+=sz[pRoot];
}else{
eleAndGroup[qRoot] = pRoot;
sz[pRoot]+= sz[qRoot];
}

//Number of groups - 1

this.count--;

}

}

```

## kruskal algorithm - KruskalMST

• PriorityQueue—java.util
```package graph.tu;

import java.util.PriorityQueue;
import java.util.Queue;

public class KruskalMST {
//Save all edges of the minimum spanning tree
private Queue<Edge> mst;
//The index represents the vertex. Use uf.connect(v,w) to judge whether vertex v and vertex W are in the same tree. Use uf.union(v,w) to merge the tree where vertex v and vertex W are located
private UF_Tree_Weighted uf;
//All edges in the graph are stored, and the edges are sorted by weight using the minimum priority queue
private Queue<Edge> pq;

//According to a weighted undirected graph, the minimum spanning tree calculation object is created
public KruskalMST(EdgeWeightedGraph G) {

//Initialize mst
//Initialize uf
this.uf = new UF_Tree_Weighted(G.V());
//Initialize pq
this.pq = new PriorityQueue<>(G.E()+1);
//Store all the edges in the graph in pq
for (Edge e : G.edges()) {
pq.offer(e);
}

//Traverse the pq queue, get the edge with the minimum weight, and process it

while(!pq.isEmpty() && mst.size()<G.V()-1){
//Find the edge with the least weight
Edge e = pq.poll();
//Find the two vertices of the edge
int v = e.either();
int w = e.other(v);

//Judge whether the two vertices are already in the same tree. If they are in the same tree, the edge will not be processed. If they are not in the same tree, the two trees to which the two vertices belong will be merged into one tree
if (uf.connected(v,w)){
continue;
}

uf.union(v,w);

//Get edge e into mst queue
mst.offer(e);

}

}

//Gets all edges of the minimum spanning tree
public Queue<Edge> edges() {
return mst;
}
}

```

Posted on Sun, 10 Oct 2021 01:26:11 -0400 by delboy1978uk