Kruskalův algoritmus minimálního Spanning Tree (MST).

Kruskalův algoritmus minimálního Spanning Tree (MST).

Minimální kostra (MST) nebo minimální hmotnostní kostra pro vážený, souvislý, neorientovaný graf je kostra s váhou menší nebo rovnou hmotnosti každé jiné kostry. Chcete-li se dozvědět více o minimálním Spanning Tree, viz tento článek .

Úvod do Kruskalova algoritmu:

Zde budeme diskutovat Kruskalův algoritmus najít MST daného váženého grafu.

V Kruskalově algoritmu seřaďte všechny hrany daného grafu ve vzestupném pořadí. Pak pokračuje v přidávání nových hran a uzlů v MST, pokud nově přidaná hrana netvoří cyklus. Nejprve vybere minimální váženou hranu a nakonec maximální váženou hranu. Můžeme tedy říci, že v každém kroku provádí lokálně optimální volbu, aby nalezl optimální řešení. Toto je tedy a Níže jsou uvedeny kroky pro nalezení MST pomocí Kruskalova algoritmu:

  1. Seřaďte všechny hrany v neklesajícím pořadí podle jejich hmotnosti.
  2. Vyberte nejmenší okraj. Zkontrolujte, zda tvoří cyklus s dosud vytvořeným kostrou. Pokud cyklus není vytvořen, zahrňte tuto hranu. Jinak to zahoď.
  3. Opakujte krok č. 2, dokud nebudou v kostrě (V-1) hrany.

Krok 2 používá Algoritmus Union-Find k detekci cyklů.

Doporučujeme tedy jako předpoklad přečíst následující příspěvek.

  • Algoritmus Union-Find | Sada 1 (detekce cyklu v grafu)
  • Algoritmus Union-Find | Sada 2 (Sjednocení podle pořadí a komprese cesty)

Kruskalův algoritmus k nalezení stromu minimálních nákladů používá chamtivý přístup. Greedy Choice je vybrat nejmenší závaží, které nezpůsobuje cyklus v MST, který byl dosud vytvořen. Pojďme to pochopit na příkladu:

Ilustrace:

Níže je ilustrace výše uvedeného přístupu:

Vstupní graf:

Kruskalův minimální algoritmus Spanning Tree

Graf obsahuje 9 vrcholů a 14 hran. Minimální vytvořená kostra tedy bude mít (9 – 1) = 8 hran.
Po třídění:

Hmotnost Zdroj Destinace
1 7 6
2 8 2
2 6 5
4 0 1
4 2 5
6 8 6
7 2 3
7 7 8
8 0 7
8 1 2
9 3 4
10 5 4
jedenáct 1 7
14 3 5

Nyní postupně vyberte všechny hrany ze seřazeného seznamu hran

Krok 1: Vyberte hranu 7-6. Nevytváří se žádný cyklus, zahrňte ho.

Přidejte hranu 7-6 v MST

Přidejte hranu 7-6 v MST

Krok 2: Vyberte hranu 8-2. Nevytváří se žádný cyklus, zahrňte ho.

Přidejte hranu 8-2 v MST

Přidejte hranu 8-2 v MST

Krok 3: Vyberte hranu 6-5. Nevytváří se žádný cyklus, zahrňte ho.

Přidejte hranu 6-5 v MST

Přidejte hranu 6-5 v MST

Krok 4: Vyberte hranu 0-1. Nevytváří se žádný cyklus, zahrňte ho.

Přidejte hranu 0-1 v MST

Přidejte hranu 0-1 v MST

Krok 5: Vyberte okraj 2-5. Nevytváří se žádný cyklus, zahrňte ho.

Přidejte hranu 0-1 v MST

Přidejte hranu 2-5 v MST

Krok 6: Vyberte hranu 8-6. Protože zahrnutí této hrany vede do cyklu, zahoďte ji. Vyberte okraj 2-3: Nevytváří se žádný cyklus, zahrňte ho.

Přidejte hranu 2-3 v MST

