王道数据结构【图】部分代码实现(C语言)

数据结构专栏:

  1. 王道数据结构【顺序表】部分代码实现(C语言)
  2. 王道数据结构【链表】部分代码实现(C语言)
  3. 王道数据结构【栈队列及其应用】部分代码实现(C语言)
  4. 王道数据结构【二叉树】部分代码实现(C语言)
  5. 王道数据结构【图】部分代码实现(C语言)
  6. 王道数据结构【查找排序】部分代码实现(C语言)

邻接矩阵存储图

/*
	使用邻接矩阵构造图
	分析:
		虽然图相比于其它数据结构较复杂,但也是十分易懂的,对于使用邻接矩阵存储的图来说,我们所需要知道的数据有
		图的顶点数、边数、用一个二维数组存储的边与边的联系及其权值,未连接的边我们要使用无穷表示,节点自身用0
		表示,初始时除自身节点外均表示为无穷。另外我们还需要一个一维数组用来存储我们的顶点个数
*/
#define _CRT_SECURE_NO_WARNINGS
#define MAXSIZE 100 //数组最大值
#define TYPE int
#include <stdio.h>
#include <stdlib.h>
typedef struct Graph {
	TYPE Vertex[MAXSIZE];
	int Edge[MAXSIZE][MAXSIZE];
	int numV, numE;//顶点、边数量
}adjMatrix;

void createGraph(adjMatrix *G) {
	int v, e, vi, vj, w;
	printf("请输入创建的图的顶点与边个数(以空格分开):");
	scanf("%d %d", &v, &e);
	G->numE = e;
	G->numV = v;
	//初始化图
	for (int i = 0; i < v; i++) {
		for (int j = 0; j < v; j++) {
			i == j ? G->Edge[i][j] = 0 : G->Edge[i][j] = 32767;
		}
	}
	//将顶点存入数组
	for (int i = 0; i < G->numV; i++) {
		printf("请输入第%d个节点信息:", i + 1);
		scanf("\n%c", &G->Vertex[i]);
	}
	//开始建立边与边的关系
	for (int i = 0; i < G->numE; i++) {
		printf("请输入边的信息vi vj w(以空格分开)");
		scanf("%d %d %d", &vi, &vj, &w);//有权值就写
		G->Edge[vi - 1][vj - 1] = w;//①
		G->Edge[vj - 1][vi - 1] = w;//②   这代表无向图
	}

}
void createGraphFromFile(adjMatrix *G) {
	FILE *fp;//创建文件指针
	char ev[4] = {};
	char numE[3] = { 0 };//边个数信息
	char numV[3] = { 0 };//顶点个数信息
	char arc[6] = { 0 };//边信息
	char *vertex;//顶点信息,名称
	fp = fopen("graph.txt", "r");//打开文件
	if (fp == NULL) {
		printf("该文件无法打开!");
		return;
	}
	fscanf(fp,"%hu %hu", numE, numV);//读取第一行
	G->numE = numE[0];
	G->numV = numV[0];

	//初始化图
	for (int i = 0; i < G->numV; i++) {
		for (int j = 0; j < G->numV; j++) {
			i == j ? G->Edge[i][j] = 0 : G->Edge[i][j] = 32767;
		}
	}
	vertex = (char *)malloc(sizeof(char*)*G->numV);//这是用来存储顶点信息的数组(顶点的名字)
	for (int i = 0; i <= G->numE; i++) {//开始获取后面的信息
		if (i == 0) {//此时,根据我们文件的结构,第二行是顶点信息
			fgets(ev, 4, fp);//获取回车符,上一次fgets后会停在回车符那儿
			fgets(vertex, G->numV * 2, fp);//这里获取顶点信息
			int w = 0;//用一个计数器,保证adjlist依次存储顶点
			for (int j = 0; j < G->numV * 2; j++) {//因为有空格,所以让j<G->numV*2
				if (vertex[j] == 32) {//是空格,不进行操作
					continue;
				}
				else {//开始赋值
					G->Vertex[w] = vertex[j];
					w++;
				}
			}
		}
		else {//开始依次存储边信息
			fgets(ev, 4, fp);//同样先吃掉换行符
			fgets(arc, 6, fp);//读取该行的边信息
			G->Edge[(int)arc[0] - 48 - 1][(int)arc[2] - 48 - 1] = (int)arc[4] - 48;
			G->Edge[(int)arc[2] - 48 - 1][(int)arc[0] - 48 - 1] = (int)arc[4] - 48;
		}

	}
	fclose(fp);

}
void dispGraph(adjMatrix *G) {
	int i, j;
	printf("\n输出顶点的信息(字符):\n");
	for (i = 0; i < G->numV; i++)
		printf("%8c", G->Vertex[i]);

	printf("\n输出邻接矩阵:\n");
	printf("\t");
	for (i = 0; i < G->numV; i++)
		printf("%8c", G->Vertex[i]);

	for (i = 0; i < G->numV; i++)
	{
		printf("\n%8c", G->Vertex[i]);
		for (j = 0; j < G->numV; j++)
		{
			if (G->Edge[i][j] == 32767)
				//两点之间无连接时权值为默认的32767,
				//在无向图中一般用"0"表示,在有向图中一般用"∞",
				//这里为了方便统一输出 "∞"
				printf("%8s", "∞");
			else
				printf("%8d", G->Edge[i][j]);
		}
		printf("\n");
	}

}
//int main() {
//	adjMatrix G;
//	createGraphFromFile(&G);
//	dispGraph(&G);
//}

邻接表存储图

/*
	采用邻接表的方式存储图
	分析:
		采用邻接表相对于邻接矩阵来说更节省存储空间,这里我们需要两个数据结构:
		①顶点表结构:包括顶点信息及指向第一个邻接点的头指针
		②边表结构:包括该邻接点域(在数组中的下标)、权值及下一个邻接点指针
		③一个数组,用于存储所有顶点,因为数组的随机存储特性,方便我们查找
		④图结构:包括顶点数组及顶点数、边数
		具体创建流程:
				首先我们需要输入图的顶点数和边数,将其存入图结构中,并由输入的顶点数依次输入顶点信息,并将第一个邻接点的头指针
			置位NULL,这是建立顶点表的流程;
				其次我们需要建立边表,根据输入的边个数,依次输入边(vi,vj)的顶点序号,再采取头插法进行插入,若是无向图则需要
			重复反向依次设置,至此,图的邻接表结构建立完成。

*/
#define _CRT_SECURE_NO_WARNINGS
#define MAXSIZE 100
#define TYPE int
typedef struct EdgeNode {//边表结点
	int index;//该边所指向的顶点的位置,在顶点数组里面的位置信息
	int weight;//权值
	EdgeNode *next;//下一个邻接边
}EdgeNode;

