Data structure (C language version) -- diagram notes

1. Definitions and basic terms of drawings

①. Definition of graph

Graph G is composed of two sets V and E, marked as G=(V,E), where V is the finite nonempty set of vertices, e is the finite set of vertex pairs in V, and these vertex pairs are symmetrical as edges. V(G) and E(G) usually represent the vertex set and edge set of graph G respectively, and E(G) can be an empty set. If E(G) is empty, graph G has only vertices and no edges.

Directed graph:

Each edge has a direction, and the edge is also called an arc, such as G1

Undirected graph:

Each edge is undirected, such as G2

②. Basic terms of Graphs

Let n represent the number of vertices in the graph and e represent the number of edges

Complete graph: any two points have an edge connected

Sparse graph: if the number of edges or arcs satisfies e < n log2n, it is called sparse graph, otherwise it is called dense graph

Subgraph: there are two graphs G=(V, {e}) and G1= (V1, {E1}). If V1 ⊆ V and E1 ⊆ e, G1 is said to be the subgraph of G.

Weight and net: the number of edges or arcs in a graph is called weight. Indicates the distance or cost from one vertex to another. A weighted graph is called a net.

For undirected graphs:
Adjacency point: if there is an edge a between vertex v and vertex w, vertices V and w are called adjacency points. Edge a is associated with vertices V and w.
Degree: the number of edges associated with vertex v, recorded as TD(v)

For a directed graph:
< x, Y > is a directed edge (ARC),
x is the starting point (arc tail) of the directed edge, and y is the ending point (arc head) of the directed edge
The penetration of vertex v is the number of directed edges ending at V, which is recorded as ID(v)
The outgoing degree of vertex v is the number of directed edges with V as the starting point, which is recorded as OD(v)

Path: a sequence of vertices formed by successive edges.

Path length: the number of edges or arcs on the path.

Simple path: a path with different vertices except that the start and end points of the path can be the same.

Simple loop (simple loop): a path with different vertices except for the same start and end points

If any two vertices in an undirected graph have paths connected, the graph is called connected graph (G1); If an undirected graph is a non connected graph, each connected subgraph in the graph is called the connected component (G2) of the graph.

If there is a directed path between any two vertices in a directed graph, it is called a strongly connected graph. Otherwise, its strongly connected subgraphs are called its strongly connected components.

2. Type definition of graph

Abstract data type definition of diagram:


3. Storage structure of graph

Due to the complex structure of the graph, there may be a connection between any two vertices, so the relationship between elements cannot be expressed by the physical position of data elements in the storage area, that is, the graph has no sequential storage structure, but the relationship between elements can be expressed by means of two-dimensional array, that is, adjacency matrix representation. On the other hand, because there may be a relationship between any two vertices of a graph, it is natural to use chain storage to represent a graph. There are many kinds of chain storage of graphs, including adjacency list, cross linked list and adjacency multiple list. Different storage structures should be selected according to different actual needs.

①. adjacency matrix

adjacency matrix

Adjacency matrix is a matrix that represents the adjacency relationship between vertices. Let g (V, E) be a graph with n vertices, then the adjacency matrix of G is an n-order square matrix with the following properties.

In the adjacency matrix of a directed graph,

  • Meaning of line I: node v; Is the edge of the starting point (i.e. the exit edge);
  • Meaning of column I: node v; Is the edge of the end point (i.e. in degree edge).

The adjacency matrix of a directed graph may be asymmetric.

  • Vertex out - sum of elements in line i
  • Vertex penetration - sum of elements in column i
  • Degree of vertex - sum of elements in row i + sum of elements in column i

The adjacency matrix of an undirected graph is symmetric;

  • Degree of vertex i = number of 1 in row I (column);
  • The number of edges of the graph = half of the sum of all non-0 elements;
  • In the adjacency matrix of a complete graph, the diagonal elements are 0 and the rest are 1.

If G is a net, the adjacency matrix can be defined as:

Where, WI and j represent the weight on the edge; ∞ represents the number allowed by the computer and greater than the weight on all edges.


Characteristics of adjacency matrix representation

  • Advantages: it is easy to realize the operation of the diagram.
    For example: find the degree of a vertex, judge whether there are edges between vertices, find the adjacent points of vertices
  • Disadvantages: n vertices require n*n cells to store edges; The spatial efficiency is O(n2).
    It is especially a waste of space for sparse graphs.
//Storage representation of adjacency matrix of graph
#define MaxInt 32767 / / indicates the maximum value, i.e. ∞
#define MVNum 100 / / maximum number of vertices
typedef char VerTexType; //Assume that the data type of the vertex is character type
typedef int ArcType;     //It is assumed that the weight type of the edge is integer
typedef struct
{
    VerTexType vexs[MVNum];     //Vertex table
    ArcType arcs[MVNum][MVNum]; //adjacency matrix 
    int vexnum, arcnum;         //The current number of vertices and edges of a graph
} AMGraph;

Using adjacency matrix representation to create undirected network

  1. Enter the total number of vertices and edges.
  2. Input the information of points in turn and store it in the vertex table.
  3. Initialize the adjacency matrix so that each weight is initialized to a maximum value.
  4. Construct adjacency matrix. Input the vertex attached to each edge and its weight in turn. After determining the position of the two vertices in the graph, make the corresponding edge give corresponding weight, and make its symmetrical edge give the same weight.
Status CreateUDN(AMGraph &G)
{                                //The adjacency matrix representation is used to create undirected network G
    cin >> G.vexnum >> G.arcnum; //Enter the total number of vertices and edges
    for (i = 0; i < G.vexnum; ++i)
        cin >> G.vexs[i];          //Enter the information of the points in turn
    for (i = 0; i < G.vexnum; ++i) //Initialize the adjacency matrix, and set the weights of the edges to the maximum
        for (j = 0; j < G.vexnum; ++j)
            G.arcs[i][j] = MaxInt;
    for (k = 0; k < G.arcnum; ++k) //Construct adjacency matrix
    {
        cin >> v1 >> v2 >> w; //Enter the vertex and weight of an edge
        i = LocateVex(G, v1);
        j = LocateVex(G, v2);        //Determine the position of v1 and v2 in G
        G.arcs[i][j] = w;            //The weight of edge < V1, V2 > is set to w
        G.arcs[j][i] = G.arcs[i][j]; //Set the weight of the symmetrical edge < V2, V1 > of < V1, V2 > to w
    }                                // for
    return OK;
} // CreateUDN

The time complexity of the algorithm is O(n2).

If the weight of the above algorithm is 0, it is only necessary to initialize two adjacent edges; Second, when constructing the adjacency matrix, change the weight w to a constant value of 1. Similarly, a directed network or graph can be established by slightly modifying the algorithm.

②. Adjacency table

Adjacency List is a chain storage structure of graph. In the adjacency table, for each vertex v in the graph; Establish a single linked list and put the vertices adjacent to V in this linked list. The first node of each single linked list in the adjacency table stores information about vertices. This node is regarded as the header of the linked list, and the other nodes store information about edges. In this way, the adjacency table is composed of two parts: header node table and edge table.

Adjacency table representation of undirected graph

Adjacency table representation of directed graph

//Adjacency table storage representation of graph
#define MVNum 100 / / maximum number of vertices
typedef struct ArcNode
{
    int adjvex;              // The position of the vertex that the edge points to
    struct ArcNode *nextarc; // Pointer to the next edge
    OtherInfo info;          // Edge related information
} ArcNode;
typedef struct VNode
{
    VertexType data;     // Vertex information
    ArcNode *firstarc;   // Points to the first edge attached to the vertex
} VNode, AdjList[MVNum]; // AdjList indicates the adjacency table type
typedef struct
{
    AdjList vertices;   // vertices - the complex number of vertex
    int vexnum, arcnum; //The current number of vertices and edges of a graph
} ALGraph;

Using adjacency table representation to create undirected graph

  1. Enter the total number of vertices and sides.
  2. Input the information of points in turn and store it in the vertex table to initialize the pointer field of each header node to NULL.
  3. Create an adjacency table. Enter the two vertices attached to each edge in turn, determine the sequence numbers i and j of the two vertices, and insert the edge node into the heads of the two edge linked lists corresponding to vi and vj respectively.
Status CreateUDG(ALGraph &G)
{                                //Using adjacency table representation, undirected graph G is created
    cin >> G.vexnum >> G.arcnum; //Enter the number of vertices and arcs
    for (i = 0; i < G.vexnum; ++i)
    {                                  //Input each point to construct the header node table
        cin >> G.vertices[i].data;     //Enter vertex value
        G.vertices[i].firstarc = NULL; //The pointer field of the initialization header node is NULL
    }
    for (k = 0; k < G.arcnum; ++k) //Input each side, construct adjacency table, head interpolation
    {
        cin >> v1 >> v2; //Enter the two vertices to which an edge is attached
        i = LocateVex(G, v1);
        j = LocateVex(G, v2);
        p1 = new ArcNode; //Generate a new edge node * p1
        p1->adjvex = j;   //The serial number of adjacent points is j
        p1->nextarc = G.vertices[i].firstarc;
        G.vertices[i].firstarc = p1;          //Insert the new node * p1 into the edge table header of vertex vi
        p2 = new ArcNode;                     //Generate a new edge node * p2
        p2->adjvex = i;                       //The serial number of adjacent points is j
        p2->nextarc = G.vertices[j].firstarc; //Insert arc node into single linked list
        G.vertices[j].firstarc = p2;          //Insert the new node * p2 into the edge table header of vertex vj
    }                                         //Head insertion
    return OK;
} // CreateUDG

The time complexity of the algorithm is O(n+e).

The establishment of adjacency list of directed graph is similar to this, but it is more simple. For each vertex pair sequence number < I, j >, it only needs to generate an edge list node with adjacent node sequence number j and insert it into the head of edge linked list of v. To create the adjacency table of the net, you can store the weight of the edge in the info field.

Comparison between adjacency matrix and adjacency table

Example 1:


Example 2:


④. Orthogonal list

Orthogonal list is another chain storage structure of directed graph. It can be regarded as a linked list obtained by combining the adjacency list and inverse adjacency list of directed graph. In the cross linked list, there is a node corresponding to each arc in the directed graph and a node corresponding to each vertex.

There are five fields in the arc node: the tail field and the head field indicate the positions of the two vertices of the arc tail and the arc head in the graph respectively. The chain field hlink points to the next arc with the same arc head, the chain field tlink points to the next arc with the same arc tail, and the info field points to the relevant information of the arc. The arc with the same arc head is on the same linked list, and the arc with the same arc tail is also on the same linked list. Their head node is the vertex node, which is composed of three fields: the data field stores the information related to the vertex, such as the name of the vertex; firstin and firstout are two chain domains, which point to the first arc node with the vertex as the arc head or tail respectively.

nameexplain
tailvexIndicates the position of the arc tail vertex in the graph.
headtexIndicates the position of the arc head vertex in the graph.
hlinkIs the pointer to the next arc with the same arc head.
tlinkIs the pointer to the next arc with the same tail.
InfoInformation pointing to the arc.

