跳转至

图

#include <stdio.h>
#include <stdlib.h>

typedef char VertexType; // 顶点类型
typedef int EdgeType; // 边上的权值
#define MAXVEX 100 // 最大顶点数
#define INF 65535 // 如果两个顶点之间不可达,用无穷表示距离
#define DIRECTED true // 是否为有向图

typedef struct {
    VertexType vexs[MAXVEX]; // 顶点表
    EdgeType arc[MAXVEX][MAXVEX]; // 邻接矩阵,可看做边表
    int vexNum, edgeNum; // 图中当前的顶点数和边数
} MGraph;

// 创建邻接矩阵
int Graph_Create (MGraph &G) {
    int vi, vj, weight;
    // 输入顶点数和边数
    printf("请输入顶点数:");
    scanf("%d", &G.vexNum);
    printf("请输入边数:");
    scanf("%d", &G.edgeNum);

    for (int i = 0; i < G.vexNum; i++) { // 为每个顶点初始化信息
        printf("请输入第 %d 个的顶点名称: ", i + 1);
        scanf(" %c", &G.vexs[i]);
    }
    for (int i = 0; i < G.vexNum; i++) { // 初始化顶点之间的权值 默认为无穷
        for (int j = 0; j < G.vexNum; j++) {
            G.arc[i][j] = INF;
        }
    }

    printf("下标为 -1 -1 则退出创建边\n");
    for(int i = 0; i < G.edgeNum; i++){ // 根据边的条数,为每一条边赋值
        printf("请输入要创建边的下标 v1 v2 ");
        scanf("%d %d", &vi, &vj);
        if (vi == -1 && vj == -1) break;
        printf("请输入边为[%d][%d]的权值 weight = ", vi, vj);
        scanf("%d", &weight);
        G.arc[vi][vj] = weight;
        // 在无向网中满足图对称性,即Vi-Vj 和Vj-Vi的距离相等,实际就是一条路径
        if (!DIRECTED) {
            G.arc[vj][vi] = weight;
        }
    }
}

// 打印图
void Graph_Show (MGraph G) {
    // 打印顶点
    for (int i = 0; i < G.vexNum; i++)
        printf("%c", G.vexs[i]);
    printf("\n");
    // 打印邻接矩阵
    for(int i = 0; i < G.vexNum; i++){
        for(int j = 0; j < G.vexNum; j++){
            if(G.arc[i][j] == INF) printf("%6s", "∞");
            else printf("%6d", G.arc[i][j]);
        }
        printf("\n");
    }
}