typedef struct VertexNode {//顶点表节点
	TYPE info;//顶点信息
	EdgeNode *firstEdge;//指向第一条依附该顶点的边的指针
}VertexNode, Adjlist[MAXSIZE];

typedef struct {
	Adjlist adjlist;//顶点数组
	int numE, numV;//边数、顶点数
}ALGraph;
#include <stdio.h>
#include <stdlib.h>

void createGraph(ALGraph *G) {
	int e, v, vi, vj, w;
	printf("请输入图的边数与结点数(以空格分开):");
	scanf("\n%d %d", &e, &v);
	G->numE = e;
	G->numV = v;
	printf("请依次输入顶点信息:\n");
	for (int i = 0; i < G->numV; i++) {
		printf("请输入第%d个结点信息:", i + 1);
		scanf("\n%c", &G->adjlist[i].info);
		G->adjlist[i].firstEdge = NULL;
		//G->adjlist[i].firstEdge->index = -1;
	}

	printf("请输入边表信息:\n");
	for (int i = 0; i < G->numE; i++) {
		printf("请输入边(vi,vj)的顶点序号及其权值(以空格分开):");
		scanf("%d %d %d", &vi, &vj, &w);
		//若是无向图则需要两个顶点进行操作,采用头插法
		EdgeNode *e = (EdgeNode *)malloc(sizeof(EdgeNode *));
		e->index = vj - 1;//数组下标要减一
		e->weight = w;
		e->next = G->adjlist[vi - 1].firstEdge;
		G->adjlist[vi - 1].firstEdge = e;

		/*EdgeNode *ed = (EdgeNode *)malloc(sizeof(EdgeNode *));
		ed->index = vi - 1;
		ed->weight = w;
		ed->next = G->adjlist[vj - 1].firstEdge;
		G->adjlist[vj - 1].firstEdge = ed;*/
	}

}
void createGraphInFile(ALGraph *G) {//从文件中读取我们的图的数据,包括边数,节点数,对应关系
	FILE *fp;//创建文件指针
	char ev[4] = {};
	char numE[3] = { 0 };//顶点,边个数信息
	char numV[3] = { 0 };//顶点,边个数信息
	char arc[6] = { 0 };//边信息
	char *vertex;//顶点信息,名称
	fp = fopen("graph.txt", "r");//打开文件
	if (fp == NULL) {
		printf("该文件无法打开!");
		return;
	}
	fscanf(fp, "%hu %hu", numE, numV);//读取第一行
	G->numE = numE[0];
	G->numV = numV[0];
	vertex = (char *)malloc(sizeof(char*)*G->numV);//这是用来存储顶点信息的数组(顶点的名字)
	for (int i = 0; i <= G->numE; i++) {//开始获取后面的信息
		if (i == 0) {//此时,根据我们文件的结构,第二行是顶点信息
			fgets(ev, 4, fp);//获取回车符,上一次fgets后会停在回车符那儿
			fgets(vertex,G->numV*2,fp);//这里获取顶点信息
			int w = 0;//用一个计数器,保证adjlist依次存储顶点
			for (int j = 0; j < G->numV*2;j++) {//因为有空格,所以让j<G->numV*2
				if (vertex[j]==32) {//是空格,不进行操作
					continue;
				}
				else {//开始赋值
					G->adjlist[w].info = vertex[j];
					G->adjlist[w].firstEdge = NULL;
					w++;
				}
			}
		}
		else {//开始依次存储边信息
			fgets(ev, 4, fp);//同样先吃掉换行符
			fgets(arc, 6, fp);//读取该行的边信息
			EdgeNode *e = (EdgeNode *)malloc(sizeof(struct EdgeNode ));
			e->index = atoi(&arc[2]) - 1;//数组下标要减一
			e->weight = atoi(&arc[4]);
			e->next = G->adjlist[atoi(&arc[0])-1].firstEdge;//采用头插法
			G->adjlist[atoi(&arc[0])-1].firstEdge = e;
			
			//下面与上面相似,目的在于构建无向图
			//EdgeNode *otherE = (EdgeNode *)malloc(sizeof(struct EdgeNode ));
			//otherE->index = atoi(&arc[0]) - 1;//数组下标要减一
			//otherE->weight = atoi(&arc[4]);
			//otherE->next = G->adjlist[atoi(&arc[2]) - 1].firstEdge;
			//G->adjlist[atoi(&arc[2]) - 1].firstEdge = otherE;
		}

	}
	fclose(fp);
}
void dispGraph(ALGraph *G) {//将图用邻接表的形式展示出来
	for (int i = 0; i < G->numV; i++) {
		int j = i;
		printf("%c-->", G->adjlist[j].info);
		EdgeNode *p = G->adjlist[j].firstEdge;
		while (p) {
			printf("(%d)%c-->", p->weight, G->adjlist[p->index].info);
			p = p->next;
		}
		printf("^\n");
	}

}
//int main() {
//	ALGraph G;
//	createGraphInFile(&G);
//	dispGraph(&G);
//	return 0;
//}

广度优先遍历

/*
	在采用邻接表存储的图上进行广度优先遍历/深度优先遍历
	分析:我们知道邻接表上的顶点所连接的节点都是它的相邻节点,而对于广度优先遍历来说,类似于层次遍历,就是要把所有的邻接点进行访问,
		  所以我们需要从第一个节点开始访问它的所有邻接点,还有需要注意的是,当我们把邻接点访问后,需要依次访问邻接点的邻接点,这就需要
		  用队列将我们访问过得邻接点入队,这和层次遍历一样,也只有这样,我们才能访问所有的节点。当然,在这个过程中,会有重复访问的情况,
		  所以我们需要用一个数组来记录节点的访问情况,已访问置true

		  对于深度优先遍历,顾名思义,我们会把每一个节点“榨干”,“顺藤摸瓜”,同样我们需要一个访问标记数组,而对于深度优先遍历,
		  我们将采用递归的方式来进行。
*/
//创建邻接表图结构  分为边表节点结构 顶点表节点结构 图结构

#define MAXSIZE 100
#define TYPE int
//边表结构 
typedef struct EdgeNode {//边表结点
	int index;//该边所指向的顶点的位置,在顶点数组里面的位置信息
	int weight;//权值
	EdgeNode *next;//下一个邻接边
}EdgeNode;