//Cross linked list storage representation of directed graph
#define MAX_VERTEX_NUM 20
typedef struct ArcBox
{
    int tailvex, headvex;
    struct ArcBox *hlink, *tlink;
    InfoType *info;
} ArcBox;
typedef struct VexNode // ArcBox is an arc node variable
{
    VertexType data;
    ArcBox *firstin, *firstout;
} VexNode;
typedef struct // VexNode is a vertex variable
{
    VexNode xlist[MAX_VERTEX_NUM]; // Heading direction
    int vexnum, arcnum;            // Current vertex number and arc number of digraph
} OLGraph;

Example:


④. Adjacency multiple table

Adjacency multiple list is another chain storage structure of undirected graph. Although it is easy to obtain various information of vertices and edges when storing undirected graph with adjacency list, each edge in adjacency list has two nodes, which are in the i and j chain lists respectively, which brings inconvenience to some operations of graph. In the adjacency multiple table, each edge has only one edge node, which provides convenience for the processing of related edges.

nameexplain
markIs a flag field, which can be used to mark whether the edge has been searched
ivex and jvexThe positions of the two vertices attached to the edge in the graph;
ilnkPoint to the next edge attached to vertex ivex;
jlinkPoint to the next edge attached to the vertex jvex
infoIs a pointer field pointing to various information related to edges.

Example:

//Storage adjacency graph without adjacency table
#define MAX_VERTEX_NUM 20
typedef enum
{
    unvisited,
    viseited
} ViseitIF;
typedef struct EBox
{
    VisitIf mark;               //Access flag field
    int ivex, jvex;             //The two vertices to which the edge is attached are located in the header array
    struct EBox *ilink, *jlink; //Point to the next edge attached to ivex and jvex, respectively
    InfoType *info;
} Ebox;
typedef struct VexBox
{
    VertexType data; //Save information about vertices
    EBox *firstedge; //Points to the first edge attached to the vertex
} VexBox;
typedef struct
{
    VexBox adjmulist[MAX_VERTEX_NUM]; // Header vector
    int vexnum, edgenum;              // Current vertex number and arc number of undirected graph
} AMLGraph;

Example: draw the adjacency multiple table of undirected graph G



4. Traversal of Graphs

V from a vertex in the graph. To access all vertices in a graph along some edges and make each vertex accessed once and only once is called graph traversal. It is the basic operation of graph.

①. Depth first search

Depth First Search (DFS) traversal is similar to the prior traversal of a tree and is a generalization of the prior traversal of a tree. For a connected graph, the Depth First Search traversal process is as follows.

  1. Starting from a vertex v in the graph, access v.
  2. Find the first unreachable adjacency point of the vertex just accessed and access the vertex. Take this vertex as a new vertex and repeat this step until the vertex just accessed has no adjacent points that have not been accessed.
  3. Return to the vertex that has been visited and still has an unreachable adjacency point, find the next unreachable adjacency point of the vertex, and access the vertex.
  4. Repeat steps (2) and (3) until all vertices in the graph have been accessed and the search ends.

For undirected connected graphs, if the edge preservation passed by the forward operation during a depth first search is left, a depth first search spanning tree can be formed.

Implementation of depth first search traversal algorithm

Obviously, depth first search traversing a connected graph is a recursive process. In order to distinguish whether a vertex has been accessed during traversal, it is necessary to attach an access flag array visited[n], whose initial value is "false". Once a vertex is accessed, its corresponding component is set to "true".

  1. Starting from a vertex v in the graph, access V and collocate the value of visited[y] to true.
  2. Check all adjacency points w of v in turn. If the value of visited[w] is false, start from W and iterate recursively until all vertices in the graph have been accessed.
//Recursive algorithm of depth first search traversing connected graph

#include <iostream>
using namespace std;

#define MVNum 100 / / maximum number of vertices
typedef char VerTexType; //Assume that the data type of the vertex is character type
typedef int ArcType;     //It is assumed that the weight type of the edge is integer

typedef struct
{
    VerTexType vexs[MVNum];     //Vertex table
    ArcType arcs[MVNum][MVNum]; //adjacency matrix 
    int vexnum, arcnum;         //Current number of points and edges of a graph
} Graph;

bool visited[MVNum];                   //Access the flag array whose initial value is "false"
int FirstAdjVex(Graph G, int v);       //Returns the first adjacent contact of v
int NextAdjVex(Graph G, int v, int w); //Returns the next adjacent node of v relative to w

int LocateVex(Graph G, VerTexType v)
{
    //Determine the position of point v in G
    for (int i = 0; i < G.vexnum; ++i)
        if (G.vexs[i] == v)
            return i;
    return -1;
} // LocateVex

void CreateUDN(Graph &G)
{
    //The adjacency matrix representation is used to create undirected network G
    int i, j, k;
    cout << "Please enter the total number of vertices and sides , Separated by spaces:";
    cin >> G.vexnum >> G.arcnum; //Enter the total number of vertices and edges
    cout << endl;

    cout << "Enter a name for the point, such as a: " << endl;

    for (i = 0; i < G.vexnum; ++i)
    {
        cout << "Please enter page" << (i + 1) << "Name of the first point:";
        cin >> G.vexs[i]; //Enter the information of the points in turn
    }
    cout << endl;

    for (i = 0; i < G.vexnum; ++i) //Initialize the adjacency matrix, and set the weights of the edges to the maximum MaxInt
        for (j = 0; j < G.vexnum; ++j)
            G.arcs[i][j] = 0;
    cout << "Enter the vertex to which the edge is attached, such as: a b" << endl;
    for (k = 0; k < G.arcnum; ++k)
    { //Construct adjacency matrix
        VerTexType v1, v2;
        cout << "Please enter page" << (k + 1) << "Vertex to which an edge is attached:";
        cin >> v1 >> v2; //Enter the vertex and weight of an edge
        i = LocateVex(G, v1);
        j = LocateVex(G, v2);            //Determine the position of v1 and v2 in G, that is, the subscript of the vertex group
        G.arcs[j][i] = G.arcs[i][j] = 1; //Set the weight of the symmetrical edge < V2, V1 > of < V1, V2 > to w
    }                                    // for
} // CreateUDN

void DFS(Graph G, int v)
{ //Starting from the v-th vertex, recursively traverse graph G with depth first
    cout << G.vexs[v] << "    ";
    visited[v] = true; //Access the v-th vertex and collocate the corresponding component value of the access flag array to true
    int w;
    for (w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w))
        //Check all adjacent points w of v in turn. FirstAdjVex(G, v) represents the first adjacent point of v
        // NextAdjVex(G, v, w) indicates the next adjacent point of v relative to W, and w ≥ 0 indicates the existence of adjacent points
        if (!visited[w])
            DFS(G, w); //DFS is called recursively on the adjacent vertex w of v that has not been accessed
} // DFS

int FirstAdjVex(Graph G, int v)
{
    int i;
    for (i = 0; i < G.vexnum; ++i)
    {
        if (G.arcs[v][i] == 1 && visited[i] == false)
            return i;
    }
    return -1;
} // FirstAdjVex

int NextAdjVex(Graph G, int v, int w)
{
    int i;
    for (i = w; i < G.vexnum; ++i)
    {
        if (G.arcs[v][i] == 1 && visited[i] == false)
            return i;
    }
    return -1;
} // NextAdjVex

int main()
{
    cout << "************Recursive algorithm of depth first search traversing connected graph**************" << endl
         << endl;
    Graph G;
    CreateUDN(G);
    cout << endl;
    cout << "Undirected connected graph G Creation completed!" << endl
         << endl;

    cout << "Please enter the starting point of traversing the connected graph:";
    VerTexType c;
    cin >> c;

    int i;
    for (i = 0; i < G.vexnum; ++i)
    {
        if (c == G.vexs[i])
            break;
    }
    cout << endl;
    while (i >= G.vexnum)
    {
        cout << "This point does not exist, please re-enter!" << endl;
        cout << "Please enter the starting point of traversing the connected graph:";
        cin >> c;
        for (i = 0; i < G.vexnum; ++i)
        {
            if (c == G.vexs[i])
                break;
        }
    }
    cout << "Depth first search traversal connected graph results:" << endl;
    DFS(G, i);

    cout << endl;
    return 0;
} // main

//Depth first search traversal unconnected graph

#include <iostream>
using namespace std;

#define MVNum 100 / / maximum number of vertices
typedef char VerTexType; //Assume that the data type of the vertex is character type
typedef int ArcType;     //It is assumed that the weight type of the edge is integer

//-------------Adjacency matrix of graph-----------------
typedef struct
{
    VerTexType vexs[MVNum];     //Vertex table
    ArcType arcs[MVNum][MVNum]; //adjacency matrix 
    int vexnum, arcnum;         //Current number of points and edges of a graph
} Graph;

bool visited[MVNum];                   //Access the flag array whose initial value is "false"
int FirstAdjVex(Graph G, int v);       //Returns the first adjacent contact of v
int NextAdjVex(Graph G, int v, int w); //Returns the next adjacent node of v relative to w

int LocateVex(Graph G, VerTexType v)
{
    //Determine the position of point v in G
    for (int i = 0; i < G.vexnum; ++i)
        if (G.vexs[i] == v)
            return i;
    return -1;
} // LocateVex

void CreateUDN(Graph &G)
{
    //The adjacency matrix representation is used to create undirected network G
    int i, j, k;
    cout << "Please enter the total number of vertices and sides, separated by spaces:";
    cin >> G.vexnum >> G.arcnum; //Enter the total number of vertices and edges
    cout << endl;

    cout << "Enter a name for the point, such as a" << endl;
    for (i = 0; i < G.vexnum; ++i)
    {
        cout << "Please enter page" << (i + 1) << "Name of the first point:";
        cin >> G.vexs[i]; //Enter the information of the points in turn
    }
    cout << endl;
    for (i = 0; i < G.vexnum; ++i) //Initialize the adjacency matrix, and set the weights of the edges to the maximum MaxInt
        for (j = 0; j < G.vexnum; ++j)
            G.arcs[i][j] = 0;
    cout << "Enter the vertex to which the edge is attached, such as a b" << endl;
    for (k = 0; k < G.arcnum; ++k)
    { //Construct adjacency matrix
        VerTexType v1, v2;
        cout << "Please enter page" << (k + 1) << "Vertex to which an edge is attached:";
        cin >> v1 >> v2; //Enter the vertex and weight of an edge
        i = LocateVex(G, v1);
        j = LocateVex(G, v2);            //Determine the position of v1 and v2 in G, that is, the subscript of the vertex group
        G.arcs[j][i] = G.arcs[i][j] = 1; //Set the weight of the symmetrical edge < V2, V1 > of < V1, V2 > to w
    }                                    // for
} // CreateUDN

void DFS(Graph G, int v)
{
    //Starting from the v-th vertex, recursively traverse graph G with depth first
    cout << G.vexs[v] << "    ";
    visited[v] = true; //Access the v-th vertex and collocate the corresponding component value of the access flag array to true
    int w;
    for (w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w))
        //Check all adjacent points w of v in turn. FirstAdjVex(G, v) represents the first adjacent point of v
        // NextAdjVex(G, v, w) indicates the next adjacent point of v relative to W, and w ≥ 0 indicates the existence of adjacent points
        if (!visited[w])
            DFS(G, w); //DFS is called recursively on the adjacent vertex w of v that has not been accessed
} // DFS