Přidejte hranu 2-3 v MST

Krok 7: Vyberte hranu 7-8. Protože zahrnutí této hrany vede do cyklu, zahoďte ji. Vyberte hranu 0-7. Nevytváří se žádný cyklus, zahrňte ho.

Přidejte hranu 0-7 v MST

Přidejte hranu 0-7 v MST

Krok 8: Vyberte hranu 1-2. Protože zahrnutí této hrany vede do cyklu, zahoďte ji. Vyberte okraj 3-4. Nevytváří se žádný cyklus, zahrňte ho.

Přidejte hranu 3-4 v MST

Přidejte hranu 3-4 v MST

Poznámka: Protože počet hran zahrnutých v MST je roven (V – 1), algoritmus se zde zastaví

Níže je uvedena implementace výše uvedeného přístupu:

C++




// C++ program for the above approach> > #include> using> namespace> std;> > // DSU data structure> // path compression + rank by union> class> DSU {> > int> * parent;> > int> * rank;> > public> :> > DSU(> int> n)> > {> > parent => new> int> [n];> > rank => new> int> [n];> > > for> (> int> i = 0; i parent[i] = -1; rank[i] = 1; } } // Find function int find(int i) { if (parent[i] == -1) return i; return parent[i] = find(parent[i]); } // Union function void unite(int x, int y) { int s1 = find(x); int s2 = find(y); if (s1 != s2) { if (rank[s1] parent[s1] = s2; } else if (rank[s1]>hodnost[s2]) { rodič[s2] = s1; } else { rodič[s2] = s1; pořadí[s1] += 1; } } } }; class Graph { vectorint>> edgelist; int V; public: Graph(int V) { this->V = V; } // Funkce pro přidání hrany do grafu void addEdge(int x, int y, int w) { edgelist.push_back({ w, x, y }); } void kruskals_mst() { // Seřadit všechny hrany sort(edgelist.begin(), edgelist.end()); // Inicializace DSU DSU s(V); int ans = 0; cout < < 'Following are the edges in the ' 'constructed MST' < < endl; for (auto edge : edgelist) { int w = edge[0]; int x = edge[1]; int y = edge[2]; // Take this edge in MST if it does // not forms a cycle if (s.find(x) != s.find(y)) { s.unite(x, y); ans += w; cout < < x < < ' -- ' < < y < < ' == ' < < w < < endl; } } cout < < 'Minimum Cost Spanning Tree: ' < < ans; } }; // Driver code int main() { Graph g(4); g.addEdge(0, 1, 10); g.addEdge(1, 3, 15); g.addEdge(2, 3, 4); g.addEdge(2, 0, 6); g.addEdge(0, 3, 5); // Function call g.kruskals_mst(); return 0; }>

C




// C code to implement Kruskal's algorithm> > #include> #include> > // Comparator function to use in sorting> int> comparator(> const> void> * p1,> const> void> * p2)> {> > const> int> (*x)[3] = p1;> > const> int> (*y)[3] = p2;> > > return> (*x)[2] - (*y)[2];> }> > // Initialization of parent[] and rank[] arrays> void> makeSet(> int> parent[],> int> rank[],> int> n)> {> > for> (> int> i = 0; i parent[i] = i; rank[i] = 0; } } // Function to find the parent of a node int findParent(int parent[], int component) { if (parent[component] == component) return component; return parent[component] = findParent(parent, parent[component]); } // Function to unite two sets void unionSet(int u, int v, int parent[], int rank[], int n) { // Finding the parents u = findParent(parent, u); v = findParent(parent, v); if (rank[u] parent[u] = v; } else if (rank[u]>hodnost[v]) { rodič[v] = u; } else { rodič[v] = u; // Vzhledem k tomu, že se hodnost zvyšuje, // hodnosti dvou sad jsou stejné rank[u]++; } } // Funkce pro nalezení MST void kruskalAlgo(int n, int hrana[n][3]) { // Nejprve seřadíme pole hran ve vzestupném pořadí //, abychom měli přístup k minimální vzdálenosti/ceně qsort(edge , n, sizeof(hrana[0]), komparátor); int rodič[n]; int hodnost[n]; // Funkce pro inicializaci parent[] a rank[] makeSet(parent, rank, n); // Pro uložení minimálních nákladů int minCost = 0; printf( 'Následují hrany ve zkonstruovaném MST '); for (int i = 0; i int v1 = najít rodiče(rodič, hrana[i][0]); int v2 = najít nadřazený(rodič, hrana[i][1]); int wt = hrana[i][2] ; // Pokud jsou rodiče různí, // znamená, že jsou v různých množinách, tak // sjednoťte je if (v1 != v2) { minCost += wt; '%d -- %d == %d ', hrana[i][0], hrana[i][1], wt } } printf('Strom minimálních nákladů: %d); n', minCost } // Kód ovladače int main() { int okraj[5][3] = { { 0, 1, 10 }, { 0, 2, 6 }, { 0, 3, 5 } , { 1, 3, 15 }, { 2, 3, 4 } }; kruskalAlgo(5, hrana 0;