typedef struct VertexNode {//顶点表节点
	int info;//顶点信息
	EdgeNode *firstEdge;//指向第一条依附该顶点的边的指针
}VertexNode, Adjlist[MAXSIZE];

typedef struct {
	Adjlist adjlist;//顶点数组
	int numE, numV;//边数、顶点数
}ALGraph;
//队列结构(我们采用顺序队列)
struct Squeue {
	TYPE *arr;
	int front, rear;
};
#include <stdio.h>
#include <stdlib.h>
void BFSBegin(ALGraph *G) {
	void BFS(ALGraph *, int *, int);
	int *visited = (int *)malloc(sizeof(int)*G->numV);//设置标记数组
	for (int i = 0; i < G->numV; i++) {
		visited[i] = 0;
	}
	for (int i = 1; i < G->numV; i++) {//从第一个节点开始
		if (!visited[i]) {
			BFS(G, visited, i);
		}
	}
}
void BFS(ALGraph *G, int *visited, int v) {//开始广度遍历
	//声明有关队列的函数
	Squeue *createQueue(int);
	bool isEmpty(Squeue *);
	bool enQueue(Squeue *, TYPE, int);
	bool deQueue(Squeue *sq, TYPE *data, int maxSize);
	Squeue *sq;
	sq = createQueue(G->numV);//创建队列
	printf("%c ", G->adjlist[v].info);//访问传进来的顶点
	enQueue(sq, v, G->numV);//入队
	visited[v] = 1;//置为已访问
	while (!isEmpty(sq)) {//队列不空,取出队首元素,进行访问
		TYPE top;
		deQueue(sq, &top, G->numV);
		for (EdgeNode *w = G->adjlist[top].firstEdge; w; w = w->next) {//依次将当前节点的边表入队,和层次遍历一致
			if (!visited[w->index]) {
				printf("%c ", G->adjlist[w->index].info);
				visited[w->index] = 1;
				enQueue(sq, w->index, G->numV);

			}
		}
	}

}
void DFSBegin(ALGraph *G) {
	void DFS(ALGraph *, int *, VertexNode *, int);
	int *visited = (int *)malloc(sizeof(int)*G->numV);//设置标记数组
	for (int i = 0; i < G->numV; i++) {
		visited[i] = 0;
	}
	for (int i = 0; i < G->numV; i++) {//从第一个节点开始“顺藤摸瓜”
		if (!visited[i]) {
			DFS(G, visited, &G->adjlist[i], i);
		}
	}
}
void DFS(ALGraph *G, int *visited, VertexNode *v, int index) {
	printf("%c ", v->info);//打印传入的节点
	visited[index] = 1;//置访问为1
	for (EdgeNode *w = v->firstEdge; w; w = w->next) {
		if (w) {//如果有邻接点,传入DFS
			if (!visited[w->index]) {//未访问
				DFS(G, visited, &G->adjlist[w->index], w->index);
			}
		}

	}
}
int main() {
	ALGraph *graph = (ALGraph *)malloc(sizeof(ALGraph *));
	//声明函数
	void createGraph(ALGraph *);
	void createGraphInFile(ALGraph *);
	void dispGraph(ALGraph *);
	//创建图
	createGraphInFile(graph);
	//打印图
	dispGraph(graph);
	//广度优先遍历
	//BFSBegin(graph);
	//深度优先遍历
	DFSBegin(graph);
	return 0;
}

深度优先遍历

/*
	在采用邻接表存储的图上进行广度优先遍历/深度优先遍历
	分析:我们知道邻接表上的顶点所连接的节点都是它的相邻节点,而对于广度优先遍历来说,类似于层次遍历,就是要把所有的邻接点进行访问,
		  所以我们需要从第一个节点开始访问它的所有邻接点,还有需要注意的是,当我们把邻接点访问后,需要依次访问邻接点的邻接点,这就需要
		  用队列将我们访问过得邻接点入队,这和层次遍历一样,也只有这样,我们才能访问所有的节点。当然,在这个过程中,会有重复访问的情况,
		  所以我们需要用一个数组来记录节点的访问情况,已访问置true

		  对于深度优先遍历,顾名思义,我们会把每一个节点“榨干”,“顺藤摸瓜”,同样我们需要一个访问标记数组,而对于深度优先遍历,
		  我们将采用递归的方式来进行。
*/
//创建邻接表图结构  分为边表节点结构 顶点表节点结构 图结构

#define MAXSIZE 100
#define TYPE int
//边表结构 
typedef struct EdgeNode {//边表结点
	int index;//该边所指向的顶点的位置,在顶点数组里面的位置信息
	int weight;//权值
	EdgeNode *next;//下一个邻接边
}EdgeNode;

typedef struct VertexNode {//顶点表节点
	int info;//顶点信息
	EdgeNode *firstEdge;//指向第一条依附该顶点的边的指针
}VertexNode, Adjlist[MAXSIZE];

typedef struct {
	Adjlist adjlist;//顶点数组
	int numE, numV;//边数、顶点数
}ALGraph;
//队列结构(我们采用顺序队列)
struct Squeue {
	TYPE *arr;
	int front, rear;
};
#include <stdio.h>
#include <stdlib.h>
void BFSBegin(ALGraph *G) {
	void BFS(ALGraph *, int *, int);
	int *visited = (int *)malloc(sizeof(int)*G->numV);//设置标记数组
	for (int i = 0; i < G->numV; i++) {
		visited[i] = 0;
	}
	for (int i = 1; i < G->numV; i++) {//从第一个节点开始
		if (!visited[i]) {
			BFS(G, visited, i);
		}
	}
}
void BFS(ALGraph *G, int *visited, int v) {//开始广度遍历
	//声明有关队列的函数
	Squeue *createQueue(int);
	bool isEmpty(Squeue *);
	bool enQueue(Squeue *, TYPE, int);
	bool deQueue(Squeue *sq, TYPE *data, int maxSize);
	Squeue *sq;
	sq = createQueue(G->numV);//创建队列
	printf("%c ", G->adjlist[v].info);//访问传进来的顶点
	enQueue(sq, v, G->numV);//入队
	visited[v] = 1;//置为已访问
	while (!isEmpty(sq)) {//队列不空,取出队首元素,进行访问
		TYPE top;
		deQueue(sq, &top, G->numV);
		for (EdgeNode *w = G->adjlist[top].firstEdge; w; w = w->next) {//依次将当前节点的边表入队,和层次遍历一致
			if (!visited[w->index]) {
				printf("%c ", G->adjlist[w->index].info);
				visited[w->index] = 1;
				enQueue(sq, w->index, G->numV);

			}
		}
	}

}
void DFSBegin(ALGraph *G) {
	void DFS(ALGraph *, int *, VertexNode *, int);
	int *visited = (int *)malloc(sizeof(int)*G->numV);//设置标记数组
	for (int i = 0; i < G->numV; i++) {
		visited[i] = 0;
	}
	for (int i = 0; i < G->numV; i++) {//从第一个节点开始“顺藤摸瓜”
		if (!visited[i]) {
			DFS(G, visited, &G->adjlist[i], i);
		}
	}
}
void DFS(ALGraph *G, int *visited, VertexNode *v, int index) {
	printf("%c ", v->info);//打印传入的节点
	visited[index] = 1;//置访问为1
	for (EdgeNode *w = v->firstEdge; w; w = w->next) {
		if (w) {//如果有邻接点,传入DFS
			if (!visited[w->index]) {//未访问
				DFS(G, visited, &G->adjlist[w->index], w->index);
			}
		}

	}
}
int main() {
	ALGraph *graph = (ALGraph *)malloc(sizeof(ALGraph *));
	//声明函数
	void createGraph(ALGraph *);
	void createGraphInFile(ALGraph *);
	void dispGraph(ALGraph *);
	//创建图
	createGraphInFile(graph);
	//打印图
	dispGraph(graph);
	//广度优先遍历
	//BFSBegin(graph);
	//深度优先遍历
	DFSBegin(graph);
	return 0;
}