void DFSTraverse(Graph G)
{
    //Depth first traversal of unconnected graph G
    int v;
    for (v = 0; v < G.vexnum; ++v)
        visited[v] = false;        //Access flag array initialization
    for (v = 0; v < G.vexnum; ++v) //Loop call algorithm 6.3
        if (!visited[v])
            DFS(G, v); //Call DFS on vertices that have not been accessed
} // DFSTraverse

int FirstAdjVex(Graph G, int v)
{
    //Returns the first adjacent contact of v
    int i;
    for (i = 0; i < G.vexnum; ++i)
    {
        if (G.arcs[v][i] == 1 && visited[i] == false)
            return i;
    }
    return -1;
} // FirstAdjVex

int NextAdjVex(Graph G, int v, int w)
{
    //Returns the next adjacent node of v relative to w
    int i;
    for (i = w; i < G.vexnum; ++i)
    {
        if (G.arcs[v][i] == 1 && visited[i] == false)
            return i;
    }
    return -1;
} // NextAdjVex

int main()
{
    cout << "************Depth first search traversal unconnected graph**************" << endl
         << endl;
    Graph G;
    CreateUDN(G);
    cout << endl;
    cout << "Undirected graph G Creation completed!" << endl
         << endl;

    cout << "Depth first search traversal unconnected graph results:" << endl;
    DFSTraverse(G);

    cout << endl;
    return 0;
} // main

②. Breadth first search

Breadth First Search (BFS) traversal is similar to the hierarchical traversal of a tree.

The breadth first search traversal process is as follows.

  1. Starting from a vertex v in the graph, access v.
  2. Access v's previously inaccessible adjacency points in turn.
  3. Starting from these adjacency points, access their adjacency points in turn, and make the "adjacency point of the first accessed vertex" be accessed before the "adjacency point of the later accessed vertex". Repeat step 3 until the adjacency points of all accessed vertices in the graph are accessed.


Breadth first spanning tree:


Breadth first search traversal connected graph

  1. Starting from a vertex v in the graph, access V, and set the value of visited[y] to true, and then queue v.
  2. As long as the queue is not empty, repeat the following operations:
    -Team leader u out of the team;
    -Check all adjacency points w of u in turn. If the value of visited[w] is false, access W, and set the value of visited[w] to true, and then queue W.
//Breadth first search traversal connected graph

#include <iostream>
using namespace std;

#define MVNum 100                        	// max vertex 
#define MAXQSIZE 100 						// Maximum queue length
						
typedef char VerTexType;              		//Assume that the data type of the vertex is character type
typedef int ArcType;                  		//It is assumed that the weight type of the edge is integer
bool visited[MVNum];           				//Access the flag array whose initial value is "false" 

//-----Storage representation of adjacency matrix of graph----- 
typedef struct{ 
	VerTexType vexs[MVNum];            		//Vertex table
	ArcType arcs[MVNum][MVNum];      		//adjacency matrix 
	int vexnum,arcnum;                		//Current number of points and edges of a graph
}Graph;

//----Definition and operation of queue--------
typedef struct{
	ArcType *base;							//Initialized dynamically allocated storage space
	int front;								//Header pointer. If the queue is not empty, it points to the queue header element
	int rear;								//Tail pointer. If the queue is not empty, it points to the next position of the tail element
}sqQueue;

void InitQueue(sqQueue &Q){
	//Construct an empty queue Q
	Q.base = new ArcType[MAXQSIZE];
	if(!Q.base)     exit(1);				//Storage allocation failed
	Q.front = Q.rear = 0;
}//InitQueue

void EnQueue(sqQueue &Q, ArcType e){
	//Insert a new tail element with element e as Q
	if((Q.rear + 1) % MAXQSIZE == Q.front)
		return;
	Q.base[Q.rear] = e;
	Q.rear = (Q.rear + 1) % MAXQSIZE;
}//EnQueue

bool QueueEmpty(sqQueue Q){
	//Determine whether it is an empty team
	if(Q.rear == Q.front)
		return true;
	return false;
}//QueueEmpty

void DeQueue(sqQueue &Q, ArcType &u){
	//The team head element is out of the team and placed as u 
	u = Q.base[Q.front];
	Q.front = (Q.front + 1) % MAXQSIZE;
}//DeQueue   								
//--------------------------------------------------

int LocateVex(Graph G , VerTexType v){
	//Determine the position of point v in G
	for(int i = 0; i < G.vexnum; ++i)
		if(G.vexs[i] == v)
			return i;
		return -1;
}//LocateVex

void CreateUDN(Graph &G){ 
    //The adjacency matrix representation is used to create undirected network G 
	int i , j , k;
	cout <<"Please enter the total number of vertices and sides, separated by spaces:";
    cin >> G.vexnum >> G.arcnum;							//Enter the total number of vertices and edges
	cout << endl;
	cout << "Enter a name for the point, such as a" << endl;
    for(i = 0; i < G.vexnum; ++i){   
		cout << "Please enter page" << (i+1) << "Name of the first point:";
		cin >> G.vexs[i];                        			//Enter the information of the points in turn 
	}
	cout << endl;
    for(i = 0; i < G.vexnum; ++i)                			//Initialize the adjacency matrix, and set the weights of the edges to the maximum MaxInt 
		for(j = 0; j < G.vexnum; ++j)   
			G.arcs[i][j] = 0; 
	cout << "Enter the vertex to which the edge is attached, such as a b" << endl;
	for(k = 0; k < G.arcnum;++k){							//Construct adjacency matrix 
		VerTexType v1 , v2;
		cout << "Please enter page" << (k + 1) << "Vertex to which an edge is attached:";
		cin >> v1 >> v2;									//Enter the vertex to which an edge is attached
		i = LocateVex(G, v1);  j = LocateVex(G, v2);		//Determine the position of v1 and v2 in G, that is, the subscript of the vertex group 
		G.arcs[i][j] = 1;									//The weight of edge < V1, V2 > is set to w 
		G.arcs[j][i] = G.arcs[i][j];						//Set the weight of the symmetrical edge < V2, V1 > of < V1, V2 > to w 
	}//for 
}//CreateUDN

int FirstAdjVex(Graph G , int v){
	//Returns the first adjacent contact of v
	int i;
	for(i = 0 ; i < G.vexnum ; ++i){
		if(G.arcs[v][i] == 1 && visited[i] == false)
			return i;
	}
	return -1;
}//FirstAdjVex

int NextAdjVex(Graph G , int u , int w){
	//Returns the next adjacent node of v relative to w
	int i;
	for(i = w ; i < G.vexnum ; ++i){
		if(G.arcs[u][i] == 1 && visited[i] == false)
			return i;
	}
	return -1;
}//NextAdjVex

void BFS (Graph G, int v){ 
    //Non recursive traversal of connected graph G by breadth first 
	sqQueue Q;
	ArcType u;
	ArcType w;

    cout << G.vexs[v] << "  ";    visited[v] = true;     						//Access the v-th vertex and collocate the corresponding component value of the access flag array to true 
    InitQueue(Q);              													//Auxiliary queue Q initialization, null         
    EnQueue(Q, v);            													//v join the team 
    while(!QueueEmpty(Q)){   													//Queue is not empty 
		DeQueue(Q, u);       													//The team head element is out of the team and placed as u
		for(w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w)){
			//Check all adjacent points w of u in turn. FirstAdjVex(G, u) represents the first adjacent point of U 
			//NextAdjVex(G, u, w) indicates the next adjacent point of u relative to W, and w ≥ 0 indicates the existence of adjacent points 
			if(!visited[w]){	           										//Adjacent vertices not yet accessed with w as u 
				cout << G.vexs[w] << "  ";   visited[w] = true;					//Access w, and the corresponding component value of the collocated access flag array is true 
				EnQueue(Q, w);													//w into the team 
			}//if 
		}//for
    }//while 
}//BFS 

int main(){
	cout << "************Algorithm breadth first search traversal connected graph**************" << endl << endl;
	Graph G;
	CreateUDN(G);
	cout << endl;
	cout << "Undirected connected graph G Creation completed!" << endl << endl;
	
	cout << "Please enter the starting point of traversing the connected graph:";
	VerTexType c;
	cin >> c;
	
	int i;
	for(i = 0 ; i < G.vexnum ; ++i){
		if(c == G.vexs[i])
			break;
	}
	cout << endl;
	while(i >= G.vexnum){
		cout << "This point does not exist, please re-enter!" << endl;
		cout << "Please enter the starting point of traversing the connected graph:";
		cin >> c;
		for(i = 0 ; i < G.vexnum ; ++i){
			if(c == G.vexs[i])
				break;
		}
	}
	cout << "Depth first search traversal connected graph results:" << endl;
	BFS(G , i);
	
	cout <<endl;
	return 0;
}//main

5. Application of graph

①. minimum spanning tree

Minimal connected subgraph: the subgraph is a connected subgraph of G. if any edge is deleted from the subgraph, the subgraph is no longer connected.

Spanning tree: a minimal connected subgraph containing all vertices of graph G

The vertex set of spanning tree is equal to that of graph, and the number of vertices is n; There is no loop and the number of sides is n-1

In the multiple spanning trees of the network, find a spanning tree with the smallest sum of the weights of each edge, that is, the smallest spanning tree

Criteria for constructing minimum spanning tree:

  • Only the edges in the net must be used to construct the minimum spanning tree;
  • You must use and only use n-1 edges to join n vertices in the network
  • Edges that produce loops cannot be used

Prim algorithm (point adding method)

Suppose N=(V,E) is a connected network and TE is the set of edges in the minimum spanning tree on N.

  1. U= {u0}(u0∈V),TE={}.
  2. Among all the edges (u,v) ∈ E of u ∈ u, v ∈ V-U, find an edge (u0, v0) with the smallest weight to merge into the set TE, and v0 is merged into U.
  3. Repeat ② until U=V.

At this time, there must be n-1 edges in te, then T=(V, TE) is the minimum spanning tree of N.

The process of constructing the minimum spanning tree by prim algorithm:

The graph is stored by adjacency matrix, and a two-dimensional array closedeg is used to record the edges with the lowest cost from U to V-U.
For each vertex vi, v-U, there is a corresponding component closedge[i-1] in the auxiliary array, which includes two fields:

typedef struct
{
    VertexType adjvex; // Vertex of the smallest edge
    VRType lowcost;    // Weight of the smallest edge
} closedge[MAX_VERTEX_NUM];

adjvex: another vertex attached to this least cost edge.

  • Equal to 0 means that vertex i is already in U;
  • Greater than 0 indicates that vertex i is still in V-U.

Therefore, in each cycle, the vertex with the smallest lowcast must be selected from those vertices with lowcast > 0 (in the set V-U) to be added to the set u, and the closedge of relevant vertices shall be adjusted accordingly.

