Data structures and algorithms 10 weighted graphs

Source: Internet
Author: User

Data structures and algorithms 10 weighted graphs

In the previous section, we have seen that the edge of the graph can have a direction. In this section, we will discuss another feature of the edge: weight. For example, if the vertex with a weight map represents a city, the edge weight may represent a distance between cities, a toll between cities, or a traffic flow between cities.

The bottom of a weighted graph is still a graph. The basic operations of those graphs in the previous section, such as the breadth-first search and depth-first search, are the same. In this section, we will mainly discuss the Shortest Path of the minimum spanning tree with a weight graph.

Minimum Spanning Tree

First, we will discuss the problem of the minimum spanning tree, which is different from the Minimum Spanning Tree mentioned in the previous section. The minimal spanning tree in the previous section is a special case, that is, the weights of all edges are the same. How to design algorithms? We recommend that you use the priority queue to implement the path with the smallest choice repeatedly, instead of the linked list or array, which is an effective way to solve the problem of the Minimum Spanning Tree. In a formal program, Priority Queues may be implemented based on heap, which speeds up operations in a large priority queue. However, in this example, we use arrays to implement priority queues, just to illustrate the algorithm. The algorithm highlights are as follows:

From a vertex, place it in the set of the tree, and then repeat the following:

1. Find all edges from the latest vertex to other vertex. These vertices cannot be placed in the priority queue in the set of trees.

2. Find the edge with the smallest weight value and place it and the vertex it reaches into the set of the tree.

Repeat these steps until all vertices are in the set of trees.

Next, let's take a look at the minimum spanning tree code and then explain some details:
// The boundary path class mainly records the vertex at the beginning and end of the Edge, and the weight value of the Edge class Edge {public int srcVert; // index of vertex starting edgepublic int destVert; // index of vertex ending edgepublic int distance; // distance from src to destpublic Edge (int sv, int dv, int d) {srcVert = sv; destVert = dv; distance = d ;}// custom priority queue, used to store Edge class PriorityQ {private final int SIZE = 20; private Edge [] queArray; // The private int size of the array storing the boundary; public PriorityQ () {queAr Ray = new Edge [SIZE]; size = 0;} public void insert (Edge item) {// ordered insert boundary int j; for (j = 0; j <size; j ++) {// locate the insert position, from 0 to size-1, and gradually decrease if (item. distance> = queArray [j]. distance) break;} // compare to item. distance moves one digit in the future to free up space for (int k = size-1; k> = j; k --) {queArray [k + 1] = queArray [k];} queArray [j] = item; // insert itemsize ++;} public Edge removeMin () {// Delete the smallest boundary and return queArray [-- size];} public void removeN (int n ){ // Delete the boundary for (int j = n; j <size-1; j ++) {queArray [j] = queArray [j + 1];} size --;} public Edge peekMin () {// returns the minimum boundary. Do not delete return queArray [size-1];} public Edge peekN (int n) {// return the return queArray [n];} public int size () {return size;} public boolean isEmpty () {return (size = 0 );} public int find (int findDex) {// search for the boundary index of a specific disVert for (int j = 0; j <size; j ++) {if (queArray [j]. destVert = findDex) return j;} Return-1 ;}}// public class WeightedGraph with weight graph {private final int MAX_VERTS = 20; // maximum number of vertices private final int INFINITY = 100000; // The longest distance... private Vertex [] vertexArray cannot be reached; // an array that stores vertices. private int adjMat [] []; // stores the boundary private int nVerts between vertices; // Number of vertices private int currentVert; // current vertex index private PriorityQ thePQ; // storage edge priority queue private int nTree; // Number of vertices in the Minimum Spanning Tree public WeightedGraph () {vertexArray = new Vertex [MAX_VERTS]; AdjMat = new int [MAX_VERTS] [MAX_VERTS]; for (int I = 0; I <MAX_VERTS; I ++) {for (int j = 0; j <MAX_VERTS; j ++) {adjMat [I] [j] = INFINITY; // Initialize all boundary INFINITY} thePQ = new PriorityQ ();} public void addVertex (char lab) {// Add Vertex vertexArray [nVerts ++] = new Vertex (lab);} public void addEdge (int start, int end, int weight) {// Add an adjMat [start] [end] = weight; adjMat [end] [start] = weight;} public void displayVertex (Int v) {System. out. print (vertexArray [v]. label);}/** the minimum spanning tree with a weight graph. Select an optimal path */public void MinSpanningTree () {currentVert = 0; // start from 0 while (nTree <nVerts-1) {// when not all nodes are in the minimal spanning tree // isInTree is the member variable private boolean isInTree added to the Vertex class in the previous section; // indicates whether the node is added to the tree, initialize to falsevertexArray [currentVert]. isInTree = true; // Add the current vertex to the tree nTree ++; // insert some adjacent boundary to the PQ for (int I = 0; I <nVerts; I ++) {if (I = currentVert) // if it is the current vertex, jump out of c Ontinue; if (vertexArray [I]. isInTree) // If vertex I is already in the tree, jump out of continue; int distance = adjMat [currentVert] [I]; // calculate the distance from the current vertex to the I vertex if (distance = INFINITY) continue; // if the current vertex is infinitely far from the I vertex, it jumps out of putInPQ (I, distance ); // Add the I node to the PQ} if (thePQ. size () = 0) {// If PQ is null, the graph is not connected to System. out. println ("Graph not connected! "); Return;} Edge theEdge = thePQ. removeMin (); int sourceVert = theEdge. srcVert; currentVert = theEdge. destVert; System. out. print (vertexArray [sourceVert]. label); System. out. print (vertexArray [currentVert]. label); System. out. print ("") ;}} private void putInPQ (int newVert, int newDist) {int queueIndex = thePQ. find (newVert); // determines whether the PQ has a boundary to the same target vertex if (queueIndex! =-1) {// compare the distance from the current vertex to the target vertex if any, and retain the shorter Edge tempEdge = thePQ. peekN (queueIndex); // get edgeint oldDist = tempEdge. distance; if (oldDist> newDist) {// thePQ if the new boundary is shorter. removeN (queueIndex); // Delete the old boundary Edge theEdge = new Edge (currentVert, newVert, newDist); thePQ. insert (theEdge) ;}} else {// If PQ does not reach the Edge of the same target vertex, theEdge = new Edge (currentVert, newVert, newDist); thePQ. insert (theEdge); // directly add to PQ }}}