普里姆算法

/*
	prim算法在用邻接矩阵方式存储的图中的实现
*/
#define _CRT_SECURE_NO_WARNINGS
#define MAXSIZE 100 //数组最大值
#include <stdio.h>
#include <stdlib.h>
typedef struct Graph {
	char Vertex[MAXSIZE];
	int Edge[MAXSIZE][MAXSIZE];
	int numV, numE;//顶点、边数量
}adjMatrix;

int getSum(adjMatrix *G, int *prims) {//获得最小生成树的权值
	int sum = 0;
	for (int i = 1; i < G->numV; i++) {
		int min = 32767;
		for (int j = 0; j < i; j++) {
			if (G->Edge[prims[j]][prims[i]] < min) {
				min = G->Edge[prims[j]][prims[i]];//疯了,把prims[j]写成了j,害我调试了好久!!!
			}
		}
		sum += min;
	}
	return sum;
}
void prim(adjMatrix *G, int start) {
	int prims[MAXSIZE];//存储最小生成树结果数组
	int lowCost[MAXSIZE];//当前已加入最小生成树的邻接顶点的边的权值
	int min, k, index = 0;
	lowCost[start] = 0;//自己到自己的距离为0
	prims[index++] = start;
	for (int i = 0; i < G->numV; i++) {
		lowCost[i] = G->Edge[start][i];//把当前传入顶点的所有连接顶点的边的权值存入
	}
	for (int i = 0; i < G->numV; i++) {//进行遍历,遍历一次加入一个顶点
		if (start == i)
			continue;
		min = 32767;
		for (int j = 0; j < G->numV; j++) {
			if (lowCost[j] != 0 && lowCost[j] < min) {//如果当前顶点未曾加入最小树中且小于目前最小值,更新
				min = lowCost[j];
				k = j;//记录位置
			}

		}
		//已找到最小值,更新prims数组
		prims[index++] = k;
		lowCost[k] = 0;//将第k个顶点置为已访问,即代表它已加入最小生成树
		//如有顶点未处理,则看情况需更新lowCost数组
		for (int j = 0; j < G->numV; j++) {
			if (lowCost[j] && G->Edge[k][j] < lowCost[j]) {
				lowCost[j] = G->Edge[k][j];
				/*
					对于这里的理解,为什么要替换?然后为什么可以这样替换?
					首先回答第一个:因为普里姆算法是每次根据我们加入的点去寻找目前可纳入的最小边,
									所以我们没加入一个顶点都要进行判断,加入的顶点是否让某些顶点的
									可达距离变短
					第二个问题:    我们每次确定一个顶点,也就意味着一条边也确定了下来,所以此时新加入顶点
									到其余顶点的距离若小于之前的距离,则需要进行更换
									比如这里的 1 2 3,当1 3 确定,1 3 边的权值为1,我们的目标是让最后的权值
									最小,我们知道之前1到2权值为6,总权值就为1 + 6 = 7,而此时3 到 2仅为5 
									小于 6,所以要进行更新替换。
				*/
			}
		}

	}
	printf("%d ", getSum(G, prims));
	for (int i = 0; i < G->numV; i++) {
		printf("%c ", G->Vertex[prims[i]]);
	}
}

int main() {
	void createGraphFromFile(adjMatrix *);
	void dispGraph(adjMatrix *G);
	adjMatrix *G = (adjMatrix *)malloc(sizeof(adjMatrix));
	createGraphFromFile(G);
	dispGraph(G);
	prim(G, 0);
	return 0;
}

kruskal算法

/*
	kruskal 算法:每次选择最短的一条边加入集合,直至所有顶点被包含,而且会用到并查集
*/
#include<stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
#define TYPE int
typedef struct EdgeNode {//边表结点
	int index;//该边所指向的顶点的位置
	int weight;//权值
	EdgeNode *next;//下一个邻接边
}EdgeNode;

typedef struct VertexNode {//顶点表节点
	char info;//顶点信息
	EdgeNode *firstEdge;//指向第一条依附该顶点的边的指针
}VertexNode, Adjlist[MAXSIZE];