>   




// Java program for Kruskal's algorithm> > import> java.util.ArrayList;> import> java.util.Comparator;> import> java.util.List;> > public> class> KruskalsMST {> > > // Defines edge structure> > static> class> Edge {> > int> src, dest, weight;> > > public> Edge(> int> src,> int> dest,> int> weight)> > {> > this> .src = src;> > this> .dest = dest;> > this> .weight = weight;> > }> > }> > > // Defines subset element structure> > static> class> Subset {> > int> parent, rank;> > > public> Subset(> int> parent,> int> rank)> > {> > this> .parent = parent;> > this> .rank = rank;> > }> > }> > > // Starting point of program execution> > public> static> void> main(String[] args)> > {> > int> V => 4> ;> > List graphEdges => new> ArrayList(> > List.of(> new> Edge(> 0> ,> 1> ,> 10> ),> new> Edge(> 0> ,> 2> ,> 6> ),> > new> Edge(> 0> ,> 3> ,> 5> ),> new> Edge(> 1> ,> 3> ,> 15> ),> > new> Edge(> 2> ,> 3> ,> 4> )));> > > // Sort the edges in non-decreasing order> > // (increasing with repetition allowed)> > graphEdges.sort(> new> Comparator() {> > @Override> public> int> compare(Edge o1, Edge o2)> > {> > return> o1.weight - o2.weight;> > }> > });> > > kruskals(V, graphEdges);> > }> > > // Function to find the MST> > private> static> void> kruskals(> int> V, List edges)> > {> > int> j => 0> ;> > int> noOfEdges => 0> ;> > > // Allocate memory for creating V subsets> > Subset subsets[] => new> Subset[V];> > > // Allocate memory for results> > Edge results[] => new> Edge[V];> > > // Create V subsets with single elements> > for> (> int> i => 0> ; i subsets[i] = new Subset(i, 0); } // Number of edges to be taken is equal to V-1 while (noOfEdges 1) { // Pick the smallest edge. And increment // the index for next iteration Edge nextEdge = edges.get(j); int x = findRoot(subsets, nextEdge.src); int y = findRoot(subsets, nextEdge.dest); // If including this edge doesn't cause cycle, // include it in result and increment the index // of result for next edge if (x != y) { results[noOfEdges] = nextEdge; union(subsets, x, y); noOfEdges++; } j++; } // Print the contents of result[] to display the // built MST System.out.println( 'Following are the edges of the constructed MST:'); int minCost = 0; for (int i = 0; i System.out.println(results[i].src + ' -- ' + results[i].dest + ' == ' + results[i].weight); minCost += results[i].weight; } System.out.println('Total cost of MST: ' + minCost); } // Function to unite two disjoint sets private static void union(Subset[] subsets, int x, int y) { int rootX = findRoot(subsets, x); int rootY = findRoot(subsets, y); if (subsets[rootY].rank subsets[rootY].parent = rootX; } else if (subsets[rootX].rank subsets[rootX].parent = rootY; } else { subsets[rootY].parent = rootX; subsets[rootX].rank++; } } // Function to find parent of a set private static int findRoot(Subset[] subsets, int i) { if (subsets[i].parent == i) return subsets[i].parent; subsets[i].parent = findRoot(subsets, subsets[i].parent); return subsets[i].parent; } } // This code is contributed by Salvino D'sa>

