zoukankan      html  css  js  c++  java
  • 数据结构(5)—— 图

    写在前面

    图这一节,考察最多的依然是算法的实现过程,而不是代码本身。但实现还是要实现的。

    本文代码的实现参考了数据结构与算法系列 目录 - 如果天空不死 - 博客园 (cnblogs.com)的博客与王道书上的逻辑。

    按照惯例,上一节:数据结构(4)—— 树与二叉树

    图的存储结构以及遍历

    注意点

    这块内容比较少,就都写在一块了。图的类型主要是有向图与无向图,图的存储主要是邻接表与邻接矩阵,遍历主要是深度优先遍历与广度优先遍历。这里的实现没有太多要注意的点,主要就是按照王道书和我大二初学时的代码加以改造而成的。主要实现了无向图的邻接矩阵的广度优先与深度优先遍历,由于邻接表的遍历实现类似,就没有重复写了。

    代码

    无向图

    /*
     * @Description: 无向图的相关算法实现
     * @version: 1.0
     * @Author: Liuge
     * @Date: 2021-07-21 20:53:36
     */
    #include<bits/stdc++.h>
    // 顶点类型,由用户自己定义
    typedef char VertexType; 
    // 边上的权值类型,由用户自己定义
    typedef int  EdgeType;  
    // 最大顶点数,由用户定义
    #define MAX_VEX 20  
    // 用int的最大值来代表无穷大
    #define	INFINITY 65535
    // 访问数组,用来标识结点是否被访问过
    int visited[MAX_VEX]={0};
    
    // 用邻接矩阵法表示无向图
    typedef struct{
        // 顶点数组
    	VertexType vexs[MAX_VEX]; 
        // 邻接矩阵
    	EdgeType arc[MAX_VEX][MAX_VEX];
        // 图中当前定点数和边数
    	int vexNum, arcNum; 
    }Graph;
    
    // *******************队列相关定义开始*******************
    // 定义结点的结构
    typedef struct LinkNode{
        int data;
        struct LinkNode *next;
    }LinkNode;
    // 定义链式队列的结构
    typedef struct{
        LinkNode *front;
        LinkNode *rear;
    }LinkQueue;
    
    // 初始化
    void initQueue(LinkQueue &Q){
        // 建立头结点
        Q.front = Q.rear = (LinkNode *)malloc(sizeof(LinkNode));
        Q.front->next = NULL;
    }
    
    // 判队空
    bool isEmpty(LinkQueue Q){
        return Q.front == Q.rear;
    }
    
    // 入队
    void enQueue(LinkQueue &Q,int x){
        LinkNode *s = (LinkNode *)malloc(sizeof(LinkNode));
        s->data = x;
        s->next = NULL;
        Q.rear->next = s;
        // 队尾指针移动到新的尾部
        Q.rear = s;
    }
    
    // 出队
    bool deQueue(LinkQueue &Q,int &x){
        if(isEmpty(Q)){
            return false;
        }
        LinkNode *p = Q.front->next;
        x = p->data;
        Q.front->next = p->next;
        // 如果原队列只有一个结点,删除后变空
        if(Q.rear == p){
            Q.rear = Q.front;
        }
        free(p);
        return true;
    }
    // *******************队列相关定义结束*******************
    
    // 定位顶点v在顶点数组的下标位置,不存在返回-1
    int locateVex(Graph g, VertexType v)
    {
    	int i = 0;
    	for (i = 0; i < g.vexNum; i++)
    	{
    		if (g.vexs[i]==v)
    			break;
    	}
    	if (i > g.vexNum)
    	{
    		printf("结点不存在!");
    		return -1;
    	}
    	return i;
    }
    
    // 用邻接矩阵表示法,构造无向网(图)g
    void createUDN(Graph &g)
    {
    	int i, j;
    	EdgeType w;
     
    	printf("输入顶点数和边数:
    ");
    	scanf("%d,%d", &(g.vexNum), &(g.arcNum));
    	// 输入顶点
    	for(i = 0; i < g.vexNum; i++)
    	{
    		printf("顶点%d:", i + 1);
    		g.vexs[i]=getchar();
    		while(g.vexs[i]=='
    '){
    			g.vexs[i]=getchar();
    		}
    	}
    	getchar();
    	//初始化邻接矩阵
    	for (i = 0; i < g.arcNum; i++)
    	{
    		for (j = 0; j < g.arcNum; j++)
    		{
    			g.arc[i][j] = INFINITY;  
    		}
    	}
     
    	printf("输入边(vi, vj)上的顶点vi vj和权值w
    ");
    	for (i = 0; i < g.arcNum; i++)
    	{		
    		char v1, v2;
    		scanf("%c %c %d", &v1, &v2, &w);
    		getchar();
    		int m = locateVex(g, v1);
    		int n = locateVex(g, v2);
    		if (m == -1 || n == -1)
    		{
    			printf("结点不存在!");
    			return;
    		}
    		g.arc[m][n] = w;
    		#if 1
            // 按照对称直接赋值
    		g.arc[n][m] = g.arc[m][n];
    		#endif	
    	}
    }
    
    // 打印图
    void printGraph(Graph g)
    {
    	int i=0,j=0; 
    	printf("领接矩阵表为:
    ");
    	for (i = 0; i < g.vexNum; i++)
    	{
    		for (j = 0; j < g.vexNum; j++)
    		{
    			printf("%6d", g.arc[i][j]);
    		}
    		putchar('
    ');
    	}
    }
    
    // 图的深度优先遍历算法 
    void DFS_AM(Graph G,int v){
    	printf("%c ",G.vexs[v]);
    	visited[v] = 1;
    	int w;
    	for(w = 0;w < G.vexNum;w++){
    		if((G.arc[v][w] != INFINITY)&&(!visited[w])){
    			DFS_AM(G,w);
    		}
    	}
    }
    // 广度优先遍历算法
    void BFSTraverse(Graph g)
    {
    	LinkQueue q;
    	int v;
    	for (v = 0; v < g.vexNum; v++)
    		visited[v] = 0;
    	initQueue(q);
    	for (v = 0; v < g.vexNum; v++)
        	// 第v个顶点尚未访问
    		if (!visited[v])
    		{
    			visited[v] = 1;
                // 打印顶点,也可以是其他操作
    			printf("%c ", g.vexs[v]);
                // 第v个顶点入队列
    			enQueue(q, v);
    			while (!isEmpty(q))
    			{
    				int i,j=0;
    				deQueue(q, i);
    				for (j = 0; j < g.vexNum; j++)	  
    					// 判断其他顶点若与当前顶点存在边且未访问过
    					if (g.arc[i][j] > 0 && g.arc[i][j] != INFINITY && !visited[j])
    					{
                            // j为i尚未访问过的邻接顶点
    						visited[j] = 1;		 
    						printf("%c ", g.vexs[j]);	 
    						enQueue(q, j);	
    					}
    			}
    		}
    }
    
    // 主函数测试
    int main(){
        Graph G;
        createUDN(G);
        printGraph(G);
        printf("深度优先遍历结果为:
    ");
        DFS_AM(G,0);
        printf("
    ");
        printf("广度优先遍历结果为:
    ");
        BFSTraverse(G);
        return 0;
    }
    

    有向图

    /*
     * @Description: 有向图的相关算法实现
     * @version: 1.0
     * @Author: Liuge
     * @Date: 2021-07-21 21:15:19
     */
    
    #include<bits/stdc++.h>
    // 顶点类型,由用户自己定义
    typedef char VertexType;
    // 边上的权值类型,由用户自己定义
    typedef int  EdgeType;
    // 最大顶点数,由用户定义
    #define MAX_VEX 20
    
    // 使用邻接表法表示有向图
    // 边表结点
    typedef struct EdgeNode	
    {
        // 邻接点域,存储该顶点在顶点表中的下标
    	int adjvex;	
        // 网图权值
    	EdgeType weight;
       	// 链域,指向下一个邻接点 
    	struct EdgeNode *next;
    }EdgeNode;
    // 顶点表结点
    typedef struct VertexNode
    {
        // 顶点域,存储顶点信息
    	VertexType data;
        // 边表头指针
    	EdgeNode *firstedge;
    }VertexNode, AdjList[MAX_VEX];
    typedef struct  
    {
    	AdjList adjList;
        // 图中当前顶点数和弧数 
    	int vexNum, arcNum; 
    }GraphList;
    
    // 定位顶点v在顶表的下标位置,不存在返回-1
    int locateVex(GraphList g, VertexType v)
    {
    	int i;
    	for (i = 0; i < g.vexNum; i++)
    	{
    		if (v == g.adjList[i].data )
    			break;
    	}
    	if (i > g.vexNum)
    	{
    		printf("结点不存在!");
    		return -1;
    	}
    	return i;
    }
    
    // 用邻接表表示法,构造有向网g
    void createGraph(GraphList &g)
    {
    	int i, j;
    	EdgeType w;
    	EdgeNode *e, *f;
    	printf("输入顶点数和边数:
    ");
    	scanf("%d,%d", &(g.vexNum), &(g.arcNum)); 
    	//输入顶点
    	for (i = 0; i < g.vexNum; i++)
    	{
    		printf("顶点%d:", i+1);
    		g.adjList[i].data = getchar();
    		g.adjList[i].firstedge = NULL;
    		while(g.adjList[i].data == '
    ')
    		{
    			g.adjList[i].data = getchar();
    		}
    	}
    	getchar();
    	// 建立边表
    	printf("输入边(vi, vj)上的顶点vi vj和权值w
    ");
    	for (i = 0; i < g.arcNum; i++)
    	{		
    		char v1, v2;
    		scanf("%c %c %d", &v1, &v2, &w);
    		getchar();
    		int m = locateVex(g, v1);
    		int n = locateVex(g, v2);
    		if (m == -1 || n == -1)
    		{
    			printf("结点不存在!");
    			return;
    		}
    		//向内存申请空间,生成边表结点
    		e = (EdgeNode*)malloc(sizeof(EdgeNode));
    		if(e == NULL)
    		{
    			printf("内存空间申请失败!");
    			return;
    		}
            // 邻接序号为n
    		e->adjvex = n;
            // 权值
    		e->weight = w;
            // 单链表的头插法
    		e->next = g.adjList[m].firstedge;
    		g.adjList[m].firstedge = e;
    	}
    }
    
    void printGrapth(GraphList g)
    {
    	int i;
        printf("邻接表为:
    ");
    	for (i = 0; i < g.vexNum; i++)
    	{
    		printf("顶点%c ", g.adjList[i].data) ;
    		EdgeNode *e = g.adjList[i].firstedge;
    		while (e != NULL)
    		{
    			printf("―> <%c, %c> 权值为: %d  ", g.adjList[i].data, g.adjList[e->adjvex].data, e->weight);
    			e = e->next;
    		}
    		putchar('
    ');
    	}
    }
    
    // 主函数测试
    int main(){
        GraphList G;
        createGraph(G);
        printGrapth(G);
        return 0;
    }
    

    最小生成树——Prim算法

    注意点

    书上在这块有两种算法,Prim和Kruskal算法。我这里随便挑选了一种来实现,另一种的实现就不再写了。Prim算法实现的重点是要遍历找到权值最小的边,然后加入到顶点集合中。具体实现看代码好了。

    代码

    /*
     * @Description: Prim算法的实现
     * @version: 1.0
     * @Author: Liuge
     * @Date: 2021-07-24 19:41:35
     */
    #include<bits/stdc++.h>
    
    // 顶点类型,由用户自己定义
    typedef char VertexType; 
    // 边上的权值类型,由用户自己定义
    typedef int  EdgeType;  
    // 最大顶点数,由用户定义
    #define MAX_VEX 20  
    // 用int的最大值来代表无穷大
    #define	INFINITY 65535
    // 访问数组,用来标识结点是否被访问过
    int visited[MAX_VEX]={0};
    
    // 用邻接矩阵法表示无向图
    typedef struct{
        // 顶点数组
    	VertexType vexs[MAX_VEX]; 
        // 邻接矩阵
    	EdgeType arc[MAX_VEX][MAX_VEX];
        // 图中当前定点数和边数
    	int vexNum, arcNum; 
    }Graph;
    
    // 定位顶点v在顶点数组的下标位置,不存在返回-1
    int locateVex(Graph g, VertexType v)
    {
    	int i = 0;
    	for (i = 0; i < g.vexNum; i++)
    	{
    		if (g.vexs[i]==v)
    			break;
    	}
    	if (i > g.vexNum)
    	{
    		printf("结点不存在!");
    		return -1;
    	}
    	return i;
    }
    
    // 用邻接矩阵表示法,构造无向网(图)g
    void createUDN(Graph &g)
    {
    	int i, j;
    	EdgeType w;
     
    	printf("输入顶点数和边数:
    ");
    	scanf("%d,%d", &(g.vexNum), &(g.arcNum));
    	// 输入顶点
    	for(i = 0; i < g.vexNum; i++)
    	{
    		printf("顶点%d:", i + 1);
    		g.vexs[i]=getchar();
    		while(g.vexs[i]=='
    '){
    			g.vexs[i]=getchar();
    		}
    	}
    	getchar();
    	//初始化邻接矩阵
    	for (i = 0; i < g.arcNum; i++)
    	{
    		for (j = 0; j < g.arcNum; j++)
    		{
    			g.arc[i][j] = INFINITY;  
    		}
    	}
     
    	printf("输入边(vi, vj)上的顶点vi vj和权值w
    ");
    	for (i = 0; i < g.arcNum; i++)
    	{		
    		char v1, v2;
    		scanf("%c %c %d", &v1, &v2, &w);
    		getchar();
    		int m = locateVex(g, v1);
    		int n = locateVex(g, v2);
    		if (m == -1 || n == -1)
    		{
    			printf("结点不存在!");
    			return;
    		}
    		g.arc[m][n] = w;
    		#if 1
            // 按照对称直接赋值
    		g.arc[n][m] = g.arc[m][n];
    		#endif	
    	}
    }
    
    // prim 算法生成最小生成树
    void prim(Graph G, int start)
    {
        int min,i,j,k,m,n,sum;
        // 最小生成树的索引,即prims数组的索引
        int index=0;         
        // 存储最小生成树的数组
        char prims[MAX_VEX];  
        // 顶点间边的权值  
        int weights[MAX_VEX]; 
    
        // prim最小生成树中第一个数是"图中第start个顶点",因为是从start开始的。
        prims[index++] = G.vexs[start];
    
        // 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。
        for (i = 0; i < G.vexNum; i++){
            weights[i] = G.arc[start][i];
        }
        // 将第start个顶点的权值初始化为0。
        weights[start] = 0;
        for (i = 0; i < G.vexNum; i++)
        {
            // 由于从start开始的,因此不需要再对第start个顶点进行处理。
            if(start == i){
                continue;
            }
            j = 0;
            k = 0;
            min = INFINITY;
            // 在未被加入到最小生成树的顶点中,找出权值最小的顶点。
            while (j < G.vexNum)
            {
                // 若weights[j]=0,意味着"第j个节点已经被加入到了最小生成树中"
                if (weights[j] != 0 && weights[j] < min)
                {
                    min = weights[j];
                    k = j;
                }
                j++;
            }
    
            // 经过上面的处理后,在未被加入到最小生成树的顶点中,权值最小的顶点是第k个顶点。
            // 将第k个顶点加入到最小生成树的结果数组中
            prims[index++] = G.vexs[k];
            // 将"第k个顶点的权值"标记为0 代表第k个顶点已经加入到了结果中
            weights[k] = 0;
            // 当第k个顶点被加入到最小生成树的结果数组中之后,更新其它顶点的权值。
            for (j = 0 ; j < G.vexNum; j++)
            {
                // 当第j个节点没有被处理,并且需要更新时才被更新。
                if (weights[j] != 0 && G.arc[k][j] < weights[j]){
                    weights[j] = G.arc[k][j];
                }    
            }
        }
    
        // 计算最小生成树的权值
        sum = 0;
        for (i = 1; i < index; i++)
        {
            min = INFINITY;
            // 获取prims[i]在G中的位置
            n = locateVex(G, prims[i]);
            // 在vexs[0...i]中,找出到j的权值最小的顶点。
            for (j = 0; j < i; j++)
            {
                m = locateVex(G, prims[j]);
                if (G.arc[m][n]<min){
                    min = G.arc[m][n];
                }
            }
            sum += min;
        }
        // 打印最小生成树
        printf("PRIM(%c)=%d: ", G.vexs[start], sum);
        for (i = 0; i < index; i++)
            printf("%c ", prims[i]);
        printf("
    ");
    }
    
    // 主函数测试
    int main(){
        Graph G;
        createUDN(G);
        prim(G,0);
    }
    

    最短路径——Floyd算法

    注意点

    这里书上也是提出了两种算法,我选择了Floyd算法来进行实现,因为这种算法虽然时间复杂度更高但实现其实较为简单。在这里的实现中,重点就是如何更新A矩阵。直接看代码吧。其实就是一个三层循环,然后里面有

    代码

    /*
     * @Description: Floyd算法的实现
     * @version: 1.0
     * @Author: Liuge
     * @Date: 2021-07-24 21:05:30
     */
    
    #include <bits/stdc++.h>
    
    #define MAXV 100
    #define INF 9999
    typedef struct
    {
        int edges[MAXV][MAXV];
        int n, e;
    } MGraph;
    void ppath(int path[][MAXV], int i, int j)
    {
        int k;
        k = path[i][j];
        if (k == -1)
            return;
        ppath(path, i, k);
        printf("%d,", k);
        ppath(path, k, j);
    }
    // 输出最短路径
    void DisPath(int A[][MAXV], int path[][MAXV], int n)
    {
        int i, j;
        for (i = 0; i < n; i++){
            for (j = 0; j < n; j++){
                if (A[i][j] != INF && i != j){
                    printf("  从%d到%d路径为:", i, j);
                    printf("%d,", i);
                    ppath(path, i, j);
                    printf("%d", j);
                    printf("	路径长度为:%d
    ", A[i][j]);
                }
            }
        }
    }
    
    // Floyd算法的实现
    void Floyd(MGraph g)
    {
        int A[MAXV][MAXV], path[MAXV][MAXV];
        int i, j, k, n = g.n;
        // 给A数组置初值
        for (i = 0; i < n; i++){
            for (j = 0; j < n; j++){
                A[i][j] = g.edges[i][j];
                path[i][j] = -1;
            }
        }
        // 计算Ak
        for (k = 0; k < n; k++){
            for (i = 0; i < n; i++){
                for (j = 0; j < n; j++){
                    if (A[i][j] > (A[i][k] + A[k][j])){
                        A[i][j] = A[i][k] + A[k][j];
                        path[i][j] = k;
                    }
                }
            }
        }
        printf("
    输出最短路径:
    ");
        // 输出最短路径
        DisPath(A, path, n); 
    }
    //输出邻接矩阵g
    void DispMat(MGraph g){
        int i, j;
        for (i = 0; i < g.n; i++{
            for (j = 0; j < g.n; j++){
                if (g.edges[i][j] == INF){
                    printf("%3s", "∞");
                }else{
                    printf("%3d", g.edges[i][j]);
                }
            }
            printf("
    ");
        }
    }
    int main(){
        int i, j, n;
        MGraph g;
        printf("请输入图中节点的个数
    ");
        scanf("%d", &n);
        int B[n][n];
        g.n = n;
        g.e = n;
        printf("请输入邻接矩阵
    ");
        for (i = 0; i < n; i++){
            for (j = 0; j < n; j++){
                scanf("%d", &B[i][j]);
            }
        }
        for (i = 0; i < g.n; i++){
            for (j = 0; j < g.n; j++){
                g.edges[i][j] = B[i][j];
            }
        }
        //DispMat(g);
        Floyd(g);
        printf("
    ");
        return 0;
    }
    

    拓扑排序

    注意点

    这里是按照王道教材上的实现方法,对其进行了一部分改写,使用了栈进行实现。大概的思路很简单,每次都删掉入度为0的结点,然后输出结点,最后删完为止。具体实现看代码吧。

    代码

    /*
     * @Description: 拓扑排序的邻接表实现
     * @version: 1.0
     * @Author: Liuge
     * @Date: 2021-07-24 20:14:44
     */
    #include<bits/stdc++.h>
    
    // 顶点类型,由用户自己定义
    typedef char VertexType;
    // 边上的权值类型,由用户自己定义
    typedef int  EdgeType;
    // 最大顶点数,由用户定义
    #define MAX_VEX 20
    
    #define maxSize 50
    // 使用邻接表法表示有向图
    // 边表结点
    typedef struct EdgeNode	
    {
        // 邻接点域,存储该顶点在顶点表中的下标
    	int adjvex;	
        // 网图权值
    	EdgeType weight;
       	// 链域,指向下一个邻接点 
    	struct EdgeNode *next;
    }EdgeNode;
    // 顶点表结点
    typedef struct VertexNode
    {
        // 顶点域,存储顶点信息
    	VertexType data;
        // 边表头指针
    	EdgeNode *firstedge;
    }VertexNode, AdjList[MAX_VEX];
    typedef struct  
    {
    	AdjList adjList;
        // 图中当前顶点数和弧数 
    	int vexNum, arcNum; 
    }GraphList;
    
    // ************顺序栈的相关实现************
    
    // 顺序栈的存储结构
    typedef struct{
        int data[maxSize];
        // 栈顶指针
        int top;
    }SqStack;
    
    // 初始化栈
    void initStack(SqStack &S){
        // 这里把栈顶指针设为-1,也可以设为0
        S.top = -1;
    }
    
    // 判空
    bool isStackEmpty(SqStack S){
        return S.top == -1;
    }
    
    // 进栈
    bool push(SqStack &S, int e){
        // 栈满
        if(S.top == maxSize -1){
            return false;
        }
        S.data[++S.top] = e;
        return false;
    }
    
    // 出栈
    bool pop(SqStack &S,int &e){
        // 栈空
        if(S.top == -1){
            return false;
        }
        e = S.data[S.top--];
        return true;
    }
    
    // 读栈顶元素
    bool getTop(SqStack &S,int &e){
        if(S.top == -1){
            return false;
        }
        e = S.data[S.top];
        return true;
    }
    // ************顺序栈的相关实现结束************
    
    
    
    // 定位顶点v在顶表的下标位置,不存在返回-1
    int locateVex(GraphList g, VertexType v)
    {
    	int i;
    	for (i = 0; i < g.vexNum; i++)
    	{
    		if (v == g.adjList[i].data )
    			break;
    	}
    	if (i > g.vexNum)
    	{
    		printf("结点不存在!");
    		return -1;
    	}
    	return i;
    }
    
    // 用邻接表表示法,构造有向网g
    void createGraph(GraphList &g)
    {
    	int i, j;
    	EdgeType w;
    	EdgeNode *e, *f;
    	printf("输入顶点数和边数:
    ");
    	scanf("%d,%d", &(g.vexNum), &(g.arcNum)); 
    	//输入顶点
    	for (i = 0; i < g.vexNum; i++)
    	{
    		printf("顶点%d:", i+1);
    		g.adjList[i].data = getchar();
    		g.adjList[i].firstedge = NULL;
    		while(g.adjList[i].data == '
    ')
    		{
    			g.adjList[i].data = getchar();
    		}
    	}
    	getchar();
    	// 建立边表
    	printf("输入边(vi, vj)上的顶点vi vj和权值w
    ");
    	for (i = 0; i < g.arcNum; i++)
    	{		
    		char v1, v2;
    		scanf("%c %c %d", &v1, &v2, &w);
    		getchar();
    		int m = locateVex(g, v1);
    		int n = locateVex(g, v2);
    		if (m == -1 || n == -1)
    		{
    			printf("结点不存在!");
    			return;
    		}
    		//向内存申请空间,生成边表结点
    		e = (EdgeNode*)malloc(sizeof(EdgeNode));
    		if(e == NULL)
    		{
    			printf("内存空间申请失败!");
    			return;
    		}
            // 邻接序号为n
    		e->adjvex = n;
            // 权值
    		e->weight = w;
            // 单链表的头插法
    		e->next = g.adjList[m].firstedge;
    		g.adjList[m].firstedge = e;
    	}
    }
    // 拓扑排序
    bool toplogicalSort(GraphList G){
        SqStack S;
        // 初始化一个栈,存储入度为0的结点
        initStack(S);
        // 统计每个顶点的入度数
        int indegree[100];
        EdgeNode *node;
        for(int i = 0; i < G.vexNum; i++)
        {
            node = G.adjList[i].firstedge;
            while (node != NULL)
            {
                indegree[node->adjvex]++;
                node = node->next;
            }
        }
        // 把所有度为0的结点存储到栈内
        for(int i = 0;i < G.vexNum;i++){
            if(indegree[i] == 0){
                push(S,i);
            }
        }
        // 开始进行拓扑排序
        int i;
        // 使用count记录输出了几个结点
        int count = 0;
        while(!isStackEmpty(S)){
            // 栈顶元素出栈
            pop(S,i);
            // 输出顶点i
            printf("%c ",G.adjList[i].data);
            count++;
            for(EdgeNode *p = G.adjList[i].firstedge;p != NULL;p = p->next){
                // 将所有i指向的顶点的入度减1,并且把入度为0的顶点压入栈S
                int v = p->adjvex;
                if(!(--indegree[v])){
                    push(S,v);
                }
            }
        }
        return !(count < G.vexNum);
    }
    
    // 主函数测试
    int main(){
        GraphList G;
        createGraph(G);
        printf("拓扑排序序列为:
    ");
        toplogicalSort(G);
        return 0;
    }
    

    总结

    这一章的核心部分在图的应用,也就是后面几个算法的实现。关键路径我并没有实现,个人认为掌握手写做法就大概足够了。感谢网上的大佬资料。

  • 相关阅读:
    团队-科学计算器-成员简介及分工
    提交错误
    《结对-结对编项目作业名称-需求分析》
    对软件工程课程的期望
    自我介绍
    课堂作业0
    selenium+Java刷新浏览器
    不要焦虑~~
    JAVA代码实现得到指定文件夹下的文件名
    安全检测检查清单(IOS版APP)
  • 原文地址:https://www.cnblogs.com/wushenjiang/p/15056358.html
Copyright © 2011-2022 走看看