typedef struct {
	Adjlist adjlist;//顶点数组
	int numE, numV;//边数、顶点数
}ALGraph;
struct Tree {
	char data;
	struct Tree *lchild, *rchild;
};
void outPut(ALGraph *G, int **weights) {//输出最小生成树
	for (int i = 0; i < G->numV; i++) {
		for (int j = i; j < G->numV; j++) {
			if (weights[i][j] != 0) {
				printf("%c->%c(%d)\n", G->adjlist[i].info, G->adjlist[j].info, weights[i][j]);
			}
		}
	}
}
int findAnster(int *fa, int i) {
	if (fa[i] == i)return i;//找到返回
	else {
		fa[i] = findAnster(fa, fa[i]);//进行路径压缩,即将i处
		return fa[i];//未找到继续
	}
}
void unionn(int *fa, int i, int j) {
	int i_a = findAnster(fa, i);
	int j_a = findAnster(fa, j);
	fa[i_a] = j_a;//i的祖先指向j的祖先
}
void kruskal(ALGraph *G) {
	int **weights = (int **)malloc(sizeof(int *)*G->numV);//两点间的权值数据
	int *fa = (int *)malloc(sizeof(int)*G->numV);//并查集数组
	for (int i = 0; i < G->numV; i++) {
		fa[i] = i;//最开始将每个节点的祖先设置为自己
	}
	for (int i = 0; i < G->numV; i++) {
		weights[i] = (int *)malloc(sizeof(int *)*G->numV);
	}
	for (int i = 0; i < G->numV; i++) {
		for (int j = 0; j < G->numV; j++) {
			weights[i][j] = 0;//初始化该二位数组
		}
	}
	int edges = 0;
	while (edges < G->numV - 1) {
		int weight = 32767;
		int start, end;
		for (int i = 0; i < G->numV; i++) {//遍历每一个顶点的所有边
			for (EdgeNode *p = G->adjlist[i].firstEdge; p; p = p->next) {
				//寻找最短边
				if (p->weight < weight && findAnster(fa, i) != findAnster(fa, p->index)) {
					weight = p->weight;
					start = i;
					end = p->index;
				}
			}
		}
		unionn(fa, start, end);
		weights[start][end] = weight;
		weights[end][start] = weight;
		edges++;
	}
	outPut(G, weights);

}
int main() {
	ALGraph *G = (ALGraph *)malloc(sizeof(ALGraph *));
	void createGraphInFile(ALGraph *);
	void dispGraph(ALGraph *);
	createGraphInFile(G);//创建图
	dispGraph(G);
	kruskal(G);
	return 0;
}

Dijkstra算法

/*
	Dijkstra 算法:
				其实该算法和prim算法相似,不同的仅仅是更新那一块
				我们这里仍然需要用到一个标记数组flag,用于记录顶点是否已被访问,一个路径数组dist,用于记录
				目前到达各顶点的距离,此外我们还需要一个前置顶点数组prevs,用于存储路径

*/
#define MAXSIZE 100 //数组最大值
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef struct Graph {
	int Vertex[MAXSIZE];
	int Edge[MAXSIZE][MAXSIZE];
	int numV, numE;//顶点、边数量
}adjMatrix;

void dijkstra(adjMatrix *G, int start) {
	int flag[MAXSIZE];//标记数组
	//int preV=0;//设置preV最开始为0
	int dist[MAXSIZE];//可到达顶点的距离数据
	int prevs[MAXSIZE];//存储每个顶点的前驱,也就是存储路径
	int k = start;
	for (int i = 0; i < G->numV; i++) {
		dist[i] = G->Edge[start][i];//初始化start到各顶点的距离
		prevs[i] = 0;//初始化
		flag[i] = 0;
	}
	flag[0] = 1;//传入的顶点设为已访问
	for (int i = 0; i < G->numV; i++) {//共进行G->numV次循环
		if (start == i)//是本身,不做操作
			continue;
		int min = 32767;
		//找目前能到达的权值最小顶点
		for (int j = 0; j < G->numV; j++) {
			if (!flag[j] && dist[j] < min) {//dist不为0代表未访问过
				min = dist[j];
				k = j;
			}
		}
		flag[k] = 1;
		//当我们加入新顶点时,我们要判断加入新顶点后是否路径会缩短,如果有这种情况,就要更新dist
		for (int m = 0; m < G->numV; m++) {
			if (!flag[m] && dist[m] > G->Edge[k][m] + dist[k]) {//当前 记录的从源点到k的距离 大于 加入k后的距离,进行更新!!
				dist[m] = G->Edge[k][m] + dist[k];
				prevs[m] = k;//一旦发生更换将m处的值设为k,代表由k处的顶点指向m处的顶点目前最近,即k是m的前驱
			}
		}
	}
	for (int i = 0; i < G->numV; i++) {
		i == start ? printf("%d ", 0) : printf("%d ", G->Vertex[prevs[i]]-48);
	}
	printf("\n");
	for (int i = 0; i < G->numV; i++) {
		 printf("%d ", dist[i]);
	}
}
int main() {
	void createGraphFromFile(adjMatrix *);
	void dispGraph(adjMatrix *G);
	adjMatrix *G = (adjMatrix *)malloc(sizeof(adjMatrix));
	createGraphFromFile(G);
	dispGraph(G);
	dijkstra(G, 0);
	return 0;
}

floyd算法

/*
	floyd算法:
			我们会设置一个dist数组和path数组,dist数组用于描述i到j的权值,
			path数组用于描述i到j经过那个顶点
*/
#define MAXSIZE 100
#include <stdio.h>
#include <stdlib.h>
typedef struct Graph {
	int Vertex[MAXSIZE];
	int Edge[MAXSIZE][MAXSIZE];
	int numV, numE;//顶点、边数量
}adjMatrix;
void floyd(adjMatrix *G,int path[][MAXSIZE]) {
	int i, j, k;
	int dist[MAXSIZE][MAXSIZE];
	for (int m = 0; m < G->numV; m++) {
		for (int n = 0; n < G->numV; n++) {
			dist[m][n] = G->Edge[m][n];//初始化顶点间距离
			path[m][n] = -1;//初始化路径
		}
	}
	for (k = 0; k < G->numV; k++) {//依次加入所有的顶点
		for (i = 0; i < G->numV; i++) {
			for (j = 0; j < G->numV; j++) {
				if (dist[i][j] > G->Edge[i][k] + G->Edge[k][j]) {//加入k后有更短的,更新
					dist[i][j] = G->Edge[i][k] + G->Edge[k][j];//更改dist
					path[i][j] = k;//path更改
				}
			}
		}
	}
	for (int i = 0; i < G->numV; i++)
	{
		for (int j = 0; j < G->numV; j++)
			printf("%2d  ", dist[i][j]);
		printf("\n");
	}
}
void printPath(int path[][MAXSIZE],int vi,int vj) {
	if (path[vi][vj]==-1) {//直接输出
		printf("%d ",vj+1);
	}
	else {
		int mid = path[vi][vj];
		printPath(path, vi, mid);
		printPath(path,mid,vj);
	}
}
int main() {
	void createGraphFromFile(adjMatrix *);
	void dispGraph(adjMatrix *);
	adjMatrix *G = (adjMatrix *)malloc(sizeof(adjMatrix));
	createGraphFromFile(G);
	dispGraph(G);
	int path[MAXSIZE][MAXSIZE];
	floyd(G,path);
	printPath(path,1,3);
	return 0;
}

邻接表转化成邻接矩阵