Python3




# Python program for Kruskal's algorithm to find> # Minimum Spanning Tree of a given connected,> # undirected and weighted graph> > > # Class to represent a graph> class> Graph:> > > def> __init__(> self> , vertices):> > self> .V> => vertices> > self> .graph> => []> > > # Function to add an edge to graph> > def> addEdge(> self> , u, v, w):> > self> .graph.append([u, v, w])> > > # A utility function to find set of an element i> > # (truly uses path compression technique)> > def> find(> self> , parent, i):> > if> parent[i] !> => i:> > > # Reassignment of node's parent> > # to root node as> > # path compression requires> > parent[i]> => self> .find(parent, parent[i])> > return> parent[i]> > > # A function that does union of two sets of x and y> > # (uses union by rank)> > def> union(> self> , parent, rank, x, y):> > > # Attach smaller rank tree under root of> > # high rank tree (Union by Rank)> > if> rank[x] parent[x] = y elif rank[x]>rank[y]: parent[y] = x # Pokud jsou hodnosti stejné, pak udělejte jedničku jako kořen # a zvyšte její hodnost o jednu další: parent[y] = x hodnost[x] += 1 # Hlavní funkce, kterou chcete sestavit MST # pomocí Kruskalova algoritmu def KruskalMST(self): # Tím se uloží výsledný výsledek MST = [] # Indexová proměnná, použitá pro seřazené hrany i = 0 # Indexová proměnná, použitá pro výsledek[] e = 0 # Seřaďte všechny hrany v # neklesajícím pořadí podle # jejich váhy self.graph = sorted(self.graph, key=lambda item: item[2]) parent = [] rank = [] # Vytvořte V podmnožiny s jednotlivými prvky for node in range(self.V): parent.append(node) rank.append(0) # Počet hran, které se mají vzít, je menší než V-1, zatímco e

C#