The algorithm is executed in the while loop. The loop end condition is that all vertices are in the tree.

1. Place the current vertex in the tree.

2. Place the edges connecting the vertex in the priority queue (if appropriate ).

3. Delete the edge with the smallest weight from the priority queue. The destination vertex of this edge changes to the current vertex.

Let's take a look at the details of these steps: 1. By marking the isInTree field of the vertex referred to by currentVert, the vertex is placed in the tree, 2, and the edge connecting the vertex is inserted into the priority queue. Scan the row with the row number currentVert in the adjacent matrix to find the desired edge. As long as any of the following conditions is true, this edge cannot be placed in the queue:

1. The source and end points are the same;

2. The destination is in the tree;

3. There is no edge between the source point and the end point (the value in the adjacent matrix is equal to infinity ).

If no condition is true, call the putInPQ () method to put this edge in the queue. In fact, this edge is not necessarily placed in the queue, and you have to make a judgment. In step 3, remove the edge of the minimum weight from the priority queue. Add the key of this edge to the tree and display the source and end points.

Finally, the isInTree variables of all vertices are reset, that is, deleted from the tree. This is because only one tree can be created based on the data. After completing a task, we 'd better restore the data to the original form.

Next we will discuss the shortest path problem:

Shortest Path

The most common problem in a weighted graph is to find the shortest path between two points. The solution to this problem can be applied to many places in real life. However, it is more complicated than the previous problems. The method proposed to solve the shortest path problem is called the Djikstra algorithm. The implementation of this algorithm is based on the graph's Adjacent matrix representation. It not only finds the shortest path between any two points, but also finds the shortest path from a specified point to all other vertices.