/*
	写出从图的邻接表表示转换成邻接矩阵表示的算法
	分析:
		我们之前也写过邻接矩阵的存储方式,在这里我们就只需要去遍历邻接表中的每一个顶点,
		并根据边的信息,将数据填入邻接矩阵中即可
*/
//分别写出邻接表和邻接矩阵两种方式的结构体
//结构体的构建一定要和创建邻接表、创建邻接矩阵里的一模一样,不然会有问题,把我整惨了
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
typedef struct Graph {
	char Vertex[MAXSIZE];//顶点数组
	int Edge[MAXSIZE][MAXSIZE];
	int numV, numE;//顶点、边数量
}adjMatrix;//邻接矩阵


//邻接表存储的图
typedef struct EdgeNode {//边表结点
	int index;//该边所指向的顶点的位置,在顶点数组里面的位置信息
	int weight;//权值
	EdgeNode *next;//下一个邻接边
}EdgeNode;

typedef struct VertexNode {//顶点表节点
	char info;//顶点信息
	EdgeNode *firstEdge;//指向第一条依附该顶点的边的指针
}VertexNode, Adjlist[MAXSIZE];

typedef struct {
	Adjlist adjlist;//顶点数组
	int numE, numV;//边数、顶点数
}ALGraph;
void edgeIput(ALGraph *alG, adjMatrix *amG, int index, int *visited) {
	visited[index] = 1;//标记为已访问
	for (EdgeNode *p = alG->adjlist[index].firstEdge; p; p = p->next) {
		amG->Edge[index][p->index] = p->weight;//边信息存入邻接矩阵
		if (!visited[p->index])
			edgeIput(alG, amG, p->index, visited);
	}
}
void transform(ALGraph *alG, adjMatrix *amG) {//开始进行转换
	
	amG->numE = alG->numE;
	amG->numV = alG->numV;
	for (int v = 0; v < amG->numV; v++) {
		amG->Vertex[v] = alG->adjlist[v].info;//顶点信息存入邻接矩阵
	}
	//初始化图
	for (int i = 0; i < amG->numV; i++) {
		for (int j = 0; j < amG->numV; j++) {
			i == j ? amG->Edge[i][j] = 0 : amG->Edge[i][j] = 32767;
		}
	}
	for (int v = 0; v < amG->numV; v++) {
		//存入边信息
		EdgeNode *p = alG->adjlist[v].firstEdge;
		while (p) {
			amG->Edge[v][p->index] = p->weight;
			p = p->next;
		}
	}
}
int main() {
	ALGraph alG;
	adjMatrix amG;
	void createGraphInFile(ALGraph*);//声明方法
	void dispGraph(adjMatrix *);
	createGraphInFile(&alG);//创建图G
	transform(&alG, &amG);
	dispGraph(&amG);
	return 0;
}

判断一个无向图是否是一棵树

/*
	设计一个算法,判断一个无向图是否是一棵树
	分析:
		我们知道,是树的前提,首先该无向图必须是连通的,且边数不能过多,只能是n-1条边。
		那么我们可以通过深度优先遍历来统计该无向图的边数与顶点数,符合条件则为一棵树
*/
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
#define TYPE int
typedef struct EdgeNode {//边表结点
	int index;//该边所指向的顶点的位置
	int weight;//权值
	EdgeNode *next;//下一个邻接边
}EdgeNode;

typedef struct VertexNode {//顶点表节点
	char info;//顶点信息
	EdgeNode *firstEdge;//指向第一条依附该顶点的边的指针
}VertexNode, Adjlist[MAXSIZE];

typedef struct {
	Adjlist adjlist;//顶点数组
	int numE, numV;//边数、顶点数
}ALGraph;
void DFS(ALGraph *G, int *visited, int &numV, int &numE, int index) {
	visited[index] = 1;//标记为已访问
	numV++;//顶点数加一
	for (EdgeNode* p = G->adjlist[index].firstEdge; p; p = p->next) {
		if (!visited[p->index]) {
			numE++;
			DFS(G, visited, numV, numE, p->index);
		}
	}
}
bool isTree(ALGraph *G) {
	int numV = 0, numE = 0;//统计边和顶点
	int *visited = (int*)malloc(sizeof(int)*G->numV);
	for (int i = 0; i < G->numV; i++) {
		*(visited + i) = 0;//标记数组初始化
	}
	DFS(G, visited, numV, numE, 0);//只进行一次遍历
	if (numV == G->numV&&numE == (G->numV - 1)) {
		return true;
	}
	else {
		return false;
	}
}
int main() {
	ALGraph *G = (ALGraph *)malloc(sizeof(ALGraph *));
	bool Tree;
	void createGraphInFile(ALGraph *);
	createGraphInFile(G);//创建图
	void dispGraph(ALGraph *G);
	dispGraph(G);
	Tree = isTree(G);
	if (Tree) {
		printf("这是一棵树");
	}
	else {
		printf("这不是一棵树");

	}
	return 0;
}

深度优先遍历的非递归实现

/*
	写出深度优先遍历的非递归算法(图用邻接表给出)
	分析:
		之前我们也做过将一个递归算法利用栈用非递归的方式算出来,这里同理,我们利用栈来进行深度优先遍历
		算法过程大致如下:从第一个顶点开始进行深度优先遍历,同时置访问位为true,然后将该顶点入栈,
		采用while循环,依次取出栈顶元素,并判断该顶点元素是否已访问,未访问则访问,
		已访问则查看它的firstEdge,当firstEdge也被访问了,查看next,如此循环。
*/
#include <stdio.h>
#include <stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
#define MAXSIZE 100
struct Stack {//栈结构
	int *arr;
	int len;
	int top;
};
typedef struct EdgeNode {//边表结点
	int index;//该边所指向的顶点的位置
	int weight;//权值
	EdgeNode *next;//下一个邻接边
}EdgeNode;

typedef struct VertexNode {//顶点表节点
	char info;//顶点信息
	EdgeNode *firstEdge;//指向第一条依附该顶点的边的指针
}VertexNode, Adjlist[MAXSIZE];

