Data Structures and Algorithms·Chapter 7 [Figure]

picture

Most of the definitions have been learned in Discrete Mathematics II, so I won’t go into details about the known or common ones.

  • A graph with arc or edge weights is called a directed network or an undirected network respectively.
  • If the number of edges or arcs e < n l o g n e<nlogn It is<nlogn、A rare picture made by another name, a dense picture made by another name.
  • For a directed graph,If there is a directed path between any two verticesAny two vertices are reachable to each other is the strongly connected component, then this directed graph is called a strongly connected graph.
  • For an undirected graph, any two points must have a path (connected)

storage structure

Adjacency matrix:

typedef struct {
    
    
    char* vexs[MAX_VERTEX_NUM]; // 顶点列表,每个元素为一个字符串,代表一个顶点
    ArcCell arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵,二维数组表示从一个顶点到另一个顶点的弧,每个弧存储了该弧的相关信息
    int vexnum; // 顶点个数
    int arcnum; // 弧个数
    GraphKind kind; // 图的类型
} MGraph;

Adjacency list:

typedef struct ArcNode {
    
    
    int adjvex; // 该弧所指向的顶点的位置
    struct ArcNode* nextarc; // 指向下一条弧的指针
    char* info; // 该弧相关信息的指针
} ArcNode;//弧的结构

typedef struct VNode {
    
    
    char* data; // 顶点信息
    ArcNode* firstarc; // 指向第一条依附该顶点的弧
} VNode, AdjList[MAX_VERTEX_NUM];

cross linked list
Insert image description here

<v,w>表示从 v 到 w 的一条弧,并称 v 为弧尾,w 为弧头。

Traverse

Depth-first search dfs (this is relatively familiar, but I won’t go into details)
A non-recursive writing method:

void DFS(Graph G, int v) {
    
    
    int w;
    InitStack(&S); // 初始化栈S
    Push(&S, v);
    visited[v] = TRUE; // 标记起点v已访问
    while (!StackEmpty(S)) {
    
    
        Pop(&S, &v); // 取出栈顶元素v
        Visit(v); // 访问v
        w = FirstAdjVex(G, v); // 求v的第一个邻接点w
        while (w >= 0) {
    
    
            if (!visited[w]) {
    
     // w为v的尚未访问的邻接顶点
                Push(&S, w); // 将w入栈
                visited[w] = TRUE; // 标记w为已访问
            }
            w = NextAdjVex(G, v, w); // 求v相对于w的下一个邻接点
        } // end while
    } // end while
}

Breadth-first search bfs (similar to the level traversal in the chapter ‘Tree’)

void BFSTraverse(Graph G, Status(*Visit)(int)) {
    
    
    int v, w;
    Status status; // 初始化一个状态变量
    Queue Q; // 定义辅助队列Q
    for (v = 0; v < G.vexnum; ++v)
        visited[v] = FALSE; // 初始化访问标志
    InitQueue(&Q); // 置空的辅助队列Q
    for (v = 0; v < G.vexnum; ++v) {
    
    
        if (!visited[v]) {
    
     // v尚未访问
            visited[v] = TRUE; // 标记v为已访问
            status = Visit(v); // 访问v
            if (status == ERROR) return; // 如果访问失败,则返回错误
            EnQueue(&Q, v); // 将v入队列
            while (!QueueEmpty(Q)) {
    
     // 队列不为空时执行循环
                DeQueue(&Q, &u); // 队头元素出队并置为u
                for (w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w)) {
    
    
                    if (!visited[w]) {
    
     // w为u的尚未访问的邻接顶点
                        visited[w] = TRUE; // 标记w为已访问
                        status = Visit(w); // 访问w
                        if (status == ERROR) return; // 如果访问失败,则返回错误
                        EnQueue(&Q, w); // 将w入队列
                    } // if
                } // for
            } // while
        }
    }
}

for (w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w)) Take a closer look at this piece of code

minimum spanning tree

  1. Spanning tree:
    is a minimally connected subgraph, which contains all the vertices in the graph but only n-1 edges.

  2. Minimum spanning tree:
    If the undirected connected graph is a weighted graph, then among all its spanning trees there must be a spanning tree whose sum of edge weights is the minimum, This spanning tree is called the minimum cost spanning tree, or minimum spanning tree for short.

K r u s k a l Kruskal Kruskal Arithmetic special point: 正边归并、适于Quest Rare 罏网's minimum generation 树.