To implement this algorithm, you must first create a DistPar class, which encapsulates the distance to the initial vertex and the information of the parent vertex.
// The DistPar class records the distance from the current vertex to the start vertex and the parent vertex class DistPar {public int distance; // distance from start to this vertexpublic int parentVert; // current parent of this vertexpublic DistPar (int pv, int d) {distance = d; parentVert = pv ;}}
An array is also required, which is a key data structure in the shortest path algorithm. It maintains the shortest path from the source point to other vertices (endpoints. The distance changes during Algorithm Execution. Knowing that, at the end, it stores the Real Shortest Distance starting from the source point. This array is defined as a private member variable of WeightedGraph:
Private DistPar [] sPath; // stores Shortest Path data and stores the preceding DistPar object private int startToCurrent; // distance from the current vertex

In addition, you need to initialize it in the constructor: sPath =NewDistPar [MAX_VERTS];

The following is a detailed analysis of the methods involved in the shortest path algorithm. These are all methods in the WeightedGraph class. Here I will extract the analysis, and I will attach the complete WeightedGraph class code.

********** * ***************** // **** Path () method to execute the true shortest path algorithm. */Public void path () {// find all Shortest Paths/** the total number of source points is 0 in the vertexArray [] array subscript, path () the first task of the method is to put this vertex into the tree. * During Algorithm Execution, other vertices are also placed in the tree. The operation to put the vertex in the tree is to set the flag. * Add the nTree variable to 1, which records the number of vertices in the tree. */Int startTree = 0; // vertexArray [startTree] Starting from vertex 0. isInTree = true; nTree = 1;/** path () method copies the distance expressed by the corresponding row of the adjacent matrix to sPath, actually, we always copy data from the first row * to make it simple, assuming that the subscript of the source point is always 0. At the beginning, the parent node field in all sPath [] arrays is A, that is, the Source Vertex. */For (int I = 0; I <nVerts; I ++) {int tempDist = adjMat [startTree] [I]; // The distance saved in sPath is the distance from the initial vertex. Therefore, the parent vertex is the initial vertex by default, and the sPath [I] = new DistPar (startTree, tempDist);}/** now enters the main cycle. When all vertices are placed in the tree, the cycle ends. This cycle has three basic actions: * 1. select the minimum distance in the sPath [] array * 2. place the corresponding vertex (the topic of the column with the minimum distance) into the tree, and the vertex becomes "current vertex" currentVert * 3. update all the sPath [] array content */while (nTree <nVerts) {// 1 according to the changes in currentVert. select int indexMin = getMin () from the sPath [] array. // obtain Int minDist = sPath [indexMin]. distance; // obtain the minimum path if (minDist = INFINITY) {System. out. println ("There are unreachable vertices"); break;} // 2. place the corresponding vertex (the topic of the column with the minimum distance) into the tree and the vertex becomes "current vertex" currentVertelse {// reset currentVertcurrentVert = indexMin; startToCurrent = sPath [indexMin]. distance;} vertexArray [currentVert]. isInTree = true; nTree ++; // 3. update the adjust_sPath ();} disp content of all sPath [] arrays based on changes in currentVert. LayPaths (); nTree = 0; for (int I = 0; I <nVerts; I ++) {vertexArray [I]. isInTree = false ;}}// obtain the index private int getMin () {int minDist = INFINITY; int indexMin = 0; for (int I = 0; I <nVerts; I ++) {if (! VertexArray [I]. isInTree & sPath [I]. distance <minDist) {minDist = sPath [I]. distance; indexMin = I;} return indexMin;}/* adjust the value of the object stored in sPath, that is, the distance from the vertex to the initial vertex, and the parent vertex * this is the core of the Dijkstra algorithm */private void adjust_sPath () {int column = 1; while (column <nVerts) {if (vertexArray [column]. isInTree) {column ++; continue;} int currentToFringe = adjMat [currentVert] [column]; // obtain the distance from the current vertex to other vertex, other vertices do not meet isInTreeint startToFringe = startToCurrent + currentToFringe; // calculate the distance from other vertices to the initial vertex = the distance from the current vertex to the initial vertex + the distance from the current vertex to other vertices int sPathDist = sPath [column]. distance; // obtain the distance from the vertex at the column to the starting vertex. if it is not adjacent to the initial vertex, the default value is infinite if (startToFringe <sPathDist) {sPath [column]. parentVert = currentVert; // modify the parent vertex sPath [column]. distance = startToFringe; // and the distance to the initial vertex} column ++ ;}// display path private void displayPaths () {for (int I = 0; I <nVerts; I ++) {System. out. print (vertexArray [I]. label + "="); if (sPath [I]. distance = INFINITY) System. out. print ("infinity"); elseSystem. out. print (sPath [I]. distance); char parent = vertexArray [sPath [I]. parentVert]. label; System. out. print ("(" + parent + ")");} System. out. println ("");}

There are two types of graph representations: the adjacent matrix and the adjacent table. Yes, the algorithm efficiency of the graph becomes more complex. If an adjacent matrix is used, most of the algorithms discussed earlier require O (V2) time, and V indicates the number of vertices. These algorithms check almost all vertices. The specific method is to scan each row in the adjacent matrix and view each edge at a time. In other words, the V2 units of the adjacent matrix have been scanned.

For large-scale matrices, O (V2) Time is basically very good performance. If the graph is dense, there is no room for improving the performance (dense means that the graph has many edges, and many or most of its adjacent matrices are occupied ). However, many graphs are sparse, but there is no definite number of definitions to indicate how many sides the graph is dense or sparse, however, if in a large graph, each vertex is connected with only a few sides, the graph is generally considered sparse.

In a sparse graph, using the representation of the adjacent table instead of the adjacent matrix can improve the running time, because it does not have to waste time to retrieve the cells without edges in the adjacent matrix. For a no-Permission graph, the deep search of the adjacent table requires O (V + E) time, V indicates the number of vertices, and E indicates the number of edges. For a weighted graph, the Minimum Spanning Tree Algorithm and the shortest path algorithm both require O (E + V) logV) time. In a large-scale sparse graph, compared with the time level O (V2) of the adjacent matrix method, such time level can greatly improve the performance, but the algorithm is more complex. Complete codeThe complete code and test code with the permission diagram are attached below
Package graph;/*** @ desciption complete code with a weight graph * @ author eson_15 * // class Edge of the boundary path {public int srcVert; // index of vertex starting edgepublic int destVert; // index of vertex ending edgepublic int distance; // distance from src to destpublic Edge (int sv, int dv, int d) {srcVert = sv; destVert = dv; distance = d ;}}// priority queue class PriorityQ {private final int SIZE = 20; private Edge [] queArray; // The array private I that stores the Boundary Nt size; public PriorityQ () {queArray = new Edge [SIZE]; size = 0;} public void insert (Edge item) {// ordered insert boundary int j; for (j = 0; j <size; j ++) {// locate the insert position, from 0 to size-1, and gradually decrease if (item. distance> = queArray [j]. distance) break;} // compare to item. distance moves one digit in the future to free up space for (int k = size-1; k> = j; k --) {queArray [k + 1] = queArray [k];} queArray [j] = item; // insert itemsize ++;} public Edge removeMin () {// Delete the smallest boundary and return queArray [-- siz E];} public void removeN (int n) {// Delete the boundary of n positions for (int j = n; j <size-1; j ++) {queArray [j] = queArray [j + 1];} size --;} public Edge peekMin () {// returns the minimum boundary, do not delete return queArray [size-1];} public Edge peekN (int n) {// return the boundary of n position return queArray [n];} public int size () {return size;} public boolean isEmpty () {return (size = 0);} public int find (int findDex) {// SEARCH for the edge index of a specific disVert for (int j = 0; j <size; j ++) {if (queArray [J]. destVert = findDex) return j;} return-1 ;}} // The DistPar class records the distance from the current vertex to the start vertex and the parent vertex class DistPar {public int distance; // distance from start to this vertexpublic int parentVert; // current parent of this vertexpublic DistPar (int pv, int d) {distance = d; parentVert = pv ;}} // public class WeightedGraph {private final int MAX_VERTS = 20; // maximum number of private final int INFINITY = 100000; // The longest distance... indicates that the priv cannot be reached. Ate Vertex [] vertexArray; // an array for storing vertices private int adjMat [] []; // stores the boundary private int nVerts between vertices; // Number of vertices private int currentVert; // The current vertex index private PriorityQ thePQ; // private int nTree; // The number of vertices in the Minimum Spanning Tree private DistPar [] sPath; // stores the shortest path data private int startToCurrent; // The distance from the current Vertex to public WeightedGraph () {vertexArray = new Vertex [MAX_VERTS]; adjMat = new int [MAX_VERTS] [MAX_VERTS]; for (int I = 0; I <MAX_VERTS; I ++) {( Int j = 0; j <MAX_VERTS; j ++) {adjMat [I] [j] = INFINITY; // Initialize all boundaries infinitely far} thePQ = new PriorityQ (); sPath = new DistPar [MAX_VERTS];} public void addVertex (char lab) {// Add Vertex vertexArray [nVerts ++] = new Vertex (lab );} public void addEdge (int start, int end, int weight) {// Add an adjMat [start] [end] = weight; adjMat [end] [start] = weight; // This sentence is not required for Optimal Path} public void displayVertex (int v) {System. out. print (vertexAr Ray [v]. label );} /************************ minimum spanning tree with a weight map ******** * *****************/public void MinSpanningTree () {currentVert = 0; // start from 0 while (nTree <nVerts-1) {// vertexArray [currentVert] when not all nodes are in the Minimal build tree. isInTree = true; // Add the current vertex to the tree nTree ++; // insert some adjacent boundary to the PQ for (int I = 0; I <nVerts; I ++) {if (I = currentVert) // if it is the current vertex, jump out of continue; if (vertexArray [I]. isInTree) // If vertex I is already in the tree, jump out of continue; int distance = AdjMat [currentVert] [I]; // calculate the distance from the current vertex to the I vertex if (distance = INFINITY) continue; // if the current vertex is infinitely far from the I vertex, jump out of putInPQ (I, distance); // Add I to PQ} if (thePQ. size () = 0) {// If PQ is null, the graph is not connected to System. out. println ("Graph not connected! "); Return;} Edge theEdge = thePQ. removeMin (); int sourceVert = theEdge. srcVert; currentVert = theEdge. destVert; System. out. print (vertexArray [sourceVert]. label); System. out. print (vertexArray [currentVert]. label); System. out. print ("") ;}} private void putInPQ (int newVert, int newDist) {int queueIndex = thePQ. find (newVert); // determines whether the PQ has a boundary to the same target vertex if (queueIndex! =-1) {// compare the distance from the current vertex to the target vertex if any, and retain the shorter Edge tempEdge = thePQ. peekN (queueIndex); // get edgeint oldDist = tempEdge. distance; if (oldDist> newDist) {// thePQ if the new boundary is shorter. removeN (queueIndex); // Delete the old boundary Edge theEdge = new Edge (currentVert, newVert, newDist); thePQ. insert (theEdge) ;}} else {// If PQ does not reach the Edge of the same target vertex, theEdge = new Edge (currentVert, newVert, newDist); thePQ. insert (theEdge); // directly add to PQ }}/******************** ****************************//* ** Path () method to execute the true shortest path algorithm. */Public void path () {// find all Shortest Paths/** the total number of source points is 0 in the vertexArray [] array subscript, path () the first task of the method is to put this vertex into the tree. * During Algorithm Execution, other vertices are also placed in the tree. The operation to put the vertex in the tree is to set the flag. * Add the nTree variable to 1, which records the number of vertices in the tree. */Int startTree = 0; // vertexArray [startTree] Starting from vertex 0. isInTree = true; nTree = 1;/** path () method copies the distance expressed by the corresponding row of the adjacent matrix to sPath, actually, we always copy data from the first row * to make it simple, assuming that the subscript of the source point is always 0. At the beginning, the parent node field in all sPath [] arrays is A, that is, the Source Vertex. */For (int I = 0; I <nVerts; I ++) {int tempDist = adjMat [startTree] [I]; // The distance saved in sPath is the distance from the initial vertex. Therefore, the parent vertex is the initial vertex by default, and the sPath [I] = new DistPar (startTree, tempDist);}/** now enters the main cycle. When all vertices are placed in the tree, the cycle ends. This cycle has three basic actions: * 1. select the minimum distance in the sPath [] array * 2. place the corresponding vertex (the topic of the column with the minimum distance) into the tree, and the vertex becomes "current vertex" currentVert * 3. update all the sPath [] array content */while (nTree <nVerts) {// 1 according to the changes in currentVert. select int indexMin = getMin () from the sPath [] array. // obtain Int minDist = sPath [indexMin]. distance; // obtain the minimum path if (minDist = INFINITY) {System. out. println ("There are unreachable vertices"); break;} // 2. place the corresponding vertex (the topic of the column with the minimum distance) into the tree and the vertex becomes "current vertex" currentVertelse {// reset currentVertcurrentVert = indexMin; startToCurrent = sPath [indexMin]. distance;} vertexArray [currentVert]. isInTree = true; nTree ++; // 3. update the adjust_sPath ();} disp content of all sPath [] arrays based on changes in currentVert. LayPaths (); nTree = 0; for (int I = 0; I <nVerts; I ++) {vertexArray [I]. isInTree = false ;}}// obtain the index private int getMin () {int minDist = INFINITY; int indexMin = 0; for (int I = 0; I <nVerts; I ++) {if (! VertexArray [I]. isInTree & sPath [I]. distance <minDist) {minDist = sPath [I]. distance; indexMin = I;} return indexMin;}/* adjust the value of the object stored in sPath, that is, the distance from the vertex to the initial vertex, and the parent vertex * this is the core of the Dijkstra algorithm */private void adjust_sPath () {int column = 1; while (column <nVerts) {if (vertexArray [column]. isInTree) {column ++; continue;} int currentToFringe = adjMat [currentVert] [column]; // obtain the distance from the current vertex to other vertex, other vertices do not meet isInTreeint startToFringe = startToCurrent + currentToFringe; // calculate the distance from other vertices to the initial vertex = the distance from the current vertex to the initial vertex + the distance from the current vertex to other vertices int sPathDist = sPath [column]. distance; // obtain the distance from the vertex at the column to the starting vertex. if it is not adjacent to the initial vertex, the default value is infinite if (startToFringe <sPathDist) {sPath [column]. parentVert = currentVert; // modify the parent vertex sPath [column]. distance = startToFringe; // and the distance to the initial vertex} column ++ ;}// display path private void displayPaths () {for (int I = 0; I <nVerts; I ++) {System. out. print (vertexArray [I]. label + "="); if (sPath [I]. distance = INFINITY) System. out. print ("infinity"); elseSystem. out. print (sPath [I]. distance); char parent = vertexArray [sPath [I]. parentVert]. label; System. out. print ("(" + parent + ")");} System. out. println ("");}}
The following is a test case:
Package test; import graph. weightedGraph; public class Test {public static void main (String [] args) {WeightedGraph arr = new WeightedGraph (); arr. addVertex ('A'); arr. addVertex ('B'); arr. addVertex ('C'); arr. addVertex ('D'); arr. addVertex ('E'); arr. addEdge (0, 1, 50); // AB 50arr. addEdge (0, 3, 80); // AD 80arr. addEdge (1, 2, 60); // BC 60arr. addEdge (1, 3, 90); // BD 90arr. addEdge (2, 4, 40); // CE 40arr. addEdge (3, 2, 20); // DC 20arr. addEdge (3, 4, 70); // DE 70arr. addEdge (4, 1, 50); // EB 50arr. minSpanningTree (); // Minimum Spanning Tree System. out. println (""); arr. path (); // Shortest path }}

Output result:

AB BE EC CD  A=infinity(A) B=50(A) C=100(D) D=80(A) E=100(B) 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.