typedef struct {
	Adjlist adjlist;//顶点数组
	int numE, numV;//边数、顶点数
}ALGraph;
void DFSUseStack(ALGraph *G, Stack *s) {
	bool push(Stack *, int);
	bool pop(Stack *);
	int top(Stack *);
	bool empty(Stack *);
	int *visited = (int *)malloc(sizeof(int)*G->numV);//设置标记数组
	for (int i = 0; i < G->numV; i++) {
		visited[i] = 0;
	}
	for (int i = 0; i < G->numV; i++) {
		if (visited[i])
			continue;
		int v;
		printf("%c ", G->adjlist[i].info);
		visited[i] = 1;
		push(s, i);//入栈
		EdgeNode *p;
		while (!empty(s)) {//栈内不空
			v = top(s);
			pop(s);
			p = G->adjlist[v].firstEdge;
			while (p) {
				if (!visited[p->index]) {
					printf("%c ", G->adjlist[p->index].info);
					visited[p->index] = 1;
					push(s, p->index);
					p = G->adjlist[p->index].firstEdge;//顺腾摸瓜
				}
				else {
					p = p->next;//摸到底了,平级顶点继续找
				}
			}
			if (p == NULL)
				pop(s);
			//printf("%c ", G->adjlist[v].info);
			//for (p = G->adjlist[v].firstEdge; p; p = p->next) {
			//	if (!visited[p->index]) {
			//		push(s, p->index);
			//		visited[p->index] = 1;
			//		//p = G->adjlist[p->index].firstEdge;//顺腾摸瓜
			//	}
			//}
		}

	}
}
int main() {
	ALGraph G;
	void createGraphInFile(ALGraph *);
	void dispGraph(ALGraph *);
	createGraphInFile(&G);//创建图
	dispGraph(&G);
	Stack *s = (Stack *)malloc(sizeof(Stack *));
	Stack *createStack(int);
	s = createStack(G.numV);
	DFSUseStack(&G, s);
	return 0;
}

判断是否有vi到vj的路径

/*
	分别采用深度优先遍历和广度优先遍历判断是否存在由vi到vj的路径,图用邻接表存储
	分析:
		采用深度优先:我们从vi顶点开始进行深度遍历,若若存在路径则必然可以走到vj顶点处;
		采用广度优先:同样从vi顶点开始进行广度遍历,若存在则必然可以走到vj顶点处。
*/
#define _CRT_SECURE_NO_WARNINGS
#define MAXSIZE 100
#include <stdio.h>
#include <stdlib.h>
typedef struct EdgeNode {//边表结点
	int index;//该边所指向的顶点的位置
	int weight;//权值
	EdgeNode *next;//下一个邻接边
}EdgeNode;

typedef struct VertexNode {//顶点表节点
	char info;//顶点信息
	EdgeNode *firstEdge;//指向第一条依附该顶点的边的指针
}VertexNode, Adjlist[MAXSIZE];

typedef struct {
	Adjlist adjlist;//顶点数组
	int numE, numV;//边数、顶点数
}ALGraph;
//链队
struct Link {
	int node;//我们进行广度优先时会用到,将顶点序号入队
	struct Link *next;
};
struct LinkQueue {
	struct Link *front, *rear;
};

void DFS(ALGraph *G, int vi, int vj, int *visited, int &flag) {
	for (EdgeNode *p = G->adjlist[vi].firstEdge; p; p = p->next) {
		if (!visited[p->index]) {
			visited[p->index] = 1;
			if (p->index == vj) {//此时找到终止顶点
				flag = 1;
			}
			DFS(G, p->index, vj, visited, flag);
		}
	}

}
bool judgeRouteInDFS(ALGraph *G, int vi, int vj) {//传入图G,路线端点vi vj
	int *visited = (int *)malloc(sizeof(int)*G->numV);
	int flag = 0;//进入递归,路径存在标志
	for (int i = 0; i < G->numV; i++) {
		visited[i] = 0;//初始化
	}
	if (!visited[vi]) {
		visited[vi] = 1;
		DFS(G, vi, vj, visited, flag);
	}
	if (flag) {
		return 1;

	}
	else {
		return 0;
	}

}

bool judgeRouteInBFS(ALGraph *G, int vi, int vj) {
	int *visited = (int *)malloc(sizeof(int)*G->numV);
	int flag = 0;//进入递归,路径存在标志
	int index;//进行判断用
	for (int i = 0; i < G->numV; i++) {
		visited[i] = 0;//初始化
	}
	bool isEmpty(LinkQueue *lq);
	bool enQueue(LinkQueue *, int);
	bool deQueue(LinkQueue *, int*);
	LinkQueue *create();//声明创建队列的方法。广度优先遍历需要用到队列
	LinkQueue *lq;
	lq = create();
	if (!visited[vi]) {
		visited[vi] = 1;
		enQueue(lq, vi);//入队
	}
	while (!isEmpty(lq)) {//当队列不空,取出队首元素进行判断
		deQueue(lq, &index);
		if (!visited[index]) {//若未曾访问过,进行判断
			visited[index] = 1;
			if (vj == index) {
				flag = 1;
			}
		}
		for (EdgeNode *p = G->adjlist[index].firstEdge; p; p = p->next) {
			if (!visited[p->index]) {
				enQueue(lq, p->index);//把所有的未访问过得邻接顶点入队

			}
		}
	}
	return flag;
}
int main() {
	int haveRoute;
	void createGraphInFile(ALGraph *);
	ALGraph *G = (ALGraph *)malloc(sizeof(ALGraph *));
	createGraphInFile(G);//创建图
	int vi, vj;
	printf("请输入vi,vj\n");
	printf("vi= ");
	scanf("%d", &vi);
	printf("vj= ");
	scanf("%d", &vj);
	while (vi > G->numV || vj > G->numV) {
		printf("输入有误,不存在该顶点,请重新输入!");
		printf("vi= ");
		scanf("%d", &vi);
		printf("vj= ");
		scanf("%d", &vj);
	}
	//haveRoute = judgeRouteInBFS(G, vi - 1, vj - 1);
	haveRoute = judgeRouteInDFS(G, vi - 1, vj - 1);
	if (haveRoute) {
		printf("顶点%d到顶点%d存在路径", vi, vj);
	}
	else {
		printf("%d到%d不存在路径", vi, vj);
	}
	return 0;
}

寻找vi到vj的所有简单路径

/*
	输出顶点vi到顶点vj的所有简单路径,图用邻接表存储
	分析:
		这里明说了输出路径,所以肯定存在简单路径。为了输出路径,我们还需要额外添加一个path数组,
		用来存储vi到vj的路径数据,方便我们之后打印输出。我们这里仍然采用深度优先遍历,广度优先遍历不适合。
*/
#define _CRT_SECURE_NO_WARNINGS
#define MAXSIZE 100
#include <stdio.h>
#include <stdlib.h>
typedef struct EdgeNode {//边表结点
	int index;//该边所指向的顶点的位置
	int weight;//权值
	EdgeNode *next;//下一个邻接边
}EdgeNode;

typedef struct VertexNode {//顶点表节点
	char info;//顶点信息
	EdgeNode *firstEdge;//指向第一条依附该顶点的边的指针
}VertexNode, Adjlist[MAXSIZE];