// C# Code for the above approach> > using> System;> > class> Graph {> > > // A class to represent a graph edge> > class> Edge : IComparable {> > public> int> src, dest, weight;> > > // Comparator function used for sorting edges> > // based on their weight> > public> int> CompareTo(Edge compareEdge)> > {> > return> this> .weight - compareEdge.weight;> > }> > }> > > // A class to represent> > // a subset for union-find> > public> class> subset {> > public> int> parent, rank;> > };> > > // V->Ne. vrcholů & E->počet hran> > int> V, E;> > > // Collection of all edges> > Edge[] edge;> > > // Creates a graph with V vertices and E edges> > Graph(> int> v,> int> e)> > {> > V = v;> > E = e;> > edge => new> Edge[E];> > for> (> int> i = 0; i edge[i] = new Edge(); } // A utility function to find set of an element i // (uses path compression technique) int find(subset[] subsets, int i) { // Find root and make root as // parent of i (path compression) if (subsets[i].parent != i) subsets[i].parent = find(subsets, subsets[i].parent); return subsets[i].parent; } // A function that does union of // two sets of x and y (uses union by rank) void Union(subset[] subsets, int x, int y) { int xroot = find(subsets, x); int yroot = find(subsets, y); // Attach smaller rank tree under root of // high rank tree (Union by Rank) if (subsets[xroot].rank subsets[xroot].parent = yroot; else if (subsets[xroot].rank>subsets[yroot].rank) subsets[yroot].parent = xroot; // Pokud jsou hodnosti stejné, udělejte jednu jako root // a zvyšte její hodnost o jednu else { subsets[yroot].parent = xroot; subsets[xroot].rank++; } } // Hlavní funkce pro konstrukci MST // pomocí Kruskalova algoritmu void KruskalMST() { // Toto uloží // výsledný výsledek MST Edge[] = new Edge[V]; // Proměnná indexu, použitá pro result[] int e = 0; // Proměnná indexu, používaná pro seřazené hrany int i = 0; for (i = 0; i result[i] = new Edge(); // Seřadit všechny hrany v neklesajícím // pořadí jejich váhy. Pokud nám není dovoleno // daný graf změnit, můžeme vytvořit // kopie pole hran Array.Sort(edge) // Alokace paměti pro vytvoření V subsets subset[] subsets = new subset[V] for (i = 0; i subsets[i] = new subset(); ; // Vytvořte V podmnožiny s jednotlivými prvky pro (int v = 0; v podmnožiny[v].rodič = v; podmnožiny[v].rank = 0; } i = 0; // Počet hran, které se mají vzít, je stejný na V-1 while (e // Vyberte nejmenší hranu. A inkrementujte // index pro další iteraci Edge next_edge = new Edge(); next_edge = edge[i++]; int x = find(subsets, next_edge.src); int y = find(subsets, next_edge.dest) // Pokud zahrnutí této hrany nezpůsobí cyklus, // zahrnout ji do výsledku a zvýšit index // výsledku pro další hranu if (x != y) {); result[e++] = next_edge (subsets, x, y) // Vytiskne obsah result[] pro zobrazení // sestavené konzoly MST.WriteLine('Následují okraje v ' + '); vytvořený MST'); int minimální náklady = 0; for (i = 0; i Console.WriteLine(result[i].src + ' -- ' + result[i].dest + ' == ' + result[i].weight); minimumCost += result[i].weight } Console.WriteLine('Strom minimálních nákladů: ' + minimumCost Console.ReadLine( } // Kód řidiče public static void Main(String[] args)); int V = 4; int E = 5; graf grafu = new Graph(V, E); graf.hrana[0].váha = 10; // přidat hranu 0-2 graf.hrana[1].src = 0; ; // přidání hrany 0-3 graf.hrana[2].src = 0;graf.hrana[2].dest = 3 graf.hrana[2].váha = 5; hrana[3].src = 1;graf.hrana[3].src = 3; .edge[4].dest = 3; graph.edge[4].weight = 4; // Volání funkce graph.KruskalMST( } } // Tento kód přispěl Aakash Hasija>'>;

>   




> // JavaScript implementation of the krushkal's algorithm.> > function> makeSet(parent,rank,n)> {> > for> (let i=0;i { parent[i]=i; rank[i]=0; } } function findParent(parent,component) { if(parent[component]==component) return component; return parent[component] = findParent(parent,parent[component]); } function unionSet(u, v, parent, rank,n) { //this function unions two set on the basis of rank //as shown below u=findParent(parent,u); v=findParent(parent,v); if(rank[u] { parent[u]=v; } else if(rank[u] { parent[v]=u; } else { parent[v]=u; rank[u]++;//since the rank increases if the ranks of two sets are same } } function kruskalAlgo(n, edge) { //First we sort the edge array in ascending order //so that we can access minimum distances/cost edge.sort((a, b)=>{ return a[2] - b[2]; }) //vestavěná funkce rychlého třídění je součástí stdlib.h //přejděte na https://www.techcodeview.com Třídění hran trvá O(E * logE) čas. Po seřazení iterujeme přes všechny hrany a aplikujeme algoritmus find-union. Operace hledání a sjednocení mohou trvat maximálně O(logV) času. Celková složitost je tedy čas O(E * logE + E * logV). Hodnota E může být nejvýše O(V2), takže O(logV) a O(logE) jsou stejné. Celková časová složitost je tedy O(E * logE) nebo O(E*logV) Pomocný prostor: O(V + E), kde V je počet vrcholů a E je počet hran v grafu. Tento článek sestavil Aashish Barnwal a zkontroloval ho tým techcodeview.com. >