//Prim algorithm
#include <iostream>
using namespace std;

typedef char VerTexType;
typedef int ArcType;
#define MVNum 100
#define MaxInt 32767                     	// Represents the maximum value, i.e. ∞

//The definition of auxiliary array is used to record the edge with the smallest weight from vertex set U to V-U
struct{
	VerTexType adjvex;						//The vertex of the smallest edge in U
	ArcType lowcost;						//Weight on minimum edge
}closedge[MVNum];

//----- adjacency table storage representation of graph ----- 						
typedef char VerTexType;              		//Assume that the data type of the vertex is character type 
typedef int ArcType;                  		//It is assumed that the weight type of the edge is integer 
typedef struct{ 
	VerTexType vexs[MVNum];            		//Vertex table 
	ArcType arcs[MVNum][MVNum];      		//adjacency matrix  
	int vexnum,arcnum;                		//Current number of points and edges of a graph 
}AMGraph;

int LocateVex(AMGraph G , VerTexType v){
	//Determine the position of point v in G
	for(int i = 0; i < G.vexnum; ++i)
		if(G.vexs[i] == v)
			return i;
		return -1;
}//LocateVex

void CreateUDN(AMGraph &G){ 
    //The adjacency matrix representation is used to create undirected network G 
	int i , j , k;
	cout <<"Please enter the total number of vertices and sides, separated by spaces:";
    cin >> G.vexnum >> G.arcnum;							//Enter the total number of vertices and edges
	cout << endl;

	cout << "Enter a name for the point, such as a" << endl;

    for(i = 0; i < G.vexnum; ++i){   
		cout << "Please enter page" << (i+1) << "Name of the first point:";
		cin >> G.vexs[i];                        			//Enter the information of the points in turn 
	}
	cout << endl;
    for(i = 0; i < G.vexnum; ++i)                			//Initialize the adjacency matrix, and set the weights of the edges to the maximum MaxInt 
		for(j = 0; j < G.vexnum; ++j)   
			G.arcs[i][j] = MaxInt;
	cout << "Enter the vertex and weight of the edge, such as a b 5" << endl;
	for(k = 0; k < G.arcnum;++k){							//Construct adjacency matrix 
		VerTexType v1 , v2;
		ArcType w;
		cout << "Please enter page" << (k + 1) << "Vertex and weight of edge attachment:";
		cin >> v1 >> v2 >> w;								//Enter the vertex and weight of an edge
		i = LocateVex(G, v1);  j = LocateVex(G, v2);		//Determine the position of v1 and v2 in G, that is, the subscript of the vertex group 
		G.arcs[i][j] = w;									//The weight of edge < V1, V2 > is set to w 
		G.arcs[j][i] = G.arcs[i][j];						//Set the weight of the symmetrical edge < V2, V1 > of < V1, V2 > to w 
	}//for
}//CreateUDN 

int Min(AMGraph G){
	//Returns the point with the lowest weight
	int i;
	int index = -1;
	int min = MaxInt;
	for(i = 0 ; i < G.vexnum ; ++i){
		if(min > closedge[i].lowcost && closedge[i].lowcost != 0){
			min = closedge[i].lowcost;
			index = i;
		}
	}//for
	return index;
}//Min

void MiniSpanTree_Prim(AMGraph G, VerTexType u){ 
    //Undirected net G is stored in the form of adjacency matrix. Starting from vertex u, the minimum spanning tree T of G is constructed, and the edges of T are output  
	int k , j , i;
	VerTexType u0 , v0;
    k =LocateVex(G, u);           										//k is the subscript of vertex u 
    for(j = 0; j < G.vexnum; ++j){     									//Initialize closedge[i] for each vertex vi of V-U 
		if(j != k){  
			closedge[j].adjvex = u;
			closedge[j].lowcost = G.arcs[k][j];							//{adjvex, lowcost}
		}//if
	}//for
	closedge[k].lowcost = 0;        									//Initial, U = {u}
	for(i = 1; i < G.vexnum; ++i){     									//Select the remaining n-1 vertices to generate n-1 edges (n= G.vexnum) 
		k = Min(G);  
		//Find the next node of T: the k-th vertex. There is the current minimum edge in closedge[k] 
		u0 = closedge[k].adjvex;     									//u0 is a vertex of the smallest edge, u0 ∈ U 
		v0 = G.vexs[k];            										//v0 is the other vertex of the smallest edge, v0 ∈ V-U 
		cout << "edge  " <<u0 << "--->" << v0 << endl;           			//Output the current minimum edge (u0, v0) 
		closedge[k].lowcost = 0;   		//The k th vertex is merged into the U set 
		for(j = 0; j < G.vexnum; ++j) 
			if(G.arcs[k][j] < closedge[j].lowcost){						//Reselect the smallest edge after the new vertex is merged into U 
				closedge[j].adjvex = G.vexs[k];
				closedge[j].lowcost = G.arcs[k][j];
			}//if 
	}//for 
}//MiniSpanTree_Prim 

int main(){
	cout << "************Prim algorithm**************" << endl << endl;
	AMGraph G;
	CreateUDN(G);
	cout << endl;
	cout << "Undirected graph G Creation completed!" << endl;
	cout <<endl;

	cout << "******Using prim algorithm to construct the minimum spanning tree result:******" << endl;
	MiniSpanTree_Prim(G , 'a');
	cout <<endl;
	return 0;
}//main

Example:

Kruskal algorithm (edging method)