typedef struct {
	Adjlist adjlist;//顶点数组
	int numE, numV;//边数、顶点数
}ALGraph;

void print(ALGraph *G, int *path, int vi,int d) {
	for (int i = 0; i <= d; i++)
		printf("%c ", G->adjlist[path[i]].info);
	printf("\n");
}
void findRoute(ALGraph *G, int vi, int vj, int *path, int *visited, int d) {
	EdgeNode *p;
	d++;
	path[d] = vi;
	visited[vi] = 1;
	if (vi == vj) {
		print(G, path, vi,d);
	}
	for (p = G->adjlist[vi].firstEdge; p;p=p->next) {
		if (!visited[p->index]) {
			findRoute(G,p->index,vj,path,visited,d);
		}
	}
	visited[vi] = 0;//重新置位可访问
}
int main() {
	void createGraphInFile(ALGraph *G);
	ALGraph *G = (ALGraph *)malloc(sizeof(ALGraph *));
	void dispGraph(ALGraph *);
	createGraphInFile(G);//创建图
	int vi, vj;
	printf("请输入vi,vj\n");
	printf("vi= ");
	scanf("%d", &vi);
	printf("vj= ");
	scanf("%d", &vj);
	while (vi > G->numV || vj > G->numV) {
		printf("输入有误,不存在该顶点,请重新输入!");
		printf("vi= ");
		scanf("%d", &vi);
		printf("vj= ");
		scanf("%d", &vj);
	}
	int *visited = (int *)malloc(sizeof(int)*G->numV);
	int *path = (int *)malloc(sizeof(int)*G->numV);
	for (int i = 0; i < G->numV; i++) {
		visited[i] = 0;//初始化
		path[i] = -1;//初始化
	}
	dispGraph(G);
	findRoute(G, vi - 1, vj - 1, path, visited, -1);
	return 0;
}

拓扑排序

/*
	拓扑排序:
			每次将入度为0的顶点输出,输出的同时将出边删除,直至所有顶点输出
*/
#define _CRT_SECURE_NO_WARNINGS
#define MAXSIZE 100
typedef struct EdgeNode {//边表结点
	int index;//该边所指向的顶点的位置
	int weight;//权值
	EdgeNode *next;//下一个邻接边
}EdgeNode;

typedef struct VertexNode {//顶点表节点
	char info;//顶点信息
	EdgeNode *firstEdge;//指向第一条依附该顶点的边的指针
}VertexNode, Adjlist[MAXSIZE];

typedef struct {
	Adjlist adjlist;//顶点数组
	int numE, numV;//边数、顶点数
}ALGraph;
struct Stack
{
	int* arr;	//内存首地址
	int  len;	//栈的容量
	int top; 	//栈的下标
};
#include <stdio.h>
#include <stdlib.h>

void inDegree(ALGraph *G,int *indegree) {//统计每个顶点的入度,用数组保存
	int k;
	for (int i = 0; i < G->numV;i++) {
		k = 0;
		for (int j = 0; j < G->numV;j++) {
			/*if (i==j) {
				continue;
			}*/
			for (EdgeNode *p = G->adjlist[j].firstEdge; p;p=p->next) {
				if (p->index == i)
					indegree[i] = ++k;
			}
		}

	}
}
void topoSort(ALGraph *G) {
	Stack *s = (struct Stack*)malloc(sizeof(struct Stack));
	Stack *createStack(int );
	bool push(Stack *, int data);
	bool empty(Stack *);
	int top(Stack *);
	bool pop(Stack *);
	int *indegree = (int *)malloc(sizeof(int )*G->numV);
	for (int i = 0; i < G->numV;i++) {
		indegree[i] = 0;
	}
	int index;
	inDegree(G,indegree);
	s=createStack(G->numV);
	for (int i = 0; i < G->numV;i++) {//将入度为0的顶点入栈
		if (indegree[i]==0) {
			push(s,i);
		}
	}
	while (!empty(s)) {//栈不空,输出栈顶
		index = top(s);//查看栈顶元素
		printf("%c ", G->adjlist[index].info);//打印
		pop(s);//出栈
		for (EdgeNode *p = G->adjlist[index].firstEdge; p; p = p->next) {//将当前出栈的顶点所指向的顶点的入度均-1
			indegree[p->index]--;
			if (!indegree[p->index]) {//出现了入度为0,入栈
				push(s,p->index);
			}
		}

	}
}
int main() {
	ALGraph *G = (ALGraph *)malloc(sizeof(ALGraph *));
	void createGraphInFile(ALGraph *);
	void dispGraph(ALGraph *);
	createGraphInFile(G);//创建图
	dispGraph(G);
	topoSort(G);
	return 0;
}
include <stdio.h>
#include <stdlib.h>

void inDegree(ALGraph *G,int *indegree) {//统计每个顶点的入度,用数组保存
	int k;
	for (int i = 0; i < G->numV;i++) {
		k = 0;
		for (int j = 0; j < G->numV;j++) {
			/*if (i==j) {
				continue;
			}*/
			for (EdgeNode *p = G->adjlist[j].firstEdge; p;p=p->next) {
				if (p->index == i)
					indegree[i] = ++k;
			}
		}

	}
}
void topoSort(ALGraph *G) {
	Stack *s = (struct Stack*)malloc(sizeof(struct Stack));
	Stack *createStack(int );
	bool push(Stack *, int data);
	bool empty(Stack *);
	int top(Stack *);
	bool pop(Stack *);
	int *indegree = (int *)malloc(sizeof(int )*G->numV);
	for (int i = 0; i < G->numV;i++) {
		indegree[i] = 0;
	}
	int index;
	inDegree(G,indegree);
	s=createStack(G->numV);
	for (int i = 0; i < G->numV;i++) {//将入度为0的顶点入栈
		if (indegree[i]==0) {
			push(s,i);
		}
	}
	while (!empty(s)) {//栈不空,输出栈顶
		index = top(s);//查看栈顶元素
		printf("%c ", G->adjlist[index].info);//打印
		pop(s);//出栈
		for (EdgeNode *p = G->adjlist[index].firstEdge; p; p = p->next) {//将当前出栈的顶点所指向的顶点的入度均-1
			indegree[p->index]--;
			if (!indegree[p->index]) {//出现了入度为0,入栈
				push(s,p->index);
			}
		}

	}
}
int main() {
	ALGraph *G = (ALGraph *)malloc(sizeof(ALGraph *));
	void createGraphInFile(ALGraph *);
	void dispGraph(ALGraph *);
	createGraphInFile(G);//创建图
	dispGraph(G);
	topoSort(G);
	return 0;
}
  • 4
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落难Coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值