int main () {
    MGraph G;
    Graph_Create(G);
    Graph_Show(G);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>

#define MaxVertexNum 26
// 是否为有向图
#define DIRECTED true
typedef char VertexType;
typedef int ArcWeight;

// 边表结点
typedef struct ArcNode {
    int adjvex; // 该边指向的顶点下标
    ArcWeight weight; // 权值
    struct ArcNode *next; // 指向下一条边的指针
} ArcNode;

// 顶点表结点
typedef struct VNode{
    VertexType data; // 顶点信息
    ArcNode *first; // 指向该顶点的第一条边的指针
} VNode, AdjList[MaxVertexNum];

// 邻接表的图结构
typedef struct {
    AdjList adjList; // 邻接表
    int vexnum, arcnum; // 图的顶点数和边数
} ALGraph;

// 队列-广度

// 循环队列算法,辅助完成二叉树层次遍历
#define MaxSize 50   // 定义队列中元素的最大个数
typedef struct {
  int data[MaxSize]; // 存放队列元素
  int front, rear;   // 队头和队尾指针 
} SqQueue;

// 初始化队列(带头结点)
void Queue_Init(SqQueue &Q) {
  Q.rear = Q.front = 0;
}

// 判断队列是否为空
bool Queue_Empty(SqQueue Q) {
  return Q.front == Q.rear;
}

// 入队
bool Queue_En(SqQueue &Q, int e) {
  if ((Q.rear + 1) % MaxSize == Q.front) return false; // 队满则报错
  Q.data[Q.rear] = e;
  Q.rear = (Q.rear + 1) % MaxSize; // 队尾指针加 1 取模
  return true;
}

// 出队
bool Queue_De(SqQueue &Q, int &e) {
  if (Queue_Empty(Q)) return false; // 队空则报错
  e = Q.data[Q.front];
  Q.front = (Q.front + 1) % MaxSize;
  return true;
}

void ALGraph_Create (ALGraph &G) {
    // 对顶点表结点进行初始化
    for (int i = 0; i < MaxVertexNum; i++) {
        G.adjList[i].first = NULL;
    }
    printf("输入顶点 边个数(空格间隔):");
    scanf("%d %d", &G.vexnum, &G.arcnum);
    // 建立顶点表
    for (int i = 0; i < G.vexnum; i++) {
        printf("请输入第%d个顶点的值:", i + 1);
        scanf(" %c", &G.adjList[i].data);
        G.adjList[i].first = NULL;
    }
    // 建立边表
    int vi, vj;
    ArcWeight weight;
    printf("下标为 -1 -1 则退出创建边\n");
    for (int i = 0; i < G.arcnum; i++) {
        // 代表两个顶点 vi 指向 vj 的边,注意vi vj是从0开始的
        printf("请输入要创建边的两个顶点 vi vj ");
        scanf("%d %d", &vi, &vj);
        if (vi == -1 && vj == -1) break;
        printf("请输入边为[%d->%d]的权值 weight = ", vi, vj);
        scanf("%d", &weight);
        ArcNode *arcNode;
        arcNode = (ArcNode *)malloc(sizeof(ArcNode));
        // 通过头插法插入新边,
        arcNode->next = G.adjList[vi].first;
        arcNode->adjvex = vj; // 该边指向的顶点位置
        arcNode->weight = weight;
        G.adjList[vi].first = arcNode;
        // 如果是无向图,则还需要创建相反方向的边
        if (!DIRECTED) {
            ArcNode *arcNode2;
            arcNode2 = (ArcNode *)malloc(sizeof(ArcNode));
            // 相反方向,放入vj里 头插
            arcNode2->next = G.adjList[vj].first;
            arcNode2->adjvex = vi;
            arcNode2->weight = weight;
            G.adjList[vj].first = arcNode2;
        }
    }
}

// 访问标记数组
bool BFSVisited[MaxVertexNum];
// 对图G进行广度优先遍历
// 注意:对邻接表进行广度优先遍历的结果并不唯一
void BFS (ALGraph G, int v) { // 从顶点V出发,广度优先遍历图G
    for (int i = 0; i < G.vexnum; i++)
        BFSVisited[i] = false;
    SqQueue Q;
    Queue_Init(Q); // 初始化辅助队列Q
    Queue_En(Q, v); // 将顶点 v 的下标入队
    // 访问初始顶点 V
    printf("\n对顶点【%d】进行广度优先遍历:", v);
    BFSVisited[v] = true; // 对 v 进行已访问标记
    ArcNode *p;
    while (Queue_Empty(Q) == false) { // 当队列非空时
        Queue_De(Q, v); // 将队头元素出队并送到 v 中
        p = G.adjList[v].first; // 指针 p 指向顶点 v 的边表
        while (p != NULL) {
            // 遍历该顶点的出边表
            if (BFSVisited[p->adjvex] == false) {
                printf("%d、", p->adjvex); // 访问顶点
                BFSVisited[p->adjvex] = true;
                Queue_En(Q, p->adjvex); // 将顶点下标入队
            }
            p = p->next;
        }
    }
}

// 对整个图进行遍历
void BFS_Traverse (ALGraph G) {
    for (int i = 0; i < G.vexnum; i++)
        BFS(G, i);
}

// 访问标记数组
bool DFSVisited[MaxVertexNum];
// 深度优先遍历
// 注意:对邻接表进行深度优先遍历的结果并不唯一
void DFS (ALGraph G, int v) {
    ArcNode *p;
    p = G.adjList[v].first;
    printf("%d、", v);
    DFSVisited[v] = true;
    while (p) {
        int j = p->adjvex;
        if (DFSVisited[j] == false) {
            DFS(G, j);
        }
        p = p->next;
    }
}
// 对整个图进行遍历
void DFS_Traverse (ALGraph G) {
    for (int i = 0; i < G.vexnum; i++) {
        // 从顶点V出发,深度优先遍历图G
        for (int j = 0; j < G.vexnum; j++)
            DFSVisited[j] = false;

        printf("\n对顶点【%d】进行深度优先遍历:", i);
        DFS(G, i);
    }
}

void ALGraph_Show (ALGraph G) {
    for (int i = 0; i < G.vexnum; i++) {
        printf("%c", G.adjList[i].data);
        ArcNode *p = G.adjList[i].first;
        while (p) {
            printf("->%d", p->adjvex);
            p = p->next;
        }
        printf("\n");
    }
}

int main () {
    printf("注意,当前创建图为有向图\n");
    ALGraph G;
    ALGraph_Create(G);
    ALGraph_Show(G);
    BFS_Traverse(G);
    DFS_Traverse(G);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>

#define MaxVertexNum 26
// 是否为有向图
#define DIRECTED true
typedef char VertexType;
typedef int ArcWeight;

// 边表结点
typedef struct ArcNode {
    int adjvex; // 该边指向的顶点下标
    ArcWeight weight; // 权值
    struct ArcNode *next; // 指向下一条边的指针
} ArcNode;

// 顶点表结点
typedef struct VNode{
    VertexType data; // 顶点信息
    ArcNode *first; // 指向该顶点的第一条边的指针
} VNode, AdjList[MaxVertexNum];

// 邻接表的图结构
typedef struct {
    AdjList adjList; // 邻接表
    int vexnum, arcnum; // 图的顶点数和边数
} ALGraph;

// 队列-广度

// 循环队列算法,辅助完成二叉树层次遍历
#define MaxSize 50   // 定义队列中元素的最大个数
typedef struct {
  int data[MaxSize]; // 存放队列元素
  int front, rear;   // 队头和队尾指针 
} SqQueue;

// 初始化队列(带头结点)
void Queue_Init(SqQueue &Q) {
  Q.rear = Q.front = 0;
}

// 判断队列是否为空
bool Queue_Empty(SqQueue Q) {
  return Q.front == Q.rear;
}

// 入队
bool Queue_En(SqQueue &Q, int e) {
  if ((Q.rear + 1) % MaxSize == Q.front) return false; // 队满则报错
  Q.data[Q.rear] = e;
  Q.rear = (Q.rear + 1) % MaxSize; // 队尾指针加 1 取模
  return true;
}

// 出队
bool Queue_De(SqQueue &Q, int &e) {
  if (Queue_Empty(Q)) return false; // 队空则报错
  e = Q.data[Q.front];
  Q.front = (Q.front + 1) % MaxSize;
  return true;
}

void ALGraph_Create (ALGraph &G) {
    // 对顶点表结点进行初始化
    for (int i = 0; i < MaxVertexNum; i++) {
        G.adjList[i].first = NULL;
    }
    printf("输入顶点 边个数(空格间隔):");
    scanf("%d %d", &G.vexnum, &G.arcnum);
    // 建立顶点表
    for (int i = 0; i < G.vexnum; i++) {
        printf("请输入第%d个顶点的值:", i + 1);
        scanf(" %c", &G.adjList[i].data);
        G.adjList[i].first = NULL;
    }
    // 建立边表
    int vi, vj;
    ArcWeight weight;
    printf("下标为 -1 -1 则退出创建边\n");
    for (int i = 0; i < G.arcnum; i++) {
        // 代表两个顶点 vi 指向 vj 的边,注意vi vj是从0开始的
        printf("请输入要创建边的两个顶点 vi vj ");
        scanf("%d %d", &vi, &vj);
        if (vi == -1 && vj == -1) break;
        printf("请输入边为[%d->%d]的权值 weight = ", vi, vj);
        scanf("%d", &weight);
        ArcNode *arcNode;
        arcNode = (ArcNode *)malloc(sizeof(ArcNode));
        // 通过头插法插入新边,
        arcNode->next = G.adjList[vi].first;
        arcNode->adjvex = vj; // 该边指向的顶点位置
        arcNode->weight = weight;
        G.adjList[vi].first = arcNode;
        // 如果是无向图,则还需要创建相反方向的边
        if (!DIRECTED) {
            ArcNode *arcNode2;
            arcNode2 = (ArcNode *)malloc(sizeof(ArcNode));
            // 相反方向,放入vj里 头插
            arcNode2->next = G.adjList[vj].first;
            arcNode2->adjvex = vi;
            arcNode2->weight = weight;
            G.adjList[vj].first = arcNode2;
        }
    }
}

// 访问标记数组
bool BFSVisited[MaxVertexNum];
// 对图G进行广度优先遍历
// 注意:对邻接表进行广度优先遍历的结果并不唯一
void BFS (ALGraph G, int v) { // 从顶点V出发,广度优先遍历图G
    for (int i = 0; i < G.vexnum; i++)
        BFSVisited[i] = false;
    SqQueue Q;
    Queue_Init(Q); // 初始化辅助队列Q
    Queue_En(Q, v); // 将顶点 v 的下标入队
    // 访问初始顶点 V
    printf("\n对顶点【%d】进行广度优先遍历:", v);
    BFSVisited[v] = true; // 对 v 进行已访问标记
    ArcNode *p;
    while (Queue_Empty(Q) == false) { // 当队列非空时
        Queue_De(Q, v); // 将队头元素出队并送到 v 中
        p = G.adjList[v].first; // 指针 p 指向顶点 v 的边表
        while (p != NULL) {
            // 遍历该顶点的出边表
            if (BFSVisited[p->adjvex] == false) {
                printf("%d、", p->adjvex); // 访问顶点
                BFSVisited[p->adjvex] = true;
                Queue_En(Q, p->adjvex); // 将顶点下标入队
            }
            p = p->next;
        }
    }
}

// 对整个图进行遍历
void BFS_Traverse (ALGraph G) {
    for (int i = 0; i < G.vexnum; i++)
        BFS(G, i);
}

// 访问标记数组
bool DFSVisited[MaxVertexNum];
// 深度优先遍历
// 注意:对邻接表进行深度优先遍历的结果并不唯一
void DFS (ALGraph G, int v) {
    ArcNode *p;
    p = G.adjList[v].first;
    printf("%d、", v);
    DFSVisited[v] = true;
    while (p) {
        int j = p->adjvex;
        if (DFSVisited[j] == false) {
            DFS(G, j);
        }
        p = p->next;
    }
}
// 对整个图进行遍历
void DFS_Traverse (ALGraph G) {
    for (int i = 0; i < G.vexnum; i++) {
        // 从顶点V出发,深度优先遍历图G
        for (int j = 0; j < G.vexnum; j++)
            DFSVisited[j] = false;

        printf("\n对顶点【%d】进行深度优先遍历:", i);
        DFS(G, i);
    }
}

void ALGraph_Show (ALGraph G) {
    for (int i = 0; i < G.vexnum; i++) {
        printf("%c", G.adjList[i].data);
        ArcNode *p = G.adjList[i].first;
        while (p) {
            printf("->%d", p->adjvex);
            p = p->next;
        }
        printf("\n");
    }
}

int main () {
    printf("注意,当前创建图为有向图\n");
    ALGraph G;
    ALGraph_Create(G);
    ALGraph_Show(G);
    BFS_Traverse(G);
    DFS_Traverse(G);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>

#define MaxVertexNum 26
// 是否为有向图
#define DIRECTED true
typedef char VertexType;
typedef int ArcWeight;

// 边表结点
typedef struct ArcNode {
    int adjvex; // 该边指向的顶点下标
    ArcWeight weight; // 权值
    struct ArcNode *next; // 指向下一条边的指针
} ArcNode;

// 顶点表结点
typedef struct VNode{
    VertexType data; // 顶点信息
    ArcNode *first; // 指向该顶点的第一条边的指针
} VNode, AdjList[MaxVertexNum];

// 邻接表的图结构
typedef struct {
    AdjList adjList; // 邻接表
    int vexnum, arcnum; // 图的顶点数和边数
} ALGraph;

// 队列-广度

// 循环队列算法,辅助完成二叉树层次遍历
#define MaxSize 50   // 定义队列中元素的最大个数
typedef struct {
  int data[MaxSize]; // 存放队列元素
  int front, rear;   // 队头和队尾指针 
} SqQueue;

// 初始化队列(带头结点)
void Queue_Init(SqQueue &Q) {
  Q.rear = Q.front = 0;
}

// 判断队列是否为空
bool Queue_Empty(SqQueue Q) {
  return Q.front == Q.rear;
}

// 入队
bool Queue_En(SqQueue &Q, int e) {
  if ((Q.rear + 1) % MaxSize == Q.front) return false; // 队满则报错
  Q.data[Q.rear] = e;
  Q.rear = (Q.rear + 1) % MaxSize; // 队尾指针加 1 取模
  return true;
}

// 出队
bool Queue_De(SqQueue &Q, int &e) {
  if (Queue_Empty(Q)) return false; // 队空则报错
  e = Q.data[Q.front];
  Q.front = (Q.front + 1) % MaxSize;
  return true;
}

void ALGraph_Create (ALGraph &G) {
    // 对顶点表结点进行初始化
    for (int i = 0; i < MaxVertexNum; i++) {
        G.adjList[i].first = NULL;
    }
    printf("输入顶点 边个数(空格间隔):");
    scanf("%d %d", &G.vexnum, &G.arcnum);
    // 建立顶点表
    for (int i = 0; i < G.vexnum; i++) {
        printf("请输入第%d个顶点的值:", i + 1);
        scanf(" %c", &G.adjList[i].data);
        G.adjList[i].first = NULL;
    }
    // 建立边表
    int vi, vj;
    ArcWeight weight;
    printf("下标为 -1 -1 则退出创建边\n");
    for (int i = 0; i < G.arcnum; i++) {
        // 代表两个顶点 vi 指向 vj 的边,注意vi vj是从0开始的
        printf("请输入要创建边的两个顶点 vi vj ");
        scanf("%d %d", &vi, &vj);
        if (vi == -1 && vj == -1) break;
        printf("请输入边为[%d->%d]的权值 weight = ", vi, vj);
        scanf("%d", &weight);
        ArcNode *arcNode;
        arcNode = (ArcNode *)malloc(sizeof(ArcNode));
        // 通过头插法插入新边,
        arcNode->next = G.adjList[vi].first;
        arcNode->adjvex = vj; // 该边指向的顶点位置
        arcNode->weight = weight;
        G.adjList[vi].first = arcNode;
        // 如果是无向图,则还需要创建相反方向的边
        if (!DIRECTED) {
            ArcNode *arcNode2;
            arcNode2 = (ArcNode *)malloc(sizeof(ArcNode));
            // 相反方向,放入vj里 头插
            arcNode2->next = G.adjList[vj].first;
            arcNode2->adjvex = vi;
            arcNode2->weight = weight;
            G.adjList[vj].first = arcNode2;
        }
    }
}

// 访问标记数组
bool BFSVisited[MaxVertexNum];
// 对图G进行广度优先遍历
// 注意:对邻接表进行广度优先遍历的结果并不唯一
void BFS (ALGraph G, int v) { // 从顶点V出发,广度优先遍历图G
    for (int i = 0; i < G.vexnum; i++)
        BFSVisited[i] = false;
    SqQueue Q;
    Queue_Init(Q); // 初始化辅助队列Q
    Queue_En(Q, v); // 将顶点 v 的下标入队
    // 访问初始顶点 V
    printf("\n对顶点【%d】进行广度优先遍历:", v);
    BFSVisited[v] = true; // 对 v 进行已访问标记
    ArcNode *p;
    while (Queue_Empty(Q) == false) { // 当队列非空时
        Queue_De(Q, v); // 将队头元素出队并送到 v 中
        p = G.adjList[v].first; // 指针 p 指向顶点 v 的边表
        while (p != NULL) {
            // 遍历该顶点的出边表
            if (BFSVisited[p->adjvex] == false) {
                printf("%d、", p->adjvex); // 访问顶点
                BFSVisited[p->adjvex] = true;
                Queue_En(Q, p->adjvex); // 将顶点下标入队
            }
            p = p->next;
        }
    }
}

// 对整个图进行遍历
void BFS_Traverse (ALGraph G) {
    for (int i = 0; i < G.vexnum; i++)
        BFS(G, i);
}

// 访问标记数组
bool DFSVisited[MaxVertexNum];
// 深度优先遍历
// 注意:对邻接表进行深度优先遍历的结果并不唯一
void DFS (ALGraph G, int v) {
    ArcNode *p;
    p = G.adjList[v].first;
    printf("%d、", v);
    DFSVisited[v] = true;
    while (p) {
        int j = p->adjvex;
        if (DFSVisited[j] == false) {
            DFS(G, j);
        }
        p = p->next;
    }
}
// 对整个图进行遍历
void DFS_Traverse (ALGraph G) {
    for (int i = 0; i < G.vexnum; i++) {
        // 从顶点V出发,深度优先遍历图G
        for (int j = 0; j < G.vexnum; j++)
            DFSVisited[j] = false;

        printf("\n对顶点【%d】进行深度优先遍历:", i);
        DFS(G, i);
    }
}

void ALGraph_Show (ALGraph G) {
    for (int i = 0; i < G.vexnum; i++) {
        printf("%c", G.adjList[i].data);
        ArcNode *p = G.adjList[i].first;
        while (p) {
            printf("->%d", p->adjvex);
            p = p->next;
        }
        printf("\n");
    }
}

int main () {
    printf("注意,当前创建图为有向图\n");
    ALGraph G;
    ALGraph_Create(G);
    ALGraph_Show(G);
    BFS_Traverse(G);
    DFS_Traverse(G);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>

typedef char VertexType; // 顶点类型
typedef int EdgeType; // 边上的权值
#define MAXVEX 100 // 最大顶点数
#define INF 65535 // 如果两个顶点之间不可达,用无穷表示距离
#define DIRECTED true // 是否为有向图

typedef struct {
    VertexType vexs[MAXVEX]; // 顶点表
    EdgeType arc[MAXVEX][MAXVEX]; // 邻接矩阵,可看做边表
    int vexNum, edgeNum; // 图中当前的顶点数和边数
} MGraph;

// 创建邻接矩阵
int Graph_Create (MGraph &G) {
    int vi, vj, weight;
    // 输入顶点数和边数
    printf("请输入顶点数:");
    scanf("%d", &G.vexNum);
    printf("请输入边数:");
    scanf("%d", &G.edgeNum);

    for (int i = 0; i < G.vexNum; i++) { // 为每个顶点初始化信息
        printf("请输入第 %d 个的顶点名称: ", i + 1);
        scanf(" %c", &G.vexs[i]);
    }
    for (int i = 0; i < G.vexNum; i++) { // 初始化顶点之间的权值 默认为无穷
        for (int j = 0; j < G.vexNum; j++) {
            G.arc[i][j] = INF;
        }
    }

    printf("下标为 -1 -1 则退出创建边\n");
    for(int i = 0; i < G.edgeNum; i++){ // 根据边的条数,为每一条边赋值
        printf("请输入要创建边的下标 v1 v2 ");
        scanf("%d %d", &vi, &vj);
        if (vi == -1 && vj == -1) break;
        printf("请输入边为[%d][%d]的权值 weight = ", vi, vj);
        scanf("%d", &weight);
        G.arc[vi][vj] = weight;
        // 在无向网中满足图对称性,即Vi-Vj 和Vj-Vi的距离相等,实际就是一条路径
        if (!DIRECTED) {
            G.arc[vj][vi] = weight;
        }
    }
}

// 找到未在最小生成树中且边权值最小的顶点
int Find_Min_V(MGraph G, int cost[], bool visited[]) {
    int minCost = INF; // 最小边权值初始设为无穷大
    int minVertex = -1; // 初始化最小边权值对应的顶点索引

    for (int v = 0; v < G.vexNum; v++) {
        if ((visited[v] == false) && cost[v] < minCost) {
            minCost = cost[v]; // 更新最小边权值
            minVertex = v; // 记录对应顶点索引
        }
    }
    return minVertex; // 返回最小边权值对应的顶点索引
}

// v 为开始顶点
void Prim (MGraph G, int v) {
    int parent[MAXVEX]; // 记录每个顶点在最小生成树中的父节点
    int cost[MAXVEX]; // 记录每个顶点与当前最小生成树的最小边权值
    bool visited[MAXVEX]; // 记录顶点是否已经在最小生成树中

    // 初始化权值
    for (int i = 0; i < G.vexNum; i++) {
        parent[i] = -1;
        cost[i] = INF;
        visited[i] = false;
    }

    cost[v] = 0; // 指定的开始顶点作为初始顶点
    parent[v] = -1; // 初始顶点没有父结点

    // 主循环,构建最小生成树
    // 最小生成树有 vexNum - 1 条边,当 i 达到 vexNum - 1 时,算法就已经完成了构建最小生成树的过程
    for (int i = 0; i < G.vexNum - 1; i++) {
        // 找到最小边权值的顶点,第一次循环找到的是开始顶点
        int minV = Find_Min_V(G, cost, visited);
        // 非联通的
        if (minV == -1) continue;
        visited[minV] = true;
        // 更新其他顶点到最小生成树的边权值和父结点
        for (int j = 0; j < G.vexNum; j++) {
            if (
                G.arc[minV][j]
                && (visited[j] == false)
                && G.arc[minV][j] < cost[j]
            ) {
                parent[j] = minV; // 顶点 j 的父节点是顶点 u
                cost[j] = G.arc[minV][j]; // 更新顶点 j 到最小生成树的边权值
            }
        }
    }
    // 输出构建的最小生成树的顶点
    printf("Vertices in the MST:\n");
    for (int i = 0; i < G.vexNum; i++)
    {
        printf("v=%d p=%d c=%d\n", i, parent[i], cost[i]);
    }
}

// 打印图
void Graph_Show (MGraph G) {
    // 打印顶点
    for (int i = 0; i < G.vexNum; i++)
        printf("%c", G.vexs[i]);
    printf("\n");
    // 打印邻接矩阵
    for(int i = 0; i < G.vexNum; i++){
        for(int j = 0; j < G.vexNum; j++){
            if(G.arc[i][j] == INF) printf("%6s", "∞");
            else printf("%6d", G.arc[i][j]);
        }
        printf("\n");
    }
}

int main () {
    MGraph G;
    // Graph_Create(G);
    G.vexNum = 6;
    G.edgeNum = 10;
    G.vexs[0] = 'a';
    G.vexs[1] = 'b';
    G.vexs[2] = 'c';
    G.vexs[3] = 'd';
    G.vexs[4] = 'e';
    G.vexs[5] = 'f';
    for (int i = 0; i < G.vexNum; i++) { // 初始化顶点之间的权值 默认为无穷
        for (int j = 0; j < G.vexNum; j++) {
            G.arc[i][j] = INF;
        }
    }
    // 设置边
    G.arc[0][1] = G.arc[1][0] = 6;
    G.arc[0][3] = G.arc[3][0] = 5;
    G.arc[0][2] = G.arc[2][0] = 1;
    G.arc[1][2] = G.arc[2][1] = 5;
    G.arc[2][3] = G.arc[3][2] = 5;
    G.arc[1][4] = G.arc[4][1] = 3;
    G.arc[2][4] = G.arc[4][2] = 6;
    G.arc[2][5] = G.arc[5][2] = 4;
    G.arc[3][5] = G.arc[5][3] = 2;
    G.arc[4][5] = G.arc[5][4] = 6;
    Graph_Show(G);
    Prim(G, 0);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>

typedef char VertexType; // 顶点类型
typedef int EdgeType; // 边上的权值
#define MAXVEX 100 // 最大顶点数
#define INF 65535 // 如果两个顶点之间不可达,用无穷表示距离
#define DIRECTED true // 是否为有向图

// Kruskal 辅助边
typedef struct {
    int source;
    int target;
    int weight;
} Edge;

typedef struct {
    VertexType vexs[MAXVEX]; // 顶点表
    EdgeType arc[MAXVEX][MAXVEX]; // 邻接矩阵,可看做边表
    int vexNum, edgeNum; // 图中当前的顶点数和边数
} MGraph;

// 创建邻接矩阵
int Graph_Create (MGraph &G) {
    int vi, vj, weight;
    // 输入顶点数和边数
    printf("请输入顶点数:");
    scanf("%d", &G.vexNum);
    printf("请输入边数:");
    scanf("%d", &G.edgeNum);

    for (int i = 0; i < G.vexNum; i++) { // 为每个顶点初始化信息
        printf("请输入第 %d 个的顶点名称: ", i + 1);
        scanf(" %c", &G.vexs[i]);
    }
    for (int i = 0; i < G.vexNum; i++) { // 初始化顶点之间的权值 默认为无穷
        for (int j = 0; j < G.vexNum; j++) {
            G.arc[i][j] = INF;
        }
    }

    printf("下标为 -1 -1 则退出创建边\n");
    for(int i = 0; i < G.edgeNum; i++){ // 根据边的条数,为每一条边赋值
        printf("请输入要创建边的下标 v1 v2 ");
        scanf("%d %d", &vi, &vj);
        if (vi == -1 && vj == -1) break;
        printf("请输入边为[%d][%d]的权值 weight = ", vi, vj);
        scanf("%d", &weight);
        G.arc[vi][vj] = weight;
        // 在无向网中满足图对称性,即Vi-Vj 和Vj-Vi的距离相等,实际就是一条路径
        if (!DIRECTED) {
            G.arc[vj][vi] = weight;
        }
    }
}

// 比较函数,用于排序边
int compareEdges (const void *a, const void *b) {
    return ((Edge *)a)->weight - ((Edge *)b)->weight;
}

// Kruskal 克鲁斯卡尔算法
void Kruskal (MGraph G, Edge edges[]) {
    // 每个顶点配置一个标记值(并查集思想)
    int *sets = (int *)malloc(G.vexNum * sizeof(int));
    // 初始状态下,每个顶点的标记都不相同
    for (int i = 0; i < G.vexNum; i++) {
        sets[i] = i;
    }
    // 根据权值,对所有边进行升序排序
    qsort(edges, G.edgeNum, sizeof(edges[0]), compareEdges);

    // 遍历所有边
    int num = 0; // 记录加入的边数
    // 由于已经按升序进行排序,只需对边进行遍历每个都是最小权值边
    for (int i = 0; i < G.edgeNum; i++) {
        // 找到当前边的两个顶点在 sets 数组中的位置下标
        int source = edges[i].source;
        int target = edges[i].target;
        int weight = edges[i].weight;
        // 如果顶点位置存在且顶点的标记不同,说明不在一个集合中,不会产生回路
        if (sets[source] != sets[target]) {
            printf("s=%d, t=%d, w=%d\n", source, target, weight);
            num++;
            // 将新加入的生成树的顶点标记全改为一样的
            for (int j = 0; j < G.vexNum; j++) {
                // 找到集合的 target 标记
                if (sets[j] == sets[target]) {
                    // 使 targe 标记 = source 的标记(相反也行)
                    sets[j] = sets[source];
                }
            }
            // 如果选中的边数量=顶点数-1,证明最小生成树已形成,退出循环
            if (num == G.vexNum - 1) {
                break;
            }
        }
    }
}

// 打印图
void Graph_Show (MGraph G) {
    // 打印顶点
    for (int i = 0; i < G.vexNum; i++)
        printf("%c", G.vexs[i]);
    printf("\n");
    // 打印邻接矩阵
    for(int i = 0; i < G.vexNum; i++){
        for(int j = 0; j < G.vexNum; j++){
            if(G.arc[i][j] == INF) printf("%6s", "∞");
            else printf("%6d", G.arc[i][j]);
        }
        printf("\n");
    }
}

int main () {
    MGraph G;
    // Graph_Create(G);
    G.vexNum = 6;
    G.vexs[0] = 'a';
    G.vexs[1] = 'b';
    G.vexs[2] = 'c';
    G.vexs[3] = 'd';
    G.vexs[4] = 'e';
    G.vexs[5] = 'f';
    for (int i = 0; i < G.vexNum; i++) { // 初始化顶点之间的权值 默认为无穷
        for (int j = 0; j < G.vexNum; j++) {
            G.arc[i][j] = INF;
        }
    }
    G.edgeNum = 10;
    // 设置边
    G.arc[0][1] = G.arc[1][0] = 6;
    G.arc[0][3] = G.arc[3][0] = 5;
    G.arc[0][2] = G.arc[2][0] = 1;
    G.arc[1][2] = G.arc[2][1] = 5;
    G.arc[2][3] = G.arc[3][2] = 5;
    G.arc[1][4] = G.arc[4][1] = 3;
    G.arc[2][4] = G.arc[4][2] = 6;
    G.arc[2][5] = G.arc[5][2] = 4;
    G.arc[3][5] = G.arc[5][3] = 2;
    G.arc[4][5] = G.arc[5][4] = 6;
    Edge *edges = (Edge *)malloc(G.edgeNum * sizeof(Edge));
    int edgeIndex = 0;
    // 构建边数组,只使用矩阵的上三角
    for (int i = 0; i < G.vexNum; i++) {
        for (int j = i + 1; j < G.vexNum; j++) {
            if (G.arc[i][j] != INF) {
                edges[edgeIndex].source = i;
                edges[edgeIndex].target = j;
                edges[edgeIndex].weight = G.arc[i][j];
                edgeIndex++;
            }
        }
    }
    Graph_Show(G);
    Kruskal(G, edges);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>

typedef char VertexType; // 顶点类型
typedef int EdgeType; // 边上的权值
#define MAXVEX 100 // 最大顶点数
#define INF 65535 // 如果两个顶点之间不可达,用无穷表示距离
#define DIRECTED true // 是否为有向图

typedef struct {
    VertexType vexs[MAXVEX]; // 顶点表
    EdgeType arc[MAXVEX][MAXVEX]; // 邻接矩阵,可看做边表
    int vexNum, edgeNum; // 图中当前的顶点数和边数
} MGraph;

// 创建邻接矩阵
int Graph_Create (MGraph &G) {
    int vi, vj, weight;
    // 输入顶点数和边数
    printf("请输入顶点数:");
    scanf("%d", &G.vexNum);
    printf("请输入边数:");
    scanf("%d", &G.edgeNum);

    for (int i = 0; i < G.vexNum; i++) { // 为每个顶点初始化信息
        printf("请输入第 %d 个的顶点名称: ", i + 1);
        scanf(" %c", &G.vexs[i]);
    }
    for (int i = 0; i < G.vexNum; i++) { // 初始化顶点之间的权值 默认为无穷
        for (int j = 0; j < G.vexNum; j++) {
            G.arc[i][j] = INF;
        }
    }

    printf("下标为 -1 -1 则退出创建边\n");
    for(int i = 0; i < G.edgeNum; i++){ // 根据边的条数,为每一条边赋值
        printf("请输入要创建边的下标 v1 v2 ");
        scanf("%d %d", &vi, &vj);
        if (vi == -1 && vj == -1) break;
        printf("请输入边为[%d][%d]的权值 weight = ", vi, vj);
        scanf("%d", &weight);
        G.arc[vi][vj] = weight;
        // 在无向网中满足图对称性,即Vi-Vj 和Vj-Vi的距离相等,实际就是一条路径
        if (!DIRECTED) {
            G.arc[vj][vi] = weight;
        }
    }
}

// 找到距离值最小的顶点,从尚未包括在最短路径树中的顶点集合中选取
int minDistance (MGraph G, int dist[], bool visited[]) {
    int min = INF, minIndex;
    // 遍历所有顶点,找到距离最小的顶点
    for (int v = 0; v < G.vexNum; v++)
        if (visited[v] == false && dist[v] <= min)
            min = dist[v], minIndex = v;

    return minIndex;
}

// 打印构造的距离数组
void printPath (int parent[], int i) {
    // 递归打印路径
    if (parent[i] == -1)
        return;
    printPath(parent, parent[i]);
    printf(" -> %d", i);
}

// 实现Dijkstra算法的函数
// 计算从源顶点到其他顶点的最短路径并输出
void Dijkstra (MGraph G, int src) {
    // 保存从源到每个顶点的最短路径
    int dist[G.vexNum];
    // 标记顶点是否在最短路径树中
    bool visited[G.vexNum];
    // 存储每个顶点在最短路径中的前一个顶点
    int parent[G.vexNum];
    // 初始化距离、最短路径树集合和前驱顶点
    for (int i = 0; i < G.vexNum; i++) {
        dist[i] = INF; // 初始化距离为无限大
        visited[i] = false; // 尚未包括在最短路径树中
        parent[i] = -1; // 初始前驱为 -1
    }

    dist[src] = 0; // 源顶点到自身的距离为0

    // 查找原顶点到其他顶点的最短路径
    for (int i = 0; i < G.vexNum - 1; i++) {
        // 找到距离最小的顶点,第一次循环找到的是开始顶点
        int u = minDistance(G, dist, visited);
        visited[u] = true;
        // 其他没更新到的顶点 dist 任然为 INF
        // 所以在 i 的下次循环中 找到的顶点是相邻顶点
        // 更新从找到的最小顶点到其相邻顶点的距离和前驱顶点
        for (int v = 0; v < G.vexNum; v++) {
            if (
                !visited[v]
                && G.arc[u][v]
                && dist[u] != INF
                // 判断是否找到了一条比当前路径更短的路径
                && dist[u] + G.arc[u][v] < dist[v]
            ) {
                dist[v] = dist[u] + G.arc[u][v];
                parent[v] = u; // 更新前驱结点
            }
        }
    }
    // 输出每个顶点的最短路径及路径本身
    printf("Vertex   Distance    Path
");
    for (int i = 0; i < G.vexNum; i++) {
        printf("%d   %d          %d", i, dist[i], src);
        printPath(parent, i);  // 打印路径
        printf("
");
    }
}

// 打印图
void Graph_Show (MGraph G) {
    // 打印顶点
    for (int i = 0; i < G.vexNum; i++)
        printf("%c", G.vexs[i]);
    printf("\n");
    // 打印邻接矩阵
    for(int i = 0; i < G.vexNum; i++){
        for(int j = 0; j < G.vexNum; j++){
            if(G.arc[i][j] == INF) printf("%6s", "∞");
            else printf("%6d", G.arc[i][j]);
        }
        printf("\n");
    }
}

int main () {
    MGraph G;
    // Graph_Create(G);
    G.vexNum = 6;
    G.edgeNum = 10;
    G.vexs[0] = 'a';
    G.vexs[1] = 'b';
    G.vexs[2] = 'c';
    G.vexs[3] = 'd';
    G.vexs[4] = 'e';
    G.vexs[5] = 'f';
    for (int i = 0; i < G.vexNum; i++) { // 初始化顶点之间的权值 默认为无穷
        for (int j = 0; j < G.vexNum; j++) {
            G.arc[i][j] = INF;
        }
    }
    // 设置边
    G.arc[0][1] = G.arc[1][0] = 6;
    G.arc[0][3] = G.arc[3][0] = 5;
    G.arc[0][2] = G.arc[2][0] = 1;
    G.arc[1][2] = G.arc[2][1] = 5;
    G.arc[2][3] = G.arc[3][2] = 5;
    G.arc[1][4] = G.arc[4][1] = 3;
    G.arc[2][4] = G.arc[4][2] = 6;
    G.arc[2][5] = G.arc[5][2] = 4;
    G.arc[3][5] = G.arc[5][3] = 2;
    G.arc[4][5] = G.arc[5][4] = 6;
    Graph_Show(G);
    Dijkstra(G, 0);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>

typedef char VertexType; // 顶点类型
typedef int EdgeType; // 边上的权值
#define MAXVEX 100 // 最大顶点数
#define INF 65535 // 如果两个顶点之间不可达,用无穷表示距离
#define DIRECTED true // 是否为有向图

#define V 3 // 定义图中结点的个数

typedef struct {
    VertexType vexs[MAXVEX]; // 顶点表
    EdgeType arc[MAXVEX][MAXVEX]; // 邻接矩阵,可看做边表
    int vexNum, edgeNum; // 图中当前的顶点数和边数
} MGraph;

// 创建邻接矩阵
int Graph_Create (MGraph &G) {
    int vi, vj, weight;
    // 输入顶点数和边数
    printf("请输入顶点数:");
    scanf("%d", &G.vexNum);
    printf("请输入边数:");
    scanf("%d", &G.edgeNum);

    for (int i = 0; i < G.vexNum; i++) { // 为每个顶点初始化信息
        printf("请输入第 %d 个的顶点名称: ", i + 1);
        scanf(" %c", &G.vexs[i]);
    }
    for (int i = 0; i < G.vexNum; i++) { // 初始化顶点之间的权值 默认为无穷
        for (int j = 0; j < G.vexNum; j++) {
            G.arc[i][j] = INF;
        }
    }

    printf("下标为 -1 -1 则退出创建边\n");
    for(int i = 0; i < G.edgeNum; i++){ // 根据边的条数,为每一条边赋值
        printf("请输入要创建边的下标 v1 v2 ");
        scanf("%d %d", &vi, &vj);
        if (vi == -1 && vj == -1) break;
        printf("请输入边为[%d][%d]的权值 weight = ", vi, vj);
        scanf("%d", &weight);
        G.arc[vi][vj] = weight;
        // 在无向网中满足图对称性,即Vi-Vj 和Vj-Vi的距离相等,实际就是一条路径
        if (!DIRECTED) {
            G.arc[vj][vi] = weight;
        }
    }
}

// 输出最短路径的函数
void printPath (int path[V][V], int start, int end) {
    // 如果路径前驱为-1,表示没有路径
    if (path[start][end] == -1) {
        printf("%d", start); // 直接输出起始结点
        return;
    }
    printPath(path, start, path[start][end]); // 递归输出路径
    printf(" -> %d", end); // 输出当前路径
}

// Flyod-Warshall 算法函数
void Floyd (MGraph G) {
    int dist[V][V]; // 最短路径的距离矩阵
    int path[V][V]; // 最短路径的前驱结点

    // 初始化 dist 和 path 矩阵
    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++) {
            dist[i][j] = G.arc[i][j];
            if (i != j && G.arc[i][j] != INF) {
                path[i][j] = i; // 初始化路径前驱结点
            } else {
                path[i][j] = -1; // 无路径时设置为 -1
            }
        }
    }

    // 逐个结点尝试作为中间节点,更新最短路径
    for (int k = 0; k <  V; k++) {
        for (int i = 0; i < V; i++) {
            for (int j = 0; j < V; j++) {
                // dist[i][k] + dist[k][j] 表示通过中间节点 k 从节点 i 到节点 j 的路径长度,即通过节点 k 的路径长度。
                // dist[i][j] 是节点 i 到节点 j 的当前已知的最短路径长度。
                // i != j 自己到自己的路径为无穷(或0)所以不需要更新
                // 如果通过中间节点 k 的路径更短,则更新最短路径
                if (i != j && dist[i][k] + dist[k][j] < dist[i][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                    path[i][j] = path[k][j]; // 更新路径前驱信息
                }
            }
        }
    }

    // 输出最终的最短路径矩阵
    printf("最短路径矩阵:\n");
    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++) {
            if (dist[i][j] == INF) {
                printf("INF ");
            } else {
                printf("%d  ", dist[i][j]);
            }
        }
        printf("\n");
    }

    // 输出没对节点之前的最短路径信息
    printf("\n最短路径信息:\n");
    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++) {
            if (path[i][j] == -1) {
                printf("No Path from %d to %d", i, j); // 没有路径时的提示
            } else {
                printf("Path from %d to %d: ", i, j);
                printPath(path, i, j); // 调用输出路径的函数
            }
            printf("\n");
        }
    }
}

// 打印图
void Graph_Show (MGraph G) {
    // 打印顶点
    for (int i = 0; i < G.vexNum; i++)
        printf("%c", G.vexs[i]);
    printf("\n");
    // 打印邻接矩阵
    for(int i = 0; i < G.vexNum; i++){
        for(int j = 0; j < G.vexNum; j++){
            if(G.arc[i][j] == INF) printf("%6s", "∞");
            else printf("%6d", G.arc[i][j]);
        }
        printf("\n");
    }
}

int main () {
    // 注意 为了方便申请数组内存,在全局定义了顶点数常量
    MGraph G;
    // Graph_Create(G);
    G.vexNum = V;
    G.vexs[0] = '0';
    G.vexs[1] = '1';
    G.vexs[2] = '2';
    for (int i = 0; i < G.vexNum; i++) { // 初始化顶点之间的权值 默认为无穷
        for (int j = 0; j < G.vexNum; j++) {
            G.arc[i][j] = INF;
        }
    }
    G.edgeNum = 5;
    // 设置边
    G.arc[0][1] = 6;
    G.arc[0][2] = 13;
    G.arc[1][0] = 10;
    G.arc[1][2] = 4;
    G.arc[2][0] = 5;
    Graph_Show(G);
    Floyd(G);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>

#define MaxVertexNum 26
// 是否为有向图
#define DIRECTED true
typedef char VertexType;
typedef int ArcWeight;

// 边表结点
typedef struct ArcNode {
    int adjvex; // 该边指向的顶点下标
    ArcWeight weight; // 权值
    struct ArcNode *next; // 指向下一条边的指针
} ArcNode;

// 顶点表结点
typedef struct VNode{
    VertexType data; // 顶点信息
    ArcNode *first; // 指向该顶点的第一条边的指针
} VNode, AdjList[MaxVertexNum];

// 邻接表的图结构
typedef struct {
    AdjList adjList; // 邻接表
    int vexnum, arcnum; // 图的顶点数和边数
} ALGraph;

// =========拓扑排序辅助栈
typedef struct {
    int data[MaxVertexNum];
    int top;
} Stack;

// 初始化栈
void Stack_Init(Stack &stack) {
    stack.top = -1;
}

// 栈是否空
int Stack_IsEmpty(Stack stack) {
    return stack.top == -1;
}

// 是否满栈
int Stack_IsFull(Stack stack) {
    return stack.top == MaxVertexNum - 1;
}

// 入栈
void Stack_Push(Stack &stack, int value) {
    if (!Stack_IsFull(stack)) {
        stack.top++;
        stack.data[stack.top] = value;
    } else {
        printf("栈满,不能Push操作\n");
    }
}

// 出栈
int Stack_Pop(Stack &stack) {
    if (!Stack_IsEmpty(stack)) {
        int value = stack.data[stack.top];
        stack.top--;
        return value;
    } else {
        printf("栈为空,不能Pop操作\n");
        return -1; // Indicating an error value
    }
}

// 添加边到图
void ALGraph_AddEdge(ALGraph &graph, int source, int target, ArcWeight weight) {
    ArcNode* newNode = (ArcNode*)malloc(sizeof(ArcNode));
    // 通过头插法插入新边
    newNode->adjvex = target; // 该边指向的顶点位置
    newNode->weight = weight;
    newNode->next = graph.adjList[source].first;
    graph.adjList[source].first = newNode;

    // 如果是无向图,则还需要创建相反方向的边
    if (!DIRECTED) {
        ArcNode* reverseNode = (ArcNode*)malloc(sizeof(ArcNode));
        reverseNode->adjvex = source;
        reverseNode->weight = weight;
        // 相反方向,放入vj里 头插
        reverseNode->next = graph.adjList[target].first;
        graph.adjList[target].first = reverseNode;
    }
}

void ALGraph_Create (ALGraph &G) {
    // 对顶点表结点进行初始化
    for (int i = 0; i < MaxVertexNum; i++) {
        G.adjList[i].first = NULL;
    }
    printf("输入顶点 边个数(空格间隔):");
    scanf("%d %d", &G.vexnum, &G.arcnum);
    // 建立顶点表
    for (int i = 0; i < G.vexnum; i++) {
        printf("请输入第%d个顶点的值:", i + 1);
        scanf(" %c", &G.adjList[i].data);
        G.adjList[i].first = NULL;
    }
    // 建立边表
    int vi, vj;
    ArcWeight weight;
    printf("下标为 -1 -1 则退出创建边\n");
    for (int i = 0; i < G.arcnum; i++) {
        // 代表两个顶点 vi 指向 vj 的边,注意vi vj是从0开始的
        printf("请输入要创建边的两个顶点 vi vj ");
        scanf("%d %d", &vi, &vj);
        if (vi == -1 && vj == -1) break;
        printf("请输入边为[%d->%d]的权值 weight = ", vi, vj);
        scanf("%d", &weight);
        ALGraph_AddEdge(G, vi, vj, weight);
    }
}

// 拓扑排序
bool TopologicalSort (ALGraph G) {
    int indegree[MaxVertexNum] = {0}; // 存放每个顶点的入度
    Stack S; // 初始化栈,存储入度为0的顶点
    Stack_Init(S);

    // 计算每个顶点的入度
    for (int i = 0; i < G.vexnum; i++) {
        ArcNode *p = G.adjList[i].first;
        while (p) {
            indegree[p->adjvex]++;
            p = p->next;
        }
    }

    // 将入度为 0 的顶点入栈
    for (int i = 0; i < G.vexnum; i++) {
        if (indegree[i] == 0) {
            Stack_Push(S, i);
        }
    }

    int count = 0; // 记录已经输出的顶点数
    while(!Stack_IsEmpty(S)) {
        int v = Stack_Pop(S); // 弹出栈顶入度为 0 的顶点
        printf("%c", G.adjList[v].data); // 输出顶点
        count++;
        ArcNode *p = G.adjList[v].first;
        while (p) {
            indegree[p->adjvex]--;
            if (indegree[p->adjvex] == 0) {
                Stack_Push(S, p->adjvex);
            }
            p = p->next;
        }

    }
    if (count != G.vexnum) {
        printf("\n图存在回路!\n");
        return false;
    }
    return true;
}

void ALGraph_Show (ALGraph G) {
    for (int i = 0; i < G.vexnum; i++) {
        printf("%c", G.adjList[i].data);
        ArcNode *p = G.adjList[i].first;
        while (p) {
            printf("->%c", G.adjList[p->adjvex].data);
            p = p->next;
        }
        printf("\n");
    }
}

int main () {
    printf("注意,当前创建图为有向图\n");
    ALGraph G;
    // ALGraph_Create(G);
    G.vexnum = 5;
    G.arcnum = 7;
    G.adjList[0].data = 'a';
    G.adjList[1].data = 'b';
    G.adjList[2].data = 'c';
    G.adjList[3].data = 'd';
    G.adjList[4].data = 'e';
    G.adjList[0].first = NULL;
    G.adjList[1].first = NULL;
    G.adjList[2].first = NULL;
    G.adjList[3].first = NULL;
    G.adjList[4].first = NULL;

    // 建立边表
    ALGraph_AddEdge(G, 0, 1, 0); // a->b
    ALGraph_AddEdge(G, 0, 3, 0); // a->d
    ALGraph_AddEdge(G, 1, 3, 0); // b->d
    ALGraph_AddEdge(G, 1, 2, 0); // b->c
    ALGraph_AddEdge(G, 3, 4, 0); // d->e
    ALGraph_AddEdge(G, 3, 2, 0); // d->c
    ALGraph_AddEdge(G, 2, 4, 0); // c->e

    ALGraph_Show(G);
    TopologicalSort(G);
    return 0;
}
#include <stdio.h>
#include <stdlib.h>

typedef char VertexType; // 顶点类型
typedef int EdgeType; // 边上的权值
#define MAXVEX 100 // 最大顶点数
#define INF 65535 // 如果两个顶点之间不可达,用无穷表示距离
#define DIRECTED true // 是否为有向图

typedef struct {
  VertexType vexs[MAXVEX]; // 顶点表
  EdgeType arc[MAXVEX][MAXVEX]; // 邻接矩阵,可看做边表
  int vexNum, edgeNum; // 图中当前的顶点数和边数
} MGraph;

// 栈相关
// 定义栈中元素的最大个数为顶点个数
#define STACK_MAX_SIZE MAXVEX

typedef struct {
  int data[STACK_MAX_SIZE];
  int top;
} SqStack;

// 初始化栈
void Stack_Init(SqStack &S) {
  S.top = -1; // 初始化栈顶指针为-1,表示栈为空
}

// 判断栈是否为空
bool Stack_Empty(SqStack S) {
  return S.top == -1;
}

// 判断栈是否已满
bool Stack_Full(SqStack S) {
  return S.top == STACK_MAX_SIZE - 1;
}

// 新元素入栈
bool Stack_Push(SqStack &S, int x) {
  if (Stack_Full(S)) {
    printf("栈已满,无法入栈");
    return false;
  } else {
    S.data[++S.top] = x; // 将元素入栈,并更新栈顶指针
    return true;
  }
}

// 栈顶元素出栈,x为出栈的栈顶元素
bool Stack_Pop(SqStack &S, int &x) {
  if (Stack_Empty(S)) {
    printf("栈为空,无法出栈");
    return false;
  } else {
    x = S.data[S.top--]; // 将栈顶元素出栈,并更新栈顶指针
    return true;
  }
}

// 创建邻接矩阵
int Graph_Create (MGraph &G) {
  int vi, vj, weight;
  // 输入顶点数和边数
  printf("请输入顶点数:");
  scanf("%d", &G.vexNum);
  printf("请输入边数:");
  scanf("%d", &G.edgeNum);

  for (int i = 0; i < G.vexNum; i++) { // 为每个顶点初始化信息
    printf("请输入第 %d 个的顶点名称: ", i + 1);
    scanf(" %c", &G.vexs[i]);
  }
  for (int i = 0; i < G.vexNum; i++) { // 初始化顶点之间的权值 默认为无穷
    for (int j = 0; j < G.vexNum; j++) {
      G.arc[i][j] = INF;
    }
  }

  printf("下标为 -1 -1 则退出创建边\n");
  for(int i = 0; i < G.edgeNum; i++){ // 根据边的条数,为每一条边赋值
    printf("请输入要创建边的下标 v1 v2 ");
    scanf("%d %d", &vi, &vj);
    if (vi == -1 && vj == -1) break;
    printf("请输入边为[%d][%d]的权值 weight = ", vi, vj);
    scanf("%d", &weight);
    G.arc[vi][vj] = weight;
    // 在无向网中满足图对称性,即Vi-Vj 和Vj-Vi的距离相等,实际就是一条路径
    if (!DIRECTED) {
      G.arc[vj][vi] = weight;
    }
  }
  return 0;
}

// 打印图
void Graph_Show (MGraph G) {
  printf("顶点:");
  // 打印顶点
  for (int i = 0; i < G.vexNum; i++)
      printf("%c ", G.vexs[i]);
  printf("\n邻接矩阵:\n");
  // 打印邻接矩阵
  for(int i = 0; i < G.vexNum; i++){
    for(int j = 0; j < G.vexNum; j++){
      if(G.arc[i][j] == INF) printf("%6s", "∞");
      else printf("%6d", G.arc[i][j]);
    }
    printf("\n");
  }
}

// 求关键路径
bool Critical_Path (MGraph G) {
  // 1.先求拓扑排序
  SqStack S;
  Stack_Init(S);
  // 拓扑排序序列,存储的为顶点下标
  int topOrder[MAXVEX];
  // 当前拓扑排序中有多少个元素
  int topOrderLen = 0;

  // 每个顶点的入度数量
  int inDegree[MAXVEX];
  // 初始入度为 0
  for (int i = 0; i < MAXVEX; i++) inDegree[i] = 0;

  // 计算每个顶点的初始入度
  for (int i = 0; i < G.vexNum; i++) {
    for (int j = 0; j < G.vexNum; j++) {
      if (G.arc[i][j] != INF) {
        // 行为出度,列为入度
        // 这里使用 j 代表列
        inDegree[j] = inDegree[j] + 1;
      }
    }
  }

  // 将所有入度为0的顶点下标加入栈中
  for (int i = 0; i < G.vexNum; i++) {
    if (inDegree[i] == 0) {
      Stack_Push(S, i);
    }
  }

  // 开始拓扑排序 栈不为空则进入循环
  while (!Stack_Empty(S)) {
    // 弹出栈顶
    int u;
    Stack_Pop(S, u);

    // 将当前出栈的顶点下标加入拓扑排序序列中
    topOrder[topOrderLen] = u;
    topOrderLen++;

    // 遍历当前顶点的邻接顶点
    for (int i = 0; i < G.vexNum; i++) {
      if (G.arc[u][i] != INF) {
        // 减少邻接顶点的入度
        inDegree[i]--;

        // 如果邻接顶点的入度为0了,则将其下标加入栈
        // 注意:加入栈的始终为下标,不是顶点名称
        if (inDegree[i] == 0) {
          Stack_Push(S, i);
        }
      }
    }
  }

  printf("\n拓扑排序顶点下标序列:");
  for (int i = 0; i < topOrderLen; i++) {
    printf("%d ", topOrder[i]);
  }
  // 如果拓扑排序后的序列长度不等于顶点数,说明拓扑排序失败,则不进行关键路径求解
  if (topOrderLen != G.vexNum) return false;

  // 求关键路径

  // 2.求所有时间的最早发生时间 ve
  int ve[MAXVEX];
  int veMax = 0;
  // 初始 ve 为 0
  for (int i = 0; i < G.vexNum; i++) ve[i] = 0;

  for (int i = 0; i < topOrderLen; i++) {
    // 根据拓扑序列,依次计算顶点最早开始时间
    int u = topOrder[i];
    // 对于每个顶点,依次遍历其所有的出边(邻接顶点)
    for (int j = 0; j < G.vexNum; j++) {
      // 其他顶点到达 u 的权值
      int weight = G.arc[j][u];
      // 检查是否通过顶点 j 到达顶点 u 的路径能够获得更早的开始时间
      if (
        weight != INF
        &&
        (ve[j] + weight) > ve[u]
      ) {
        // 更新最早开始时间
        ve[u] = ve[j] + weight;
        // 记录最大值,给第 3 步求所有事件的最迟发生时间使用
        if (ve[u] > veMax) veMax = ve[u];
      }
    }
  }

  // 3.求所有事件的最迟发生时间 vl
  // 按逆拓扑排序序列,依次求各个顶点的 vl
  int vl[MAXVEX];
  // 初始化最迟发生时间
  for (int i = 0; i < G.vexNum; i++) {
    vl[i] = veMax;
  }
  for (int i = topOrderLen - 1; i >= 0; i--) {
    int u = topOrder[i];
    for (int j = 0; j < G.vexNum; j++) {
      // u 到其它顶点的权值
      int weight = G.arc[u][j];
      if (
        weight != INF
        &&
        vl[j] - weight < vl[u]
      ) {
        vl[u] = vl[j] - weight;
      }
    }
  }

  int e[MAXVEX * 2]; // 因为是记录边,所以最大值为顶点 * 2
  int l[MAXVEX * 2];
  int d[MAXVEX * 2];
  int edgeLen = 0;
  printf("\n关键路径:");
  for (int i = 0; i < G.vexNum; i++) {
    for (int j = 0; j < G.vexNum; j++) {
      int weight = G.arc[i][j];
      // 边存在
      if (weight != INF) {
        // 4.求所有活动的最早发生时间(e)
        // 边活动最早发生时间等于其起点顶点的 ve
        e[edgeLen] = ve[i];

        // 5.求所有活动的最迟发生时间(l)
        // 边活动的最迟发生时间等于 其指向 顶点的 vl - 边权值
        l[edgeLen] = vl[j] - weight;

        // 6.求所有活动的时间余量(d)
        d[edgeLen] = l[edgeLen] - e[edgeLen];

        // 7.余量 d 为 0 的即关键边
        if (d[edgeLen] == 0) {
          printf("%d -> %d,", i, j);
        }
        edgeLen++;
      }
    }
  }

  printf("\n所有事件的最早发生时间(ve):");
  for (int i = 0; i < G.vexNum; i++) {
    printf("%d ", ve[i]);
  }

  printf("\n所有事件的最迟发生时间(vl):");
  for (int i = 0; i < G.vexNum; i++) {
    printf("%d ", vl[i]);
  }

  printf("\n所有活动的最早发生时间(e):");
  for (int i = 0; i < edgeLen; i++) {
    printf("%d ", e[i]);
  }

  printf("\n所有活动的最迟发生时间(l):");
  for (int i = 0; i < edgeLen; i++) {
    printf("%d ", l[i]);
  }

  printf("\n求所有活动的时间余量  (d):");
  for (int i = 0; i < edgeLen; i++) {
    printf("%d ", d[i]);
  }

  // 关键路径即为 活动时间余量 d 为 0 的边
  return true;
}

int main () {
  MGraph G;
  // Graph_Create(G);
  G.vexs[0] = '1';
  G.vexs[1] = '2';
  G.vexs[2] = '3';
  G.vexs[3] = '4';
  G.vexs[4] = '5';
  G.vexs[5] = '6';
  G.vexNum = 6;

  // 初始化所有边为 无穷
  for (int i = 0; i < G.vexNum; i++) {
      for (int j = 0; j < G.vexNum; j++) {
      G.arc[i][j] = INF;
      }
  }
  G.arc[0][1] = 3;
  G.arc[0][2] = 2;
  G.arc[1][3] = 2;
  G.arc[1][4] = 3;
  G.arc[2][3] = 4;
  G.arc[2][5] = 3;
  G.arc[3][5] = 2;
  G.arc[4][5] = 1;
  G.edgeNum = 8;
  Graph_Show(G);

  // 求关键路径
  Critical_Path(G);
  return 0;
}