P r i m e Prime PrimeAlgorithm features: convert vertices Merging, regardless of the number of edges, is suitable for dense networks.

Prim's algorithm

During the construction process of the spanning tree, n vertices in the graph belong to two sets: the vertex set U that has fallen on the spanning tree and the vertex set V-U that has not yet fallen on the spanning tree. Then the vertex sum in all connected U should be Select the edge with the smallest weight among the edges of the vertices in V-U.

Set an auxiliary arrayclosedge. For each vertex in the current V-U set, there is a corresponding component in the auxiliary arrayclosedge[i-1], which includes two Domain, wherelowcost stores the weight on this edge. For each vertex vi ∈ V-U, the following formula is established:

closedge[i-1].lowcost = Min { cost(u, v) | u ∈ U }

where cost(u, v) represents the weight of edge (u, v). Obviously, lowcost records the weight of the edge with the smallest weight between the current node and the selected node.

struct {
    
    
    VertexType adjvex;  // U集中的顶点序号
    VRType lowcost;     // 边的权值
} closedge[MAX_VERTEX_NUM];

algorithm

void MiniSpanTree_P(MGraph G, VertexType u) {
    
    
    int i, j, k;
    k = LocateVex(G, u);
    for (j = 0; j < G.vexnum; ++j) {
    
    
        if (j != k) {
    
    
            closedge[j].adjvex = u;
            closedge[j].lowcost = G.arcs[k][j].adj;
        }
    }
    closedge[k].lowcost = 0;
    for (i = 1; i < G.vexnum; ++i) {
    
    
        k = minimum(closedge);  // 求出加入生成树的下一个顶点(k)
        printf("(%d, %d) ", closedge[k].adjvex, G.vexs[k]);  // 输出生成树上一条边
        closedge[k].lowcost = 0;  // 第k顶点并入U集
        for (j = 0; j < G.vexnum; ++j) {
    
     // 修改其它顶点的最小边
            if (G.arcs[k][j].adj < closedge[j].lowcost) {
    
    
                closedge[j].adjvex = G.vexs[k];
                closedge[j].lowcost = G.arcs[k][j].adj;
            }
        }
    }
}

k = minimum(closedge);
if (G.arcs[k][j].adj < closedge[j].lowcost) { closedge[j].adjvex = G.vexs[k]; closedge[j].lowcost = G.arcs[k][j].adj; }
These two codes are worth looking at
The time complexity is O ( n 2 ) O(n^2) O(n2)

Kruskal's algorithm

  1. Construct a subgraph containing only n vertices. SG

  2. Start from the edge with the smallest weight. If adding this edge will not produce a cycle in SG, add this edge on SG side.

  3. Repeat the above steps until SG is added with n-1 edges.

  4. Repeat the above steps again to construct another minimum spanning tree.

Specific reference
Time and effort O ( e l o g e ) O(eloge) O(eloge)

Topological sorting, critical path

topological sort

Applies todirected acyclic graph

Topological sorting is a special sorting method that is based on the dependency relationship between nodes in a directed graph and obtains a topologically ordered sequence through a series of operations. The specific implementation method is: according to the order relationship given by the directed graph, the vertices in the graph are arranged into a linear sequence. For the vertices in the directed graph that have no limited order relationship, any order relationship can be artificially added. The resulting linear sequence of vertices is called a topologically ordered sequence.

Insert image description here

The implementation steps of topological sorting are as follows:

  1. Select a vertex without a predecessor from the directed graph and output it;
  2. Delete this vertex and all arcs ending with it from the directed graph;
  3. Repeat steps 1 and 2 until the graph is empty, or the graph is not empty but no vertex without a predecessor is found. The latter case indicates the existence of cycles in the directed graph.

Critical Path

In the analysis of the critical path, we need to calculate the earliest and latest occurrence time of each event (vertex):

  1. Earliest occurrence time of event (vertex) v e ( j ) ve(j) ve(j) etc. V j Vj Vj The longest path length;
    This time determines all the paths starting with V j Vj a>Vj is the earliest start time of the activity represented by the tail arc.

  2. The latest occurrence time of the event (vertex) v l ( k ) vl(k) vl(k) represents the latest time when the event occurs without delaying the completion of the entire project;
    v l ( k ) vl(k) vl(k) Time to complete process decreases V k Vk Vk The longest path length to the sink.

In critical path analysis, the formula for calculating the time of event occurrence is as follows (The meeting point can be understood as the last point):

The formula for calculating the time of event:

- ve(源点) = 0;
- ve(k) = Max {ve(j) + dut(<j, k>)}

   其中,dut(<j,k>) 表示从顶点 j 到顶点 k 的活动所需的时间或耗费。

- vl(汇点) = ve(汇点);
- vl(j) = Min {vl(k) - dut(<j, k>)}

   其中,vl(j) 表示从顶点 j 开始到工程结束所能容忍的最大延迟时间。

In critical path analysis, the order of solving the earliest occurrence time ve and the latest occurrence time vl is as follows:

  1. v e and ve Order: In topological order, starting from the source point, calculate the earliest occurrence time of each vertex in sequence.

  2. v l vl vl Sequence: In the reverse topological order, starting from the sink point, calculate the latest occurrence time of each vertex in turn.

shortest path

  1. Single source shortest path algorithm - Dijkstra algorithm:
    This algorithm can solve the shortest path from the source point to all other vertices, but it requires that there are no There are negative weight edges.

  2. The shortest path algorithm between all vertices - Floyd (Floyd) algorithm:
    This algorithm can solve the shortest path between any two vertices in the graph and can handle the A graph with negative weight edges.

In graph theory, the concepts of shortest path and shortest path length are as follows:

  1. For an unweighted graph, there may be multiple paths from one node to another, and the path with the shortest path length is called the shortest path. Its length is called the shortest path length.

  2. For a weighted graph, there may be multiple paths from one node to another. The path with the shortest weighted path length is called the shortest path. Its weighted path length is called the shortest path length.

Specific reference

exercise

connected components of a graph

Insert image description here
Insert image description here
Main idea 3 ​​3 3sum 5 5 5

Critical Path

Insert image description here
Insert image description here
关键路道—— v e ve ve v l vl vlThe same point is on the critical path

Dijkstra's algorithm

Insert image description here
Insert image description here
Just take a look, it's relatively simple.

Depth first search, whether the path exists in the adjacency list

Try to write an algorithm based on the depth-first search strategy of the graph to determine whether there is a vertex in a directed graph stored in an adjacency list v i v_i iniAchieved point v j v_j inj path diameter ( i ≠ j i≠j i=j) Note: The basic operations of the graph involved in the algorithm must be implemented on this storage structure.

#define MAX 100
typedef struct Arc {
    
    
    int vex;
    struct Arc *next;
    int info;
} Arc;
typedef struct Vertex {
    
    
    int info;
    Arc *first;
} Vertex;
Vertex vertex[MAX]; // 图的顶点集合,最多储存 MAX 个顶点
int visited[MAX]; // 记录每个顶点是否被访问过
int DFS(int i, int j) {
    
     // 从第 i 个顶点开始,寻找是否有一条路径连接到第 j 个顶点
    Arc* p; 
    if(i == j) return 1; // 如果 i 和 j 相同,返回 1 表示有路径连接
    else {
    
    
        visited[i] = 1; // 标记 i 为已访问
        for(p = vertex[i].first; p != NULL; p = p->next) {
    
     // 遍历顶点 i 的所有邻居
            int k = p->vex; // 取出邻居的编号
            if(!visited[k] && DFS(k, j)) return 1; // 如果邻居没有被访问过且与 j 有路径连接,返回 1
        }
        return 0; // 没有找到从 i 到 j 的路径,返回 0
    }
}

It’s still a little difficult to understand. Just look at the data structure code of this adjacency list and draw a picture to help you understand.

Still the requirements of the previous question, but search widely

#define MAX 100
typedef struct Arc {
    
    
    int vex;
    struct Arc *next;
    int info;
} Arc;
typedef struct Vertex {
    
    
    int info;
    Arc *first;
} Vertex;
Vertex vertex[MAX]; // 图的顶点集合,最多储存 MAX 个顶点
bool visited[MAX]; // 记录每个顶点是否被访问过
int BFS(int i, int j) {
    
    
    Arc* p; 
    Queue Q;
    initQueue(&Q);
    visited[i] = 1; 
    enQueue(&Q, i); 
    while(!isEmpty(Q)) {
    
    
        int cur = deQueue(&Q); 
        if(cur == j)  return 1;
        for(p = vertex[cur].first; p != NULL; p = p->next) {
    
    
            int k = p->vex; 
            if(!visited[k]) {
    
     
                visited[k] = 1; 
                enQueue(&Q, k); 
            }
        }
    }
    return 0;
}

Dijkstra algorithm based on adjacency list storage structure

Insert image description here

Guess you like

Origin blog.csdn.net/qq_61786525/article/details/131094834