Assuming the connected network N=(V,E), arrange the edges in Ⅳ in the order of weight from small to large.

  1. The initial state is a non connected graph with only n vertices and no edges, T=(V, {), and each vertex in the graph forms a connected component.
  2. Select the edge with the smallest weight in E. if the vertex attached to the edge falls on different connected components in t (i.e. no loop is formed), the edge will be added to T. otherwise, the edge will be rounded off and the next edge with the smallest weight will be selected.
  3. Repeat ② until all vertices in T are on the same connected component.

The process of constructing the minimum spanning tree by Kruskal algorithm:

The implementation of the algorithm should introduce the following auxiliary data structure.

  1. Structure array Edge: stores the information of the Edge, including the two vertex information and weight of the Edge.
//Definition of auxiliary array Edges
struct
{
    VerTexType Head; //Start point of edge
    VerTexType Tail; //End of edge
    ArcType lowcost; //Weight on edge
} Edge[arcnnum];
  1. Vexset[i]: identifies the connected component to which each vertex belongs. For each vertex v,EV, there is a corresponding element Vexset[i] in the auxiliary array to represent the connected component of the vertex. Initially, Vexset[i]=i, indicating that each vertex forms a connected component.
//Definition of auxiliary array Vexset
int Vexset[MVNum];

  1. Sort the elements in the array Edge by weight from small to large.
  2. View the edges in the array Edge in turn and cycle through the following operations:
  • Select an Edge (U1,U2) from the ordered array Edge in turn;
  • Find the connected components vs1 and vs2 of v1 and v2 in Vexset and judge:
    -If vs1 and vs2 are not equal, it indicates that the selected two vertices belong to different connected components, output this edge, and merge the two connected components of vs1 and vs2;
    -If vs1 and vs2 are equal, it indicates that the selected two vertices belong to the same connected component. This edge is rounded off and the next edge with the lowest weight is selected.
//Kruskal algorithm

#include <iostream>
using namespace std;

typedef char VerTexType;              		//Assume that the data type of the vertex is character type 
typedef int ArcType;   
#define MVNum 100                        	// max vertex 
#define MaxInt 32767                     	// Represents the maximum value, i.e. ∞

//----------------Adjacency matrix of graph---------------------
typedef struct{ 
	VerTexType vexs[MVNum];            		//Vertex table 
	ArcType arcs[MVNum][MVNum];      		//adjacency matrix  
	int vexnum,arcnum;                		//Current number of points and edges of a graph 
}AMGraph;

//Definition of auxiliary array Edges
struct{
	VerTexType Head;						//Start point of edge
	VerTexType Tail;						//End of edge
	ArcType lowcost;						//Weight on edge
}Edge[(MVNum * (MVNum - 1)) / 2];

int Vexset[MVNum];							//Definition of auxiliary array Vexset

int LocateVex(AMGraph G , VerTexType v){
	//Determine the position of point v in G
	for(int i = 0; i < G.vexnum; ++i)
		if(G.vexs[i] == v)
			return i;
		return -1;
}//LocateVex

void CreateUDN(AMGraph &G){ 
    //The adjacency matrix representation is used to create undirected network G 
	int i , j , k;
	cout <<"Please enter the total number of vertices and sides, separated by spaces:";
    cin >> G.vexnum >> G.arcnum;						//Enter the total number of vertices and edges
	cout << endl;
	
	cout << "Enter a name for the point, such as a" << endl;

    for(i = 0; i < G.vexnum; ++i){   
		cout << "Please enter page" << (i+1) << "Name of the first point:";
		cin >> G.vexs[i];                        		//Enter the information of the points in turn 
	}
	cout << endl;
	for(i = 0; i < G.vexnum; ++i)                		//Initialize the adjacency matrix, and set the weights of the edges to the maximum MaxInt 
		for(j = 0; j < G.vexnum; ++j) 
			G.arcs[i][j] = MaxInt; 
	cout << "Enter the vertex and weight of the edge, such as a b 6" << endl;
	for(k = 0; k < G.arcnum;++k){						//Construct adjacency matrix 
		VerTexType v1 , v2;
		ArcType w;
		cout << "Please enter page" << (k + 1) << "Vertex and weight of edge attachment:";
		cin >> v1 >> v2 >> w;                           //Enter the vertex and weight of an edge
		i = LocateVex(G, v1);  j = LocateVex(G, v2);	//Determine the position of v1 and v2 in G, that is, the subscript of the vertex group 
		G.arcs[i][j] = w;								//The weight of edge < V1, V2 > is set to w 
		G.arcs[j][i] = G.arcs[i][j];					//Set the weight of the symmetrical edge < V2, V1 > of < V1, V2 > to w 
		Edge[k].lowcost = w;
		Edge[k].Head = v1;
		Edge[k].Tail = v2;
	}//for
}//CreateUDN 

//----------Bubble sorting-------------------
void Sort(AMGraph G){
	int m = G.arcnum - 2;
	int flag = 1;
	while((m > 0) && flag == 1){
		flag = 0;
		for(int j = 0 ; j <= m ; j++){
			if(Edge[j].lowcost > Edge[j+ 1].lowcost){
				flag = 1;

				VerTexType temp_Head = Edge[j].Head;
				Edge[j].Head = Edge[j+ 1].Head;
				Edge[j + 1].Head = temp_Head;
				

				VerTexType temp_Tail = Edge[j].Tail;
				Edge[j].Tail = Edge[j+ 1].Tail;
				Edge[j + 1].Tail = temp_Tail;
				
				ArcType temp_lowcost = Edge[j].lowcost;
				Edge[j].lowcost = Edge[j+ 1].lowcost;
				Edge[j + 1].lowcost = temp_lowcost;
			}//if
		}//for
		--m;
	}//while
}//Sort

void MiniSpanTree_Kruskal(AMGraph G){ 
    //Undirected net G is stored in the form of adjacency matrix, constructs the minimum spanning tree T of G, and outputs each edge of T     
    int i , j , v1 , v2 , vs1 , vs2;
	Sort(G);                 							//Sort the elements in the array Edge by weight from small to large 
	for(i = 0; i < G.vexnum; ++i)     					//Auxiliary array, indicating that each vertex forms a connected component 
        Vexset[i] = i;
    for(i = 0; i < G.arcnum; ++i){      
		//Check whether the edges in the ordered array Edge are on the same connected component     
		v1 =LocateVex(G, Edge[i].Head);     			//v1 is the subscript of the starting point Head of the edge 
		v2 =LocateVex(G, Edge[i].Tail);     			//v2 is the subscript of Tail, the end point of the edge 
		vs1 = Vexset[v1];       						//Get the connected component vs1 where the starting point of Edge[i] is located 
		vs2 = Vexset[v2];       						//Get the connected component vs2 where the end point of Edge[i] is located 
		if(vs1 != vs2){         						//The two vertices of an edge belong to different connected components 
			cout << Edge[i].Head << "-->" << Edge[i].Tail << endl;		//Output this edge 
			for(j = 0; j < G.vexnum; ++j)      			//Combine vs1 and vs2 components, that is, the two sets are numbered uniformly 
				if(Vexset[j] == vs2) Vexset[j] = vs1;	//Set number vs2 is changed to vs1 
		}//if 
    }//for 
}//MiniSpanTree_Kruskal

void main(){
	cout << "************Kruskal algorithm**************" << endl << endl;
	AMGraph G;
	CreateUDN(G);
	
	cout <<endl;
	cout << "*****Undirected network G Creation completed!*****" << endl;

	cout <<endl;
	MiniSpanTree_Kruskal(G);
}///main

②. Shortest path

For a graph, there may be multiple paths from one vertex to another, and the number of edges in each path may be different. The path with the least number of edges is called the shortest path.

Shortest path: for a network (weighted graph), the sum of the weights of the edges passing from one vertex to another is called the weighted path length, and the one with the shortest weighted path length is called the shortest path

The shortest path from a source point to other vertices -- Dijkstra algorithm

  1. Initialization: first find the direct path (v0,vk) from the source point v0 to each end point v, that is, the path reached through an arc.
  2. Select: find a path with the shortest length (v0,u) from these paths.
  3. Update: then adjust the remaining paths appropriately.

If there are arcs (U, vk), (v0, u) +(u, vk) < (v0, vk) in the graph, replace (v0, vk) with path (v0,u,vk).
Among the adjusted paths, find the path with the shortest length.

Main storage structure: adjacency matrix G [n][n] (or adjacency table)

Secondary storage structure:

Array S[n]: record whether the shortest distance of the corresponding vertex has been determined
true: OK false: not OK

Array D[n]: record the path length from the source point to the corresponding vertex
Initial value: if there is an arc from v0 to vi, D[i] is the weight on the arc; Otherwise ∞

Array Path[n]: record the precursor vertex of the corresponding vertex
Initial value: if there is an arc from v0 to vi, Path[i] is V0, otherwise - 1


  1. initialization:
    Add the source point v0 to S, that is, S[v0] = true;
    Initialize the shortest path length from v0 to each end point as the weight, that is, D[i]= G.arcs[v0][vi], (VI ∈ V -S);
    If there is an arc between v0 and vertex vi, set the precursor of vi to v0, that is, Path[i] = v0, otherwise Path[i] = -1.

  2. Cycle n-1 times and perform the following operations:
    Select the end point vk of the next shortest path so that: D[k]=Min{D[i]viEV-S}
    Add vk to S, i.e. S[vk] = true.
    Update the length of the shortest path from v0 to any vertex of the set V-S, and change the precursor of vi to vk.
    If S[i]=false and D [k] + g.arcs [k] [i] < d [i], update D[i]-D[k]+ G.arcs[k][i; Path [i]=k;.

//Shortest path -- dijestra algorithm
#include <iostream>
using namespace std;

#define MaxInt 32767                     					// Represents the maximum value, i.e. ∞
#define MVNum 100                        					// max vertex 
typedef char VerTexType;              						//Assume that the data type of the vertex is character type 
typedef int ArcType;                  						//It is assumed that the weight type of the edge is integer

int *D=new int[MVNum];	                    				//Used to record the length of the shortest circuit
bool *S=new bool[MVNum];          							//Mark whether the vertex enters the S set
int *Path=new int[MVNum];									//Precursor for recording the shortest vertex

//------------Adjacency matrix of graph-----------------
typedef struct{ 
	VerTexType vexs[MVNum];            						//Vertex table 
	ArcType arcs[MVNum][MVNum];      						//adjacency matrix  
	int vexnum,arcnum;                						//Current number of points and edges of a graph 
}AMGraph;

int LocateVex(AMGraph G , VerTexType v){
	//Determine the position of point v in G
	for(int i = 0; i < G.vexnum; ++i)
		if(G.vexs[i] == v)
			return i;
   return -1;
}//LocateVex

void CreateUDN(AMGraph &G){ 
    //The adjacency matrix representation is used to create undirected network G 
	int i , j , k;
	cout <<"Please enter the total number of vertices and sides, separated by spaces:";
    cin >> G.vexnum >> G.arcnum;							//Enter the total number of vertices and edges
	cout << endl;

	cout << "Enter a name for the point:,as a" << endl;

    for(i = 0; i < G.vexnum; ++i){   
		cout << "Please enter page" << (i+1) << "Name of the first point:";
		cin >> G.vexs[i];                        			//Enter the information of the points in turn 
	}
	cout << endl;
    for(i = 0; i < G.vexnum; ++i)                			//Initialize the adjacency matrix, and set the weights of the edges to the maximum MaxInt 
		for(j = 0; j < G.vexnum; ++j)   
			G.arcs[i][j] = MaxInt; 
	cout << "Enter the vertex and weight of the edge, such as a b 7" << endl;
	for(k = 0; k < G.arcnum;++k){							//Construct adjacency matrix 
		VerTexType v1 , v2;
		ArcType w;
		cout << "Please enter page" << (k + 1) << "Vertex and weight of edge attachment:";
		cin >> v1 >> v2 >> w;								//Enter the vertex and weight of an edge
		i = LocateVex(G, v1);  j = LocateVex(G, v2);		//Determine the position of v1 and v2 in G, that is, the subscript of the vertex group 
		G.arcs[i][j] = w;									//The weight of edge < V1, V2 > is set to w 
		G.arcs[j][i] = G.arcs[i][j];						//Set the weight of the symmetrical edge < V2, V1 > of < V1, V2 > to w 
	}//for
}//CreateUDN

void ShortestPath_DIJ(AMGraph G, int v0){ 
    //Using Dijkstra algorithm to find the shortest path from v0 vertex of directed network G to other vertices 
    int v , i , w , min;
	int n = G.vexnum;                    					//n is the number of vertices in G 

	for(v = 0; v < n; ++v){             					//n vertices are initialized in turn 
		S[v] = 0;                  						//S is initially an empty set 
		D[v] = G.arcs[v0][v];           					//Initialize the shortest path length from v0 to each end point as the weight on the arc 
		if(D[v] < MaxInt)  Path [v] = v0;  					//If there is an arc between V0 and V, set the front drive of V to v0 
		else Path [v] = -1;               					//If there is no arc between v0 and v, set the front drive of v to - 1 
	}//for 

	S[v0]=true;                    							//Add v0 to S 
	D[v0]=0;                      							//The distance from the source point to the source point is 0 

	/*―After initialization, start the main loop, find the shortest path from v0 to a vertex v each time, and add V to S set --*/ 
	for(i = 1;i < n; ++i){									//The remaining n-1 vertices are calculated in turn 
        min= MaxInt; 
        for(w = 0; w < n; ++w) 
			if(!S[w] && D[w] < min){						//Select a current shortest path, ending at v 
				v = w; 
				min = D[w];
			}//if         	
		S[v]=true;                   						//Add v to S 
		for(w = 0;w < n; ++w)           					//Update from v0 to set V? The shortest path length of all vertices on S 
			if(!S[w] && (D[v] + G.arcs[v][w] < D[w])){ 
				D[w] = D[v] + G.arcs[v][w];   				//Update [w] 
				Path [w] = v;              					//Change the precursor of w to v 
			}//if 
    }//for  
}//ShortestPath_DIJ

void DisplayPath(AMGraph G , int begin ,int temp ){
	//Display the shortest circuit
	if(Path[temp] != -1){
		DisplayPath(G , begin ,Path[temp]);
		cout << G.vexs[Path[temp]] << "-->";
	}
}//DisplayPath

int main()
{
	cout << "************Dijkstra's algorithm **************" << endl << endl;
	AMGraph G; 
	int i , j ,num_start , num_destination;
	VerTexType start , destination;
	CreateUDN(G);
	cout <<endl;
	cout << "*****Undirected network G Creation completed!*****" << endl;
	
	for(i = 0 ; i < G.vexnum ; ++i){
		for(j = 0; j < G.vexnum; ++j){
			if(j != G.vexnum - 1){
				if(G.arcs[i][j] != MaxInt)
					cout << G.arcs[i][j] << "\t";
				else
					cout << "∞" << "\t";
			}
			else{
				if(G.arcs[i][j] != MaxInt)
					cout << G.arcs[i][j] <<endl;
				else
					cout << "∞" <<endl;
			}
		}
	}//for
	cout << endl;
	cout << "Please enter the start point and end point name in sequence:";
	cin >> start >> destination;
	num_start = LocateVex(G , start);
	num_destination = LocateVex(G , destination);
	ShortestPath_DIJ(G , num_start);
	cout << endl <<"The shortest path is:";
	DisplayPath(G , num_start , num_destination);
	cout << G.vexs[num_destination]<<endl;
}//main

The shortest path between each pair of vertices -- Floyd algorithm

Starting from the weighted adjacency matrix G.arcs of the graph,
Suppose to find the shortest path from vertex Vi to Vj. If there is an arc from Vi to Vj, there is a path with a length of G.arcs[i]i] from Vi to Vj, but whether the path must be the shortest path still needs to be explored n times.

  1. For the first time, judge (Vi, V0) and (V0, Vj), that is, judge whether (Vi, V0, Vj) exists. If so, compare (Vi,
    The length of Vj) and (Vi, V0, Vj), whichever is shorter, is the shortest path from Vi to Vj, and the sequence number of the middle vertex is not greater than 0.
  2. The second time, add another vertex V1 if (Vi,..., V1) and (V1,
    Vj) are the shortest paths with the sequence number of intermediate vertices not greater than 0, then (Vi,..., V1,
    Vj) may be the shortest path from Vi to Vj with the middle vertex number not greater than 1. Compare it with the shortest path from Vi to Vj whose vertex number is not greater than 0, and take the shorter one as the shortest path from Vi to Vj whose middle vertex number is not greater than 1.
  3. The third time, add another vertex V2 and continue the temptation.

To find the shortest path:

  1. Initially, set an n-order square matrix so that its diagonal element is 0. If there is an arc < VI, VJ >, the corresponding element is the weight; Otherwise, it is infinite.
  2. Gradually try to add intermediate vertices to the original direct path. If the path becomes shorter after adding intermediate vertices, modify it; Otherwise, maintain the original value. All vertex probes are completed and the algorithm ends.


//Freudian algorithm

#include <iostream>
using namespace std;

#define MaxInt 32767                     	// Represents the maximum value, i.e. ∞
#define MVNum 100                        	// max vertex 

typedef char VerTexType;              		//Assume that the data type of the vertex is character type 
typedef int ArcType;                  		//It is assumed that the weight type of the edge is integer 

int Path[MVNum][MVNum];						//The sequence number of the previous vertex vj of the vertex on the shortest path
int D[MVNum][MVNum];						//Record the shortest path length between vertices vi and vj

//------------Adjacency matrix of graph---------------
typedef struct{ 
	VerTexType vexs[MVNum];            		//Vertex table 
	ArcType arcs[MVNum][MVNum];      		//adjacency matrix  
	int vexnum,arcnum;                		//Current number of points and edges of a graph 
}AMGraph;

int LocateVex(AMGraph G , VerTexType v){
	//Determine the position of point v in G
	for(int i = 0; i < G.vexnum; ++i)
		if(G.vexs[i] == v)
			return i;
		return -1;
}//LocateVex

void CreateUDN(AMGraph &G){ 
    //The adjacency matrix representation is used to create the directed network G 
	int i , j , k;
	cout <<"Please enter the total number of vertices and sides, separated by spaces:";
    cin >> G.vexnum >> G.arcnum;							//Enter the total number of vertices and edges
	cout << endl;

	cout << "Enter a name for the point, such as a" << endl;

    for(i = 0; i < G.vexnum; ++i){   
		cout << "Please enter page" << (i+1) << "Name of the first point:";
		cin >> G.vexs[i];                        			//Enter the information of the points in turn 
	}
	cout << endl;
    for(i = 0; i < G.vexnum; ++i){                			//Initialize the adjacency matrix, and set the weights of the edges to the maximum MaxInt 
		for(j = 0; j < G.vexnum; ++j){  
			if(j != i)
				G.arcs[i][j] = MaxInt;  
			else
				G.arcs[i][j] = 0;
		}//for
	}//for

	cout << "Enter the vertex and weight of the edge, such as a b 3" << endl;
	for(k = 0; k < G.arcnum;++k){						//Construct adjacency matrix 
		VerTexType v1 , v2;
		ArcType w;
		cout << "Please enter page" << (k + 1) << "Vertex and weight of edge attachment:";
		cin >> v1 >> v2 >> w;                           //Enter the vertex and weight of an edge
		i = LocateVex(G, v1);  j = LocateVex(G, v2);	//Determine the position of v1 and v2 in G, that is, the subscript of the vertex group 
		G.arcs[i][j] = w;								//The weight of edge < V1, V2 > is set to w 
	}//for
}//CreateUDN 

void ShortestPath_Floyed(AMGraph G){ 
    //Using Floyd algorithm to find the shortest path between each pair of vertices i and j in directed network G 
	int i , j , k ;
    for (i = 0; i < G.vexnum; ++i)          		//Initial known path and distance between pairs of nodes 
        for(j = 0; j < G.vexnum; ++j){ 
            D[i][j] = G.arcs[i][j]; 
            if(D[i][j] < MaxInt && i != j)  Path[i][j]=i;  	//If there is an arc between i and j, set the precursor of J to i 
            else Path [i][j] = -1;              		//If there is no arc between i and j, set the precursor of J to - 1 
		}//for
		for(k = 0; k < G.vexnum; ++k) 
			for(i = 0; i < G.vexnum; ++i) 
				for(j = 0; j < G.vexnum; ++j)
					if(D[i][k] + D[k][j] < D[i][j]){   		//The path from i through k to j is shorter 
						D[i][j] = D[i][k]+D[k][j];    		//Update D[i][j] 
						Path[i][j] = Path[k][j];       			//Change the precursor of j to k 
					}//if 
}//ShortestPath_Floyed

void DisplayPath(AMGraph G , int begin ,int temp ){
	//Show shortest path
	if(Path[begin][temp] != -1){
		DisplayPath(G , begin ,Path[begin][temp]);
		cout << G.vexs[Path[begin][temp]] << "-->";
	}
}//DisplayPath

void main(){
	cout << "************Freudian algorithm**************" << endl << endl;
	AMGraph G;
	char start , destination;
	int num_start , num_destination;

	CreateUDN(G);
	
	cout <<endl;
	cout << "Directed net G Creation completed!" << endl;
	ShortestPath_Floyed(G);

	cout << "Please enter the names of the starting point and the ending point of the path in sequence:";
	cin >> start >> destination;
	num_start = LocateVex(G , start);
	num_destination = LocateVex(G , destination);

	DisplayPath(G , num_start , num_destination);
	cout << G.vexs[num_destination] << endl;
	cout << "The shortest path length is:" << D[num_start][num_destination] << endl;
	cout <<endl;
}//main

③. Topological sorting

For a project, we are most concerned about two issues:

  1. Whether the project can be successfully completed; (topological sorting)
  2. The minimum period of work necessary for the completion of the whole project. (critical path)

Directed acyclic graph ---- directed acyclic graph, referred to as DAG graph

AOV network: a directed graph is used to represent the subprojects of a project and their mutual restriction relationship, in which the vertex represents the activity and the arc represents the priority restriction relationship between activities. This directed graph is called the network in which the vertex represents the activity, which is referred to as AOV network for short.

AOV network should be a directed acyclic graph, namely DAG graph.

Topology sorting:

That is to arrange all vertices in the AOV network into a linear sequence (called topological sequence), which satisfies:
If there is a path from vertex vi to vj in AOV network, vertex vi in the linear sequence must precede vj

  1. Select a vertex without precursor in the directed graph and output it (i.e. the degree of penetration is 0)
  2. Deletes the vertex and all edges starting from it from the graph
  3. Repeat (1) (2) until there are no vertices without precursors
  4. If the number of vertices output at this time is less than that of the directed graph, it indicates that there are rings in the directed graph, otherwise the output vertex sequence is a topological sequence

Topology sorting implementation

  1. Calculate the in degree of a vertex, store it in the array indegree[i], and stack the vertices with 0 in degree.

  2. As long as the stack is not empty, repeat the following operations
    -The vertex vi at the top of the stack is out of the stack and saved in the topology sequence array topo;
    -For each adjacent point of vertex vi, the depth of vk is reduced by 1. If the depth of vk becomes 0, vk is put on the stack

  3. If the number of output vertices is less than the number of vertices of AOV network, there is a directed ring in the web address and topological sorting cannot be carried out. Otherwise, topological sorting is successful.

//Topological sorting

#include <iostream>
using namespace std;

#define MVNum 100                        	// max vertex 
#define OK 1	
#define ERROR 0 

typedef char VerTexType;

//----- adjacency table storage representation of graph ----- 
typedef struct ArcNode{                		//Edge node 
    int adjvex;                          	//The position of the vertex that the edge points to 
    struct ArcNode *nextarc;          		//Pointer to the next edge 
}ArcNode; 

typedef struct VNode{ 
    VerTexType data;                    	//Vertex information 
    ArcNode *firstarc;                		//Pointer to the first edge attached to the vertex 
}VNode, AdjList[MVNum];               		//AdjList indicates the adjacency table type 

typedef struct{ 
    AdjList vertices;                 		//Adjacency table 
	AdjList converse_vertices;				//Inverse adjacency table
    int vexnum, arcnum;              		//The current number of vertices and edges of a graph 
}ALGraph;
//- - - - - - - - - - - - - - - -

//----- definition of sequential stack -----
typedef struct{
	int *base;
	int *top;
	int stacksize;
}spStack;
//- - - - - - - - - - - - - - - -

int indegree[MVNum];						//The array indegree stores the penetration of a vertex
spStack S;

//------------Stack related operations----------------------
void InitStack(spStack &S){
	//Initialization stack
	S.base = new int[MVNum];
	if(!S.base)
		exit(1);
	S.top = S.base;
	S.stacksize = MVNum;
}//InitStack

void Push(spStack &S , int i){
	//Enter the stack
	if(S.top - S.base == S.stacksize)
		return;
	*S.top++ = i;
}//Push

void Pop(spStack &S , int &i){
	//Out of stack
	if(S.top == S.base)
		return;
	i = *--S.top;
}//Pop

bool StackEmpty(spStack S){
	//Determine whether the stack is empty
	if(S.top == S.base)
		return true;
	return false;
}//StackEmpty
//-------------------------------------------------

int LocateVex(ALGraph G , VerTexType v){
	//Determine the position of point v in G
	for(int i = 0; i < G.vexnum; ++i)
		if(G.vertices[i].data == v)
			return i;
		return -1;
}//LocateVex

int CreateUDG(ALGraph &G){ 
	//Create adjacency table and inverse adjacency table of directed graph G
	int i , k;
	
	cout <<"Please enter the total number of vertices and sides, separated by spaces:";
	cin >> G.vexnum >> G.arcnum;				//Enter the total number of vertices and edges 
    cout << endl;
	
	cout << "Enter a name for the point, such as a" << endl;
	
	for(i = 0; i < G.vexnum; ++i){          	//Input each point to construct the header node table
		cout << "Please enter page" << (i+1) << "Name of the first point:";
		cin >> G.vertices[i].data;           	//Enter vertex value
		G.converse_vertices[i].data = G.vertices[i].data;
		//The pointer field of the initialization header node is NULL 
		G.vertices[i].firstarc=NULL;			
		G.converse_vertices[i].firstarc=NULL;
    }//for
	cout << endl;
	cout << "Enter the vertex to which the edge is attached, such as a b" << endl;
	for(k = 0; k < G.arcnum;++k){        		//Input each edge to construct the adjacency table
		VerTexType v1 , v2;
		int i , j;
		cout << "Please enter page" << (k + 1) << "Vertex to which an edge is attached:";
		cin >> v1 >> v2;                		//Enter the two vertices to which an edge is attached
		i = LocateVex(G, v1);  j = LocateVex(G, v2);
		//Determine the position of v1 and v2 in G, that is, the sequence number of vertices in G.vertices 

		ArcNode *p1=new ArcNode;               	//Generate a new edge node * p1 
		p1->adjvex=j;                   		//The serial number of adjacent points is j
		p1->nextarc = G.vertices[i].firstarc;  G.vertices[i].firstarc=p1;
		//Insert the new node * p1 into the edge table header of vertex vi

		ArcNode *p2=new ArcNode;               	//Generate a new edge node * p1 
		p2->adjvex=i;                   		//The serial number of the inverse adjacent contact is i
		p2->nextarc = G.converse_vertices[j].firstarc;  G.converse_vertices[j].firstarc=p2;
		//Insert the new node * p1 into the edge table header of vertex vi
    }//for 
    return OK; 
}//CreateUDG

void FindInDegree(ALGraph G){
	//Calculate the penetration of each vertex and store it in the array indegree 
	int i , count;

	for(i = 0 ; i < G.vexnum ; i++){
		count = 0;
		ArcNode *p = G.converse_vertices[i].firstarc;
		if(p){
			while(p){
				p = p->nextarc;
				count++;
			}
		}
		indegree[i] = count;
	}
}//FindInDegree

int TopologicalSort(ALGraph G , int topo[]){ 
    //Directed graph G adopts adjacency table storage structure 
    //If G has no loop, generate a topological sequence topo [] of G and return OK, otherwise ERROR 
	int i , m;
    FindInDegree(G);              				//Calculate the penetration of each vertex and store it in the array indegree 
    InitStack(S);                          		//Stack S initialized to empty 
    for(i = 0; i < G.vexnum; ++i)
		if(!indegree[i]) Push(S, i);     		//If the entry degree is 0, enter the stack 
	m = 0;                               		//The initial count of vertices is 0 
	while(!StackEmpty(S)){                		//Stack S is not empty 
		Pop(S, i);                          	//Push the top of the stack vi out of the stack
		topo[m]=i;                         		//Save vi in topology sequence array topo 
		++m;                             		//Count output vertices 
		ArcNode *p = G.vertices[i].firstarc;    //p points to the first adjacent contact of vi 
		while(p){
			int k = p->adjvex;					//vk is the adjacency point of vi   
			--indegree[k];                   	//The penetration of each adjacent point of vi minus 1 
			if(indegree[k] ==0)  Push(S, k);	//If the input degree is reduced to 0, it will be put into the stack 
			p = p->nextarc;                		//p points to the next adjacent node of vertex vi 
		}//while 
	}//while
	
	if(m < G.vexnum)  return ERROR;    			//The directed graph has a loop 
	else return OK;
}//TopologicalSort 

int main(){
	cout << "************Topological sorting**************" << endl << endl;
	ALGraph G;
	CreateUDG(G);
	int *topo = new int [G.vexnum];
	
	cout << endl;
	cout << "The adjacency table and inverse adjacency table of directed graph are created!" << endl << endl;

	if(TopologicalSort(G , topo)){
		cout << "The topological ordered sequence of the directed graph is:";
		for(int j = 0 ; j < G.vexnum; j++){
			if(j != G.vexnum - 1)
				cout << G.vertices[topo[j]].data << " , ";
			else
				cout << G.vertices[topo[j]].data << endl << endl;
		}//for
	}
	else
		cout << "There are rings in the network, unable to sort topology!" <<endl << endl;
	return OK;
}//main

④. critical path

AOE network (Activity On Edges) - a network with edges representing activities, a directed graph representing the sub projects of a project and their mutual constraints, an arc representing activities, a weight representing the duration of activities, and a vertex representing events (start or end time of activities). This kind of directed graph is called a network with edges representing activities, which is called AOE network for short; AOE network is used to estimate the completion time of the project.

nameexplain
Source pointVertices with 0 penetration (only 1)
Meeting pointVertices with degree 0 (only 1)
path length Sum of duration of each activity on the path
Completion time of the whole projectThe longest path from the source point to the sink point of a directed graph
critical pathThe path with the longest path length
Key activitiesFor the activities on the critical path, the increase of the weight on the edge will increase the length of the longest path on the directed graph.
ve(j)Indicates the earliest occurrence time of event V
vl(j)Indicates the latest occurrence time of event V
e(i)Indicates the earliest start time of the activity ai
l(i)Indicates the latest start time of the activity ai
l(i)-e(i)Indicates the time allowance to complete the activity ai

Note: in an AOE network, there can be more than one critical path.

critical path


//Critical path algorithm

#include <iostream>
using namespace std;

#define MVNum 100                        	// max vertex 
#define BDNum MVNum * (MVNum - 1) 			// Maximum number of sides
#define OK 1	
#define ERROR 0 

typedef char VerTexType;

//----- adjacency table storage representation of graph ----- 
typedef struct ArcNode{                		//Edge node 
    int adjvex;                          	//The position of the vertex that the edge points to
	int weight;								//Weight 
    struct ArcNode *nextarc;          		//Pointer to the next edge 
}ArcNode; 

typedef struct VNode{ 
    VerTexType data;                    	//Vertex information
    ArcNode *firstarc;                		//Pointer to the first edge attached to the vertex 
}VNode, AdjList[MVNum];               		//AdjList indicates the adjacency table type 

typedef struct{ 
    AdjList vertices;                 		//Adjacency table 
	AdjList converse_vertices;				//Inverse adjacency table
    int vexnum, arcnum;              		//The current number of vertices and edges of a graph 
}ALGraph;
//- - - - - - - - - - - - - - - -

//----- definition of sequential stack -----
typedef struct{
	int *base;
	int *top;
	int stacksize;
}spStack;
//- - - - - - - - - - - - - - - -

int indegree[MVNum];						//The array indegree stores the penetration of a vertex
int ve[BDNum];								//Earliest occurrence time of event vi
int vl[BDNum];								//Latest occurrence time of event vi
int topo[MVNum];							//Record the vertex sequence number of the topology sequence
spStack S;

//----------------Stack operation--------------------
void InitStack(spStack &S){
	//Initialization of stack
	S.base = new int[MVNum];
	if(!S.base)
		exit(1);
	S.top = S.base;
	S.stacksize = MVNum;
}//InitStack

void Push(spStack &S , int i){
	//Push 
	if(S.top - S.base == S.stacksize)
		return;
	*S.top++ = i;
}//Push

void Pop(spStack &S , int &i){
	//Out of stack
	if(S.top == S.base)
		return;
	i = *--S.top;
}//Pop

bool StackEmpty(spStack S){
	//Determine whether the stack is empty
	if(S.top == S.base)
		return true;
	return false;
}//StackEmpty
//---------------------------------------

int LocateVex(ALGraph G , VerTexType v){
	//Determine the position of point v in G
	for(int i = 0; i < G.vexnum; ++i)
		if(G.vertices[i].data == v)
			return i;
		return -1;
}//LocateVex

int CreateUDG(ALGraph &G){ 
	//Create adjacency table and inverse adjacency table of directed graph G
	int i , k;
	
	cout <<"Please enter the total number of vertices and sides, separated by spaces:";
	cin >> G.vexnum >> G.arcnum;				//Enter the total number of vertices and edges 
    cout << endl;

	cout << "Enter a name for the point, such as a" << endl;
	
	for(i = 0; i < G.vexnum; ++i){          		//Input each point to construct the header node table
		cout << "Please enter page" << (i+1) << "Name of the first point:";
		cin >> G.vertices[i].data;           		//Enter vertex value
		G.converse_vertices[i].data = G.vertices[i].data;
		//The pointer field of the initialization header node is NULL 
		G.vertices[i].firstarc=NULL;			
		G.converse_vertices[i].firstarc=NULL;
    }//for
	cout << endl;

	cout << "Enter the vertex to which the edge is attached and its weight, such as a b 3" << endl;

	for(k = 0; k < G.arcnum;++k){        			//Input each edge to construct the adjacency table
		VerTexType v1 , v2;
		int i , j , w;
		cout << "Please enter page" << (k + 1) << "Vertices attached to edges and their weights:";
		cin >> v1 >> v2 >> w;                		//Enter the two vertices to which an edge is attached
		i = LocateVex(G, v1);  j = LocateVex(G, v2);
		//Determine the position of v1 and v2 in G, that is, the sequence number of vertices in G.vertices 

		ArcNode *p1=new ArcNode;               		//Generate a new edge node * p1 
		p1->adjvex=j;                   			//The serial number of adjacent points is j
		p1->nextarc = G.vertices[i].firstarc;  G.vertices[i].firstarc=p1;
		p1->weight = w;
		//Insert the new node * p1 into the edge table header of vertex vi

		ArcNode *p2=new ArcNode;               		//Generate a new edge node * p1 
		p2->adjvex=i;                   			//The serial number of the inverse adjacent contact is i
		p2->nextarc = G.converse_vertices[j].firstarc;  G.converse_vertices[j].firstarc=p2;
		p2->weight = w;
		//Insert the new node * p1 into the edge table header of vertex vi
    }//for 
    return OK; 
}//CreateUDG

void FindInDegree(ALGraph G){
	//Calculate the penetration of each vertex and store it in the array indegree 
	int i , count;

	for(i = 0 ; i < G.vexnum ; i++){
		count = 0;
		ArcNode *p = G.converse_vertices[i].firstarc;
		if(p){
			while(p){
				p = p->nextarc;
				count++;
			}
		}//if
		indegree[i] = count;
	}//for
}//FindInDegree

int TopologicalOrder(ALGraph G , int topo[]){ 
    //Directed graph G adopts adjacency table storage structure 
    //If G has no loop, generate a topological sequence topo [] of G and return OK, otherwise ERROR 
	int i , m;
    FindInDegree(G);              				//Calculate the penetration of each vertex and store it in the array indegree 
    InitStack(S);                          		//Stack S initialized to empty 
    for(i = 0; i < G.vexnum; ++i)
		if(!indegree[i]) Push(S, i);     		//If the entry degree is 0, enter the stack 
	m = 0;                               		//Count the output vertices, initially 0 
	while(!StackEmpty(S)){                		//Stack S is not empty 
		Pop(S, i);                          	//Push the top of the stack vi out of the stack
		topo[m]=i;                         		//Save vi in topology sequence array topo 
		++m;                             		//Count output vertices 
		ArcNode *p = G.vertices[i].firstarc;    //p points to the first adjacent contact of vi 
		while(p){
			int k = p->adjvex;					//vk is the adjacency point of vi   
			--indegree[k];                   	//The penetration of each adjacent point of vi minus 1 
			if(indegree[k] ==0)  Push(S, k);	//If the input degree is reduced to 0, it will be put into the stack 
			p = p->nextarc;                		//p points to the next adjacent node of vertex vi 
		}//while 
	}//while
	
	if(m < G.vexnum)  return ERROR;    			//The directed graph has a loop 
	else return OK;
}//TopologicalOrder

int CriticalPath(ALGraph G){ 
    //G is the directed network stored in the adjacency table and outputs the key activities of G
	int n , i , k , j , e , l;
    if (!TopologicalOrder(G, topo))  return ERROR; 
    //Call the topology sorting algorithm to save the topology sequence in topo. If the call fails, there is a directed ring and ERROR is returned 
    n = G.vexnum;                  				//n is the number of vertices 
    for(i = 0; i < n; i++)               		//Set the initial value of 0 for the earliest occurrence time of each event 
		ve[i] = 0; 


    /*――――――――――Find the earliest occurrence time of each event in topological order*/ 
    for(i = 0;i < n; i++){                 
		k = topo[i];                   			//Gets the vertex sequence number k in the topology sequence             
		ArcNode *p = G.vertices[k].firstarc;    //p points to the first adjacent vertex of k  
		while(p != NULL){            			//Update the earliest occurrence time of all adjacent vertices of k in turn   
			j = p->adjvex;               		//j is the sequence number of adjacent vertices                   
			if(ve[j] < ve[k] + p->weight)    	//Earliest occurrence time of updating vertex j ve[j] 
				ve[j] = ve[k] + p->weight;     
			p = p->nextarc;              		//p points to the next adjacent vertex of k  
		} //while 
    } //for 

    for(i=0;i<n;i++)                 			//Set the initial value ve[n-1] for the latest occurrence time of each event 
		vl[i]=ve[n-1];
	
    /*――――――――――Calculate the latest occurrence time of each event in reverse topological order*/ 
    for(i = n - 1;i >= 0; i--){               
		k = topo[i];                   			//Gets the vertex sequence number k in the topology sequence             
		ArcNode *p = G.vertices[k].firstarc;    //p points to the first adjacent vertex of k  
		while(p != NULL){            			//Update the latest occurrence time of k according to the adjacency point of k   
			j = p->adjvex;              		//j is the sequence number of adjacent vertices                   
			if(vl[k] > vl[j] - p->weight)    	//Update the latest occurrence time of vertex K vl[k] 
				vl[k] = vl[j] - p->weight;       
			p = p->nextarc;              		//p points to the next adjacent vertex of k  
		}//while 
    }//for 

    /*――――――――――――Judge whether each activity is a key activity ――――――――――――*/
	cout << endl;
	cout << "The critical activity path is:";
    for(i = 0;i < n; i++){                		//vi is the start point for each activity 
        ArcNode *p = G.vertices[i].firstarc;    //p points to the first adjacent vertex of i  
        while(p != NULL) {    
			j = p->adjvex;             			//j is the sequence number of adjacent vertices of i    
			e = ve[i];                 			//Calculate the earliest start time of the activity < VI, VJ > 
			l = vl[j] - p->weight;      		//Calculate the latest start time of the activity < VI, VJ > 
			if(e == l)               			//If it is a key activity, output < VI, VJ > 
				cout << G.vertices[i].data << "-->" << G.vertices[j].data << " ";
			p = p->nextarc;              		//p points to the next adjacent vertex of i  
		} //while 
	} //for  
	return OK;
}//CriticalPath

int main(){
	cout << "************Critical path algorithm**************" << endl << endl;
	ALGraph G;
	CreateUDG(G);
	int *topo = new int [G.vexnum];
	
	cout << endl;
	cout << "Directed graph creation completed!" << endl << endl;
	
	if(!CriticalPath(G))
		cout << "There are rings in the network, unable to sort topology!" <<endl << endl;
	cout << endl;
	return OK;
}//main

Example:


6. Summary

(1) According to different classification rules, graphs can be divided into many types: undirected graph, directed graph, complete graph, connected graph, strongly connected graph, weighted graph (Network), sparse graph and dense graph. Adjacency point, path, loop, degree, connected component and spanning tree are important terms commonly used in graph algorithm design.

(2) There are two kinds of storage methods of graphs: edge set representation and link representation. Among them, the adjacency matrix represented by edge set includes adjacency table, cross linked table and adjacency multiple table. Adjacency matrix representation is simple to realize by using two-dimensional array to represent the relationship between elements; Adjacency list, cross linked list and adjacency multiple list all belong to chain storage structure, which is more complex to implement. The specific storage representation in practical application can be selected according to the type of graph and the basic idea of actual algorithm. Adjacency matrix and adjacency table are two common storage structures. The comparison between them is shown in the figure below.

(3) graph traversal algorithm is the basis of realizing other operations of graph. There are two traversal methods of * * graph: depth first search traversal and breadth first search traversal** The depth first search traversal is similar to the pre order traversal of the tree, which is realized by means of the stack structure (recursion); Breadth first search traversal is similar to the hierarchical traversal of tree, which is realized by means of queue structure. The only difference between the two traversal methods is that the order of accessing vertices is different, so the time complexity is the same. When the adjacency matrix is used for storage, the time complexity is O(n2), and when the adjacency table is used for storage, the time complexity is O(n+e).

(4) Many algorithms of graph are closely related to practical applications. The commonly used algorithms include constructing the minimum spanning tree algorithm, solving the shortest path algorithm, topological sorting and solving the critical path algorithm.
① There are prim algorithm and Kruskal algorithm to construct the minimum spanning tree, both of which can achieve the same purpose. However, the core of the former algorithm is the merging point, and the time complexity is O(n2), which is suitable for dense networks; The latter is the merging edge, and the time complexity is O(elog2e), which is suitable for sparse networks.
② Shortest path algorithm: one is dijestra algorithm, which finds the shortest path from a source point to other vertices. The solution process is to generate the shortest path in the order of increasing path length, and the time complexity is O(n2); The other is the Freudian algorithm, which finds the shortest path between each pair of vertices, and the time complexity is O(n3). In terms of implementation form, this algorithm is more concise than calling dijestra algorithm n times with each vertex in the graph as the source point.
③ Topological sorting and critical path are the applications of directed acyclic graph. Topological sorting is based on a directed graph with vertices representing activities, that is, AOV network. For a directed graph without a ring, all vertices in the graph must be arranged into a linear sequence, that is, a topological sequence, which is not unique. The graph is represented by adjacency table, and the time complexity of topological sorting is O(n+e).
④ The critical path algorithm is based on a directed graph with arcs representing activities, that is, AOE network. The activities on the critical path are called critical activities. These activities are the key to affect the project progress. Their advance or delay will advance or delay the whole project. The critical path is not unique. The implementation of critical path algorithm is based on topological sorting, and the graph is represented by adjacency table. The time complexity of critical path algorithm is O(n+e).

7. Examples and Applications


  1. The following functions are realized by programming:
    (1) The number of vertices, edges and vertex pairs of each edge of an undirected graph are input, and an undirected graph represented by adjacency matrix is established.
    (2) The graph is traversed by depth first search and breadth first search, and its traversal sequence is output respectively.

Test sample undirected graph

Operation results

#include <bits/stdc++.h>
using namespace std;
#define MVNum 100
#define MAXQSIZE 100
typedef char VerTexType;
typedef int ArcType;
//Storage representation of adjacency matrix of graph
typedef struct
{
    VerTexType vexs[MVNum];
    ArcType arcs[MVNum][MVNum];
    int vexnum, arcnum;
} Graph;
//Definition and operation of queue
typedef struct
{
    ArcType *base;
    int front;
    int rear;
} sqQueue;
bool visited[MVNum];
bool visited1[MVNum];
int FirstAdjVex(Graph G, int v);
int NextAdjVex(Graph G, int v, int w);
//Build empty queue Q
void InitQueue(sqQueue &Q)
{
    Q.base = new ArcType[MAXQSIZE];
    if (!Q.base)
        exit(1);
    Q.front = Q.rear = 0;
}
//Insert a new tail element with element e as Q
void EnQueue(sqQueue &Q, ArcType e)
{
    if ((Q.rear + 1) % MAXQSIZE == Q.front)
        return;
    Q.base[Q.rear] = e;
    Q.rear = (Q.rear + 1) % MAXQSIZE;
}
//Determine whether it is an empty team
bool QueueEmpty(sqQueue Q)
{
    if (Q.rear == Q.front)
        return true;
    return false;
}
//The team head element is out of the team and placed as u
void DeQueue(sqQueue &Q, ArcType &u)
{
    u = Q.base[Q.front];
    Q.front = (Q.front + 1) % MAXQSIZE;
}
//Determine the position of point v in G
int LocateVex(Graph G, VerTexType v)
{
    for (int i = 0; i < G.vexnum; ++i)
        if (G.vexs[i] == v)
            return i;
    return -1;
}
//The adjacency matrix representation is used to create undirected network G
void CreateUDN(Graph &G)
{
    int i, j, k;
    cout << "Enter the total number of vertices and sides, separated by spaces:(Example: 3 (2)";
    cin >> G.vexnum >> G.arcnum;
    cout << endl;

    cout << "Enter the name of the point (example: a)" << endl;

    for (i = 0; i < G.vexnum; ++i)
    {
        cout << "Please enter page" << (i + 1) << "Name of the first point:";
        cin >> G.vexs[i];
    }
    cout << endl;

    for (i = 0; i < G.vexnum; ++i)
        for (j = 0; j < G.vexnum; ++j)
            G.arcs[i][j] = 0;
    cout << "Enter the vertex to which the edge is attached (example) a b)" << endl;
    for (k = 0; k < G.arcnum; ++k)
    {
        VerTexType v1, v2;
        cout << "Please enter page" << (k + 1) << "Vertex to which an edge is attached:";
        cin >> v1 >> v2;
        i = LocateVex(G, v1);
        j = LocateVex(G, v2);
        G.arcs[j][i] = G.arcs[i][j] = 1;
    }
}
// DFS
void DFS(Graph G, int v)
{
    int w;
    cout << G.vexs[v] << "    ";
    visited[v] = true;
    for (w = 0; w < G.vexnum; w++)
        if ((G.arcs[v][w] != 0) && (!visited[w]))
            DFS(G, w);
}
// BFS
void BFS(Graph G, int v)
{
    sqQueue Q;
    ArcType u;
    ArcType w;

    cout << G.vexs[v] << "    ";
    visited[v] = true;
    InitQueue(Q);
    EnQueue(Q, v);
    while (!QueueEmpty(Q))
    {
        DeQueue(Q, u);
        for (w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w))
        {
            if (!visited[w])
            {
                cout << G.vexs[w] << "    ";
                visited[w] = true;
                EnQueue(Q, w);
            }
        }
    }
}
//Returns the first adjacent contact of v
int FirstAdjVex(Graph G, int v)
{
    int i;
    for (i = 0; i < G.vexnum; ++i)
    {
        if (G.arcs[v][i] == 1 && visited[i] == false)
            return i;
    }
    return -1;
}
//Returns the next adjacent node of v relative to w
int NextAdjVex(Graph G, int v, int w)
{
    int i;
    for (i = w; i < G.vexnum; ++i)
    {
        if (G.arcs[v][i] == 1 && visited[i] == false)
            return i;
    }
    return -1;
}
int main()
{
    Graph G;
    CreateUDN(G);
    cout << endl;
    cout << "Undirected graph G Creation completed!" << endl
         << endl;
    cout << "Input traversal undirected graph G Starting point of:";
    VerTexType c;
    cin >> c;
    int i;
    for (i = 0; i < G.vexnum; ++i)
    {
        if (c == G.vexs[i])
            break;
    }
    cout << endl;
    while (i >= G.vexnum)
    {
        cout << "This point does not exist, please re-enter!" << endl;
        cout << "Please enter the starting point of traversing the connected graph:";
        cin >> c;
        for (i = 0; i < G.vexnum; ++i)
        {
            if (c == G.vexs[i])
                break;
        }
    }
    cout << "Depth first search traversal undirected graph G result:" << endl;
    DFS(G, i);

    for (int j = 1; j <= G.vexnum; j++)
        visited[j] = false;

    cout << endl;

    cout << "Breadth first search traversal undirected graph G result:" << endl;
    BFS(G, i);

    cout << endl;
    return 0;
}

Keywords: C data structure Graph Theory Minimum Spanning Tree

Added by theelectricwiz on Sun, 20 Feb 2022 16:17:45 +0200