数据结构--图

1.图的领接矩阵和领接表:

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

#define INF 32767				//定义∞
#define	MAXV 100				//最大顶点个数
typedef char InfoType;


typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型

typedef struct
{
	int edges[MAXV][MAXV];		//邻接矩阵数组
	int n, e;					//顶点数,边数
	VertexType vexs[MAXV];		//存放顶点信息
} MatGraph;						//完整的图邻接矩阵类型

typedef struct ANode
{
	int adjvex;					//该边的邻接点编号
	struct ANode* nextarc;		//指向下一条边的指针
	int weight;					//该边的相关信息,如权值(用整型表示)
} ArcNode;						//边结点类型

typedef struct Vnode
{
	InfoType info;				//顶点其他信息
	int count;					//存放顶点入度,仅仅用于拓扑排序
	ArcNode* firstarc;			//指向第一条边
} VNode;

typedef struct
{
	VNode adjlist[MAXV];		//邻接表头结点数组
	int n, e;					//图中顶点数n和边数e
} AdjGraph;						//完整的图邻接表类型

//----邻接矩阵的基本运算算法----------------------------------
void CreateMat(MatGraph* g, int A[MAXV][MAXV], int n, int e) //创建图的邻接矩阵 ,矩阵都是 N x N
{
	int i, j;
	g->n = n;
	g->e = e;
	for (i = 0; i < g->n; i++)
		for (j = 0; j < g->n; j++)
			g->edges[i][j] = A[i][j];
}

void DispMat(MatGraph* g)	//输出邻接矩阵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("%4d", g->edges[i][j]);
			else
				printf("%4s", "∞");
		printf("\n");
	}
}

//邻接表的基本运算算法
void CreateAdj(AdjGraph** G, int A[MAXV][MAXV], int n, int e) {
	int i, j;
	ArcNode* p;
	*G = (AdjGraph*)malloc(sizeof(AdjGraph));

	if (!*G) {
		printf("Memory allocation failed.\n");
		return ;
	}

	for (i = 0; i < n; i++) {
		(*G)->adjlist[i].firstarc = NULL;
	}

	int actualEdges = 0; // 实际边数计数器

	for (i = 0; i < n; i++) {
		for (j = n - 1; j >= 0; j--) {
			if (A[i][j] != 0 && A[i][j] != INF) {
				p = (ArcNode*)malloc(sizeof(ArcNode));

				if (!p) {
					printf("内存分配失败\n");
					return;
				}

				p->adjvex = j;
				p->weight = A[i][j];
				p->nextarc = (*G)->adjlist[i].firstarc;
				(*G)->adjlist[i].firstarc = p;

				actualEdges++; // 增加实际边数
			}
		}
	}

	(*G)->n = n;
	(*G)->e = actualEdges; // 设置正确的边数
}

void DispAdj(AdjGraph* G) {
	int i;
	ArcNode* p;

	for (i = 0; i < G->n; i++) {
		p = G->adjlist[i].firstarc;
		printf("%3d: ", i);
		while (p != NULL) {
			printf("%3d[%d]→", p->adjvex, p->weight);
			p = p->nextarc;
		}
		printf("∧\n");
	}
}

void DestroyAdj(AdjGraph** G)		//销毁图的邻接表
{
	int i;
	ArcNode* pre, * p;

	for (i = 0; i < (*G)->n; i++)			//扫描所有的单链表
	{
		pre = (*G)->adjlist[i].firstarc;	//p指向第i个单链表的首结点
		if (pre != NULL)
		{
			p = pre->nextarc;
			while (p != NULL)			//释放第i个单链表的所有边结点
			{
				free(pre);
				pre = p; p = p->nextarc;
			}
			free(pre);
		}
	}

	free(*G);						//释放头结点数组
}

int main()
{
	MatGraph* g = (MatGraph*)malloc(sizeof(MatGraph));
	AdjGraph* G = (AdjGraph*)malloc(sizeof(AdjGraph));

	int A[MAXV][MAXV] = {
		{0,5,INF,7,INF,INF},{INF,0,4,INF,INF,INF},
		{8,INF,0,INF,INF,9},{INF,INF,5,0,INF,6},
		{INF,INF,INF,5,0,INF},{3,INF,INF,INF,1,0}
	};

	int n = 6, e = 10;

	CreateMat(g, A, n, e);
	printf("图G的领接矩阵\n");
	DispMat(g);

	CreateAdj(&G, A, n, e);
	printf("图G的领接表\n");
	DispAdj(G);

	DestroyAdj(&G);

	return 0;
}

2.图的深度优先和广度优先:

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

#define INF 32767				//定义∞
#define	MAXV 100				//最大顶点个数
#define MaxSize 100

typedef char InfoType;


typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型

typedef struct
{
	int edges[MAXV][MAXV];		//邻接矩阵数组
	int n, e;					//顶点数,边数
	VertexType vexs[MAXV];		//存放顶点信息
} MatGraph;						//完整的图邻接矩阵类型

typedef struct ANode
{
	int adjvex;					//该边的邻接点编号
	struct ANode* nextarc;		//指向下一条边的指针
	int weight;					//该边的相关信息,如权值(用整型表示)
} ArcNode;						//边结点类型

typedef struct Vnode
{
	InfoType info;				//顶点其他信息
	int count;					//存放顶点入度,仅仅用于拓扑排序
	ArcNode* firstarc;			//指向第一条边
} VNode;

typedef struct
{
	VNode adjlist[MAXV];		//邻接表头结点数组
	int n, e;					//图中顶点数n和边数e
} AdjGraph;						//完整的图邻接表类型

typedef int ElemType;
typedef struct
{
	ElemType data[MaxSize];
	int front, rear;		//队首和队尾指针
} SqQueue;

void InitQueue(SqQueue** q)
{
	(*q) = (SqQueue*)malloc(sizeof(SqQueue));
	(*q)->front = (*q)->rear = 0;
}

void DestroyQueue(SqQueue** q)
{
	free(*q);
}

bool QueueEmpty(SqQueue* q)
{
	return(q->front == q->rear);
}

bool enQueue(SqQueue** q, ElemType e)
{
	if (((*q)->rear + 1) % MaxSize == (*q)->front)	//队满上溢出
		return false;
	(*q)->rear = ((*q)->rear + 1) % MaxSize;
	(*q)->data[(*q)->rear] = e;
	return true;
}

bool deQueue(SqQueue** q, ElemType* e)
{
	if ((*q)->front == (*q)->rear)				//队空下溢出
		return false;
	(*q)->front = ((*q)->front + 1) % MaxSize;
	*e = (*q)->data[(*q)->front];
	return true;
}


//----邻接矩阵的基本运算算法----------------------------------
void CreateMat(MatGraph* g, int A[MAXV][MAXV], int n, int e) //创建图的邻接矩阵
{
	int i, j;
	(*g).n = n; 
	(*g).e = e;
	for (i = 0; i < (*g).n; i++)
		for (j = 0; j < (*g).n; j++)
			(*g).edges[i][j] = A[i][j];
}

void DispMat(MatGraph *g)	//输出邻接矩阵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("%4d", (*g).edges[i][j]);
			else
				printf("%4s", "∞");
		printf("\n");
	}
}

//邻接表的基本运算算法
void CreateAdj(AdjGraph** G, int A[MAXV][MAXV], int n, int e) {
	int i, j;
	ArcNode* p;
	*G = (AdjGraph*)malloc(sizeof(AdjGraph));
	if (!*G) {
		printf("Memory allocation failed.\n");
		return;
	}
	for (i = 0; i < n; i++) {
		(*G)->adjlist[i].firstarc = NULL;
	}

	int actualEdges = 0; // 实际边数计数器
	for (i = 0; i < n; i++) {
		for (j = n - 1; j >= 0; j--) {
			if (A[i][j] != 0 && A[i][j] != INF) {
				p = (ArcNode*)malloc(sizeof(ArcNode));
				if (!p) {
					printf("Memory allocation failed.\n");
					return;
				}
				p->adjvex = j;
				p->weight = A[i][j];
				p->nextarc = (*G)->adjlist[i].firstarc;
				(*G)->adjlist[i].firstarc = p;
				actualEdges++; // 增加实际边数
			}
		}
	}

	(*G)->n = n;
	(*G)->e = actualEdges; // 设置正确的边数
}

void DispAdj(AdjGraph* G) {
	int i;
	ArcNode* p;
	for (i = 0; i < G->n; i++) {
		p = G->adjlist[i].firstarc;
		printf("%3d: ", i);
		while (p != NULL) {
			printf("%3d[%d]→", p->adjvex, p->weight);
			p = p->nextarc;
		}
		printf("∧\n");
	}
}

void DestroyAdj(AdjGraph** G)		//销毁图的邻接表
{
	int i;
	ArcNode* pre, * p;
	for (i = 0; i < (*G)->n; i++)			//扫描所有的单链表
	{
		pre = (*G)->adjlist[i].firstarc;	//p指向第i个单链表的首结点
		if (pre != NULL)
		{
			p = pre->nextarc;
			while (p != NULL)			//释放第i个单链表的所有边结点
			{
				free(pre);
				pre = p; p = p->nextarc;
			}
			free(pre);
		}
	}
	free(*G);						//释放头结点数组
}

void BFS(AdjGraph* G, int v)
{
	int w, i;
	ArcNode* p;
	SqQueue* qu;							//定义环形队列指针
	InitQueue(&qu);							//初始化队列
	int visited[MAXV];            			//定义顶点访问标志数组
	for (i = 0; i < G->n; i++) visited[i] = 0;		//访问标志数组初始化
	printf("%d ", v); 						//输出被访问顶点的编号
	visited[v] = 1;              				//置已访问标记
	enQueue(&qu, v);
	while (!QueueEmpty(qu))       			//队不空循环
	{
		deQueue(&qu, &w);						//出队一个顶点w
		p = G->adjlist[w].firstarc; 			//指向w的第一个邻接点
		while (p != NULL)						//查找w的所有邻接点
		{
			if (visited[p->adjvex] == 0) 		//若当前邻接点未被访问
			{
				printf("%d ", p->adjvex);  	//访问该邻接点
				visited[p->adjvex] = 1;		//置已访问标记
				enQueue(&qu, p->adjvex);		//该顶点进队
			}
			p = p->nextarc;              		//找下一个邻接点
		}
	}
	printf("\n");
}

int visited[MAXV] = { 0 };
void DFS(AdjGraph* G, int v)
{
	ArcNode* p;
	visited[v] = 1;                   //置已访问标记
	printf("%d  ", v); 				//输出被访问顶点的编号
	p = G->adjlist[v].firstarc;      	//p指向顶点v的第一条弧的弧头结点
	while (p != NULL)
	{
		if (visited[p->adjvex] == 0)	//若p->adjvex顶点未访问,递归访问它
			DFS(G, p->adjvex);
		p = p->nextarc;              	//p指向顶点v的下一条弧的弧头结点
	}
}

int main()
{
	MatGraph* g = (MatGraph*)malloc(sizeof(MatGraph));
	AdjGraph* G = (AdjGraph*)malloc(sizeof(AdjGraph));

	int A[MAXV][MAXV] = {
		{0,5,INF,7,INF,INF},{INF,0,4,INF,INF,INF},
		{8,INF,0,INF,INF,9},{INF,INF,5,0,INF,6},
		{INF,INF,INF,5,0,INF},{3,INF,INF,INF,1,0}
	};

	int n = 6, e = 10;

	CreateMat(g, A, n, e);
	printf("图G的领接矩阵\n");
	DispMat(g);

	CreateAdj(&G, A, n, e);
	printf("图G的领接表\n");
	DispAdj(G);
	printf("\n");

	printf("广度优先序列:"); 
	BFS(G, 0); 
	printf("\n");

	printf("深度优先序列(递归):"); 
	DFS(G, 0); 
	printf("\n");

	DestroyAdj(&G);

	return 0;
}

3.图的所有深度优先:

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

#define INF 32767				//定义∞
#define	MAXV 100				//最大顶点个数
typedef char InfoType;


typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型

typedef struct ANode
{
	int adjvex;					//该边的邻接点编号
	struct ANode* nextarc;		//指向下一条边的指针
	int weight;					//该边的相关信息,如权值(用整型表示)
} ArcNode;						//边结点类型

typedef struct Vnode
{
	InfoType info;				//顶点其他信息
	int count;					//存放顶点入度,仅仅用于拓扑排序
	ArcNode* firstarc;			//指向第一条边
} VNode;

typedef struct
{
	VNode adjlist[MAXV];		//邻接表头结点数组
	int n, e;					//图中顶点数n和边数e
} AdjGraph;						//完整的图邻接表类型


//邻接表的基本运算算法
void CreateAdj(AdjGraph** G, int A[MAXV][MAXV], int n, int e) {
	int i, j;
	ArcNode* p;
	*G = (AdjGraph*)malloc(sizeof(AdjGraph));
	if (!*G) {
		printf("Memory allocation failed.\n");
		return;
	}
	for (i = 0; i < n; i++) {
		(*G)->adjlist[i].firstarc = NULL;
	}

	int actualEdges = 0; // 实际边数计数器
	for (i = 0; i < n; i++) {
		for (j = n - 1; j >= 0; j--) {
			if (A[i][j] != 0 && A[i][j] != INF) {
				p = (ArcNode*)malloc(sizeof(ArcNode));
				if (!p) {
					printf("Memory allocation failed.\n");
					return;
				}
				p->adjvex = j;
				p->weight = A[i][j];
				p->nextarc = (*G)->adjlist[i].firstarc;
				(*G)->adjlist[i].firstarc = p;
				actualEdges++; // 增加实际边数
			}
		}
	}

	(*G)->n = n;
	(*G)->e = actualEdges; // 设置正确的边数
}

void DispAdj(AdjGraph* G) {
	int i;
	ArcNode* p;
	for (i = 0; i < G->n; i++) {
		p = G->adjlist[i].firstarc;
		printf("%3d: ", i);
		while (p != NULL) {
			printf("%3d[%d]→", p->adjvex, p->weight);
			p = p->nextarc;
		}
		printf("∧\n");
	}
}

void DestroyAdj(AdjGraph** G)		//销毁图的邻接表
{
	int i;
	ArcNode* pre, * p;
	for (i = 0; i < (*G)->n; i++)			//扫描所有的单链表
	{
		pre = (*G)->adjlist[i].firstarc;	//p指向第i个单链表的首结点
		if (pre != NULL)
		{
			p = pre->nextarc;
			while (p != NULL)			//释放第i个单链表的所有边结点
			{
				free(pre);
				pre = p; p = p->nextarc;
			}
			free(pre);
		}
	}
	free(*G);						//释放头结点数组
}

int visited[MAXV] = { 0 };

void DFSALL(AdjGraph* G, int v, int path[], int d)
{
	ArcNode* p;
	visited[v] = 1;
	path[d] = v;
	d++;

	if (d == G->n)
	{
		int i = 0; 
		for (i = 0; i < d; i++)
		{
			printf(" %d ", path[i]);
		}
		printf("\n");
	}

	p = G->adjlist[v].firstarc;

	while (p != NULL)
	{
		if (visited[p->adjvex] == 0)
		{
			DFSALL(G, p->adjvex, path, d);
		}
		p = p->nextarc;
	}

	visited[v] = 0;
}

int main()
{
	AdjGraph* G = (AdjGraph*)malloc(sizeof(AdjGraph));

	int A[MAXV][MAXV] = { {0,1,0,1,1},{1,0,1,1,0},
			{0,1,0,1,1},{1,1,1,0,1},{1,0,1,1,0} };
	int n = 5, e = 8;


	CreateAdj(&G, A, n, e);
	printf("图G的领接表\n");
	DispAdj(G);

	int path[MAXV], v = 1;
	printf("深度优先序列(递归):\n"); 
	DFSALL(G, v, &path,0); 
	printf("\n");

	DestroyAdj(&G);

	return 0;
}

4.判断是否存在回路:

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

#define INF 32767				//定义∞
#define	MAXV 100				//最大顶点个数
typedef char InfoType;


typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型

typedef struct ANode
{
	int adjvex;					//该边的邻接点编号
	struct ANode* nextarc;		//指向下一条边的指针
	int weight;					//该边的相关信息,如权值(用整型表示)
} ArcNode;						//边结点类型

typedef struct Vnode
{
	InfoType info;				//顶点其他信息
	int count;					//存放顶点入度,仅仅用于拓扑排序
	ArcNode* firstarc;			//指向第一条边
} VNode;

typedef struct
{
	VNode adjlist[MAXV];		//邻接表头结点数组
	int n, e;					//图中顶点数n和边数e
} AdjGraph;						//完整的图邻接表类型


//邻接表的基本运算算法
void CreateAdj(AdjGraph** G, int A[MAXV][MAXV], int n, int e) {
	int i, j;
	ArcNode* p;
	*G = (AdjGraph*)malloc(sizeof(AdjGraph));
	if (!*G) {
		printf("Memory allocation failed.\n");
		return;
	}
	for (i = 0; i < n; i++) {
		(*G)->adjlist[i].firstarc = NULL;
	}

	int actualEdges = 0; // 实际边数计数器
	for (i = 0; i < n; i++) {
		for (j = n - 1; j >= 0; j--) {
			if (A[i][j] != 0 && A[i][j] != INF) {
				p = (ArcNode*)malloc(sizeof(ArcNode));
				if (!p) {
					printf("Memory allocation failed.\n");
					return;
				}
				p->adjvex = j;
				p->weight = A[i][j];
				p->nextarc = (*G)->adjlist[i].firstarc;
				(*G)->adjlist[i].firstarc = p;
				actualEdges++; // 增加实际边数
			}
		}
	}

	(*G)->n = n;
	(*G)->e = actualEdges; // 设置正确的边数
}

void DispAdj(AdjGraph* G) {
	int i;
	ArcNode* p;
	for (i = 0; i < G->n; i++) {
		p = G->adjlist[i].firstarc;
		printf("%3d: ", i);
		while (p != NULL) {
			printf("%3d[%d]→", p->adjvex, p->weight);
			p = p->nextarc;
		}
		printf("∧\n");
	}
}

void DestroyAdj(AdjGraph** G)		//销毁图的邻接表
{
	int i;
	ArcNode* pre, * p;
	for (i = 0; i < (*G)->n; i++)			//扫描所有的单链表
	{
		pre = (*G)->adjlist[i].firstarc;	//p指向第i个单链表的首结点
		if (pre != NULL)
		{
			p = pre->nextarc;
			while (p != NULL)			//释放第i个单链表的所有边结点
			{
				free(pre);
				pre = p; p = p->nextarc;
			}
			free(pre);
		}
	}
	free(*G);						//释放头结点数组
}


int visited[MAXV];					//全局变量
void hasCycle(AdjGraph* G, int v,bool* has)
//判断从顶点v出发能否找到环
{
	ArcNode* p;
	int w;
	visited[v] = 1;				//置已访问标记
	p = G->adjlist[v].firstarc;	//p指向顶点v的第一个邻接点
	while (p != NULL)
	{
		w = p->adjvex;
		if (visited[w] == 0)		//若顶点w未访问,递归访问它
			hasCycle(G, w, has);
		else					//又找到了已访问过的顶点说明有回路
			has = true;
		p = p->nextarc;			//找下一个邻接点
	}
	visited[v] = 0;
}

bool Cycle(AdjGraph* G)         //判断有向图G中是否存在环
{
	int i = 0;
	bool* has = false;
	for (i = 0; i < G->n; i++)
	{
		hasCycle(G, i, has);
		if (has) return true;
	}
	return false;
}

int main()
{
	int n = 4, e = 4;
	int A[MAXV][MAXV] = {
		{0,  1,  1,INF},
		{INF, 0, INF,INF},
		{INF,1,    0,1},
		{INF,INF,INF,0}

	};

	AdjGraph* G;
	int i = 0;

	CreateAdj(&G, A, n, e);
	for (i = 0; i < n; i++)
		visited[i] = 0;

	printf("图G:\n");
	DispAdj(G);

	bool has = false;
	printf("has=%d\n", Cycle(G));

	DestroyAdj(&G);
	return 0;
}

5.prim算法求最小生成树:

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

#define INF 32767				//定义∞
#define	MAXV 100				//最大顶点个数
typedef char InfoType;


typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型

typedef struct
{
	int edges[MAXV][MAXV];		//邻接矩阵数组
	int n, e;					//顶点数,边数
	VertexType vexs[MAXV];		//存放顶点信息
} MatGraph;						//完整的图邻接矩阵类型

typedef struct ANode
{
	int adjvex;					//该边的邻接点编号
	struct ANode* nextarc;		//指向下一条边的指针
	int weight;					//该边的相关信息,如权值(用整型表示)
} ArcNode;						//边结点类型

typedef struct Vnode
{
	InfoType info;				//顶点其他信息
	int count;					//存放顶点入度,仅仅用于拓扑排序
	ArcNode* firstarc;			//指向第一条边
} VNode;

void CreateMat(MatGraph* g, int A[MAXV][MAXV], int n, int e) //创建图的邻接矩阵
{
	int i, j;
	(*g).n = n;
	(*g).e = e;
	for (i = 0; i < (*g).n; i++)
		for (j = 0; j < (*g).n; j++)
			(*g).edges[i][j] = A[i][j];
}

void DispMat(MatGraph* g)	//输出邻接矩阵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("%4d", (*g).edges[i][j]);
			else
				printf("%4s", "∞");
		printf("\n");
	}
}

void Prim(MatGraph g, int v)
{
	int lowcost[MAXV];			//顶点i是否在U中
	int min;
	int closest[MAXV], i, j, k;
	for (i = 0; i < g.n; i++)          //给lowcost[]和closest[]置初值
	{
		lowcost[i] = g.edges[v][i];
		closest[i] = v;
	}
	for (i = 1; i < g.n; i++)          //找出n-1个顶点
	{
		min = INF;
		for (j = 0; j < g.n; j++)       //在(V-U)中找出离U最近的顶点k
			if (lowcost[j] != 0 && lowcost[j] < min)
			{
				min = lowcost[j];
				k = j;			//k记录最近顶点的编号
			}
		printf(" 边(%d,%d)权为:%d\n", closest[k], k, min);
		lowcost[k] = 0;         	//标记k已经加入U
		for (j = 0; j < g.n; j++)   	//修改数组lowcost和closest
			if (g.edges[k][j] != 0 && g.edges[k][j] < lowcost[j])
			{
				lowcost[j] = g.edges[k][j];
				closest[j] = k;
			}
	}
}

int main()
{
	MatGraph g;
	int A[MAXV][MAXV] = {
		{0,28,INF,INF,INF,10,INF},
		{28,0,16,INF,INF,INF,14},
		{INF,16,0,12,INF,INF,INF},
		{INF,INF,12,0,22,INF,18},
		{INF,INF,INF,22,0,25,24},
		{10,INF,INF,INF,25,0,INF},
		{INF,14,INF,18,24,INF,0} };

	int n = 7, e = 9;

	CreateMat(&g, A, n, e);			
	printf("图G的邻接矩阵:\n");
	DispMat(&g);	

	int v = 0;
	printf("Prim算法结果(起始点为%d)\n", v);
	Prim(g, v);

	return 0;
}

6.kruskal算法求最小生成树:

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

#define INF 32767				//定义∞
#define	MAXV 100				//最大顶点个数
#define Maxsize 100

typedef char InfoType;

typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型

typedef struct
{
	int edges[MAXV][MAXV];		//邻接矩阵数组
	int n, e;					//顶点数,边数
	VertexType vexs[MAXV];		//存放顶点信息
} MatGraph;						//完整的图邻接矩阵类型

typedef struct ANode
{
	int adjvex;					//该边的邻接点编号
	struct ANode* nextarc;		//指向下一条边的指针
	int weight;					//该边的相关信息,如权值(用整型表示)
} ArcNode;						//边结点类型

typedef struct Vnode
{
	InfoType info;				//顶点其他信息
	int count;					//存放顶点入度,仅仅用于拓扑排序
	ArcNode* firstarc;			//指向第一条边
} VNode;

typedef struct
{
	int u;			//边的起始顶点
	int v;			//边的终止顶点
	int w;			//边的权值
} Edge;

void CreateMat(MatGraph* g, int A[MAXV][MAXV], int n, int e) //创建图的邻接矩阵
{
	int i, j;
	(*g).n = n;
	(*g).e = e;
	for (i = 0; i < (*g).n; i++)
		for (j = 0; j < (*g).n; j++)
			(*g).edges[i][j] = A[i][j];
}

void DispMat(MatGraph* g)	//输出邻接矩阵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("%4d", (*g).edges[i][j]);
			else
				printf("%4s", "∞");
		printf("\n");
	}
}

void InsertSort(Edge E[], int n) //对E[0..n-1]按递增有序进行直接插入排序
{
	int i, j;
	Edge temp;
	for (i = 1; i < n; i++)
	{
		temp = E[i];
		j = i - 1;				//从右向左在有序区E[0..i-1]中找E[i]的插入位置
		while (j >= 0 && temp.w < E[j].w)
		{
			E[j + 1] = E[j];	//将关键字大于E[i].w的记录后移
			j--;
		}
		E[j + 1] = temp;		//在j+1处插入E[i] 
	}
}

void Kruskal(MatGraph g)
{
	int i, j, u1, v1, sn1, sn2, k;
	int vset[MAXV];
	Edge E[Maxsize];				//存放所有边
	k = 0;							//E数组的下标从0开始计
	for (i = 0; i < g.n; i++)				//由g产生的边集E
		for (j = 0; j <= i; j++)
		{
			if (g.edges[i][j] != 0 && g.edges[i][j] != INF)
			{
				E[k].u = i; E[k].v = j; E[k].w = g.edges[i][j];
				k++;
			}
		}
	InsertSort(E, g.e);				//采用直接插入排序对E数组按权值递增排序
	for (i = 0; i < g.n; i++) 			//初始化辅助数组
		vset[i] = i;
	k = 1;                 			//k表示当前构造生成树的第几条边,初值为1
	j = 0;                 			//E中边的下标,初值为0
	while (k < g.n)       			//生成的边数小于n时循环
	{
		u1 = E[j].u; v1 = E[j].v;        //取一条边的头尾顶点
		sn1 = vset[u1];
		sn2 = vset[v1]; 				//分别得到两个顶点所属的集合编号
		if (sn1 != sn2)     	  		//两顶点属于不同的集合,该边是最小生成树的一条边
		{
			printf("  (%d,%d):%d\n", u1, v1, E[j].w);
			k++;                    //生成边数增1
			for (i = 0; i < g.n; i++)     //两个集合统一编号
				if (vset[i] == sn2)  	//集合编号为sn2的改为sn1
					vset[i] = sn1;
		}
		j++;   						//扫描下一条边
	}
}


int main()
{
	MatGraph g;

	int A[MAXV][MAXV] = {
		{0,28,INF,INF,INF,10,INF},
		{28,0,16,INF,INF,INF,14},
		{INF,16,0,12,INF,INF,INF},
		{INF,INF,12,0,22,INF,18},
		{INF,INF,INF,22,0,25,24},
		{10,INF,INF,INF,25,0,INF},
		{INF,14,INF,18,24,INF,0} };

	int n = 7, e = 9;

	CreateMat(&g, A, n, e);			//建立《教程》中图8.27的邻接矩阵
	
	printf("图G的邻接矩阵:\n");
	DispMat(&g);					//输出邻接矩阵
	
	printf("Kruskal算法结果\n");
	Kruskal(g);

	return 0;
}

7.Floyd算法求最短路径:

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

#define INF 32767				//定义∞
#define	MAXV 100				//最大顶点个数
typedef char InfoType;


typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型

typedef struct
{
	int edges[MAXV][MAXV];		//邻接矩阵数组
	int n, e;					//顶点数,边数
	VertexType vexs[MAXV];		//存放顶点信息
} MatGraph;						//完整的图邻接矩阵类型

typedef struct ANode
{
	int adjvex;					//该边的邻接点编号
	struct ANode* nextarc;		//指向下一条边的指针
	int weight;					//该边的相关信息,如权值(用整型表示)
} ArcNode;						//边结点类型

typedef struct Vnode
{
	InfoType info;				//顶点其他信息
	int count;					//存放顶点入度,仅仅用于拓扑排序
	ArcNode* firstarc;			//指向第一条边
} VNode;

void CreateMat(MatGraph* g, int A[MAXV][MAXV], int n, int e) //创建图的邻接矩阵
{
	int i, j;
	(*g).n = n;
	(*g).e = e;
	for (i = 0; i < (*g).n; i++)
		for (j = 0; j < (*g).n; j++)
			(*g).edges[i][j] = A[i][j];
}

void DispMat(MatGraph* g)	//输出邻接矩阵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("%4d", (*g).edges[i][j]);
			else
				printf("%4s", "∞");
		printf("\n");
	}
}

void Dispath(MatGraph g, int A[][MAXV], int path[][MAXV])
{
	int i, j, k, s;
	int apath[MAXV], d;		//存放一条最短路径中间顶点(反向)及其顶点个数
	for (i = 0; i < g.n; i++)
		for (j = 0; j < g.n; j++)
		{
			if (A[i][j] != INF && i != j)			//若顶点i和j之间存在路径
			{
				printf("  从%d到%d的路径为:", i, j);
				k = path[i][j];
				d = 0; apath[d] = j;				//路径上添加终点
				while (k != -1 && k != i)			//路径上添加中间点
				{
					d++; apath[d] = k;
					k = path[i][k];
				}
				d++; apath[d] = i;				//路径上添加起点
				printf("%d", apath[d]);			//输出起点
				for (s = d - 1; s >= 0; s--)			//输出路径上的中间顶点
					printf(",%d", apath[s]);
				printf("\t路径长度为:%d\n", A[i][j]);
			}
		}
}

void Floyd(MatGraph g)							//Floyd算法
{
	int A[MAXV][MAXV], path[MAXV][MAXV];
	int i, j, k;
	for (i = 0; i < g.n; i++)
		for (j = 0; j < g.n; j++)
		{
			A[i][j] = g.edges[i][j];
			if (i != j && g.edges[i][j] < INF)
				path[i][j] = i;					//顶点i到j有边时
			else
				path[i][j] = -1;				//顶点i到j没有边时
		}
	for (k = 0; k < g.n; k++)						//依次考察所有顶点
	{
		for (i = 0; i < g.n; i++)
			for (j = 0; j < g.n; j++)
				if (A[i][j] > A[i][k] + A[k][j])
				{
					A[i][j] = A[i][k] + A[k][j];	//修改最短路径长度
					path[i][j] = path[k][j];		//修改最短路径
				}
	}
	Dispath(g, A, path);							//输出最短路径
}

int main()
{
	MatGraph g;
	
	int A[MAXV][MAXV] = {
		{0,  6, INF,INF,2},
		{INF,0, INF,INF,INF},
		{INF,1, 0,  3,  INF},
		{2,  INF,INF,0, INF},
		{INF,3,  1,  3, 0}
	};
	
	int n = 5, e = 8;
	CreateMat(&g, A, n, e);			//建立图的邻接矩阵
	
	printf("图G的邻接矩阵:\n");
	DispMat(&g);					//输出邻接矩阵
	
	printf("各顶点对的最短路径:\n");
	Floyd(g);

	return 0;
}

8.Dijkstra算法求最短路径:

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

#define INF 32767				//定义∞
#define	MAXV 100				//最大顶点个数
#define Maxsize 100

typedef char InfoType;

typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型

typedef struct
{
	int edges[MAXV][MAXV];		//邻接矩阵数组
	int n, e;					//顶点数,边数
	VertexType vexs[MAXV];		//存放顶点信息
} MatGraph;						//完整的图邻接矩阵类型

typedef struct ANode
{
	int adjvex;					//该边的邻接点编号
	struct ANode* nextarc;		//指向下一条边的指针
	int weight;					//该边的相关信息,如权值(用整型表示)
} ArcNode;						//边结点类型

typedef struct Vnode
{
	InfoType info;				//顶点其他信息
	int count;					//存放顶点入度,仅仅用于拓扑排序
	ArcNode* firstarc;			//指向第一条边
} VNode;

void CreateMat(MatGraph* g, int A[MAXV][MAXV], int n, int e) //创建图的邻接矩阵
{
	int i, j;
	(*g).n = n;
	(*g).e = e;
	for (i = 0; i < (*g).n; i++)
		for (j = 0; j < (*g).n; j++)
			(*g).edges[i][j] = A[i][j];
}

void DispMat(MatGraph* g)	//输出邻接矩阵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("%4d", (*g).edges[i][j]);
			else
				printf("%4s", "∞");
		printf("\n");
	}
}

int count = 0;
void Dispath(MatGraph g, int dist[], int path[], int S[], int v)
//输出从顶点v出发的所有最短路径
{
	int i, j, k;
	int apath[MAXV], d;					//存放一条最短路径(逆向)及其顶点个数
	for (i = 0; i < g.n; i++)					//循环输出从顶点v到i的路径
		if (S[i] == 1 && i != v)
		{
			printf("  从顶点%d到顶点%d的路径长度为:%d\t路径为:", v, i, dist[i]);
			d = 0; apath[d] = i;			//添加路径上的终点
			k = path[i];
			if (k == -1)					//没有路径的情况
				printf("无路径\n");
			else						//存在路径时输出该路径
			{
				while (k != v)
				{
					d++; apath[d] = k;
					k = path[k];
				}
				d++; apath[d] = v;		//添加路径上的起点
				printf("%d", apath[d]);	//先输出起点
				for (j = d - 1; j >= 0; j--)	//再输出其他顶点
					printf(",%d", apath[j]);
				printf("\n");
			}
		}
}

void disp(int dist[MAXV], int path[MAXV], int n)  //输出dis和path
{
	int i;
	printf("         dist                    path\n");
	for (i = 0; i < n; i++)
		if (dist[i] != INF)
			printf("%4d", dist[i]);
		else
			printf("%4s", "∞");
	printf("\t");
	for (i = 0; i < n; i++)
		printf("%4d", path[i]);
	printf("\n");
}

void Dijkstra(MatGraph g, int v)	//Dijkstra算法
{
	int dist[MAXV], path[MAXV];
	int S[MAXV];				//S[i]=1表示顶点i在S中, S[i]=0表示顶点i在U中
	int Mindis, i, j, u;
	bool flag;
	for (i = 0; i < g.n; i++)
	{
		dist[i] = g.edges[v][i];	//距离初始化
		S[i] = 0;					//S[]置空
		if (g.edges[v][i] < INF)	//路径初始化
			path[i] = v;			//顶点v到顶点i有边时,置顶点i的前一个顶点为v
		else
			path[i] = -1;			//顶点v到顶点i没边时,置顶点i的前一个顶点为-1
	}
	disp(dist, path, g.n);
	printf("(%d)将顶点%d添加到S集合\n", ++count, v);
	S[v] = 1; path[v] = 0;			//源点编号v放入S中
	for (i = 0; i < g.n - 1; i++)		//循环直到所有顶点的最短路径都求出
	{
		Mindis = INF;				//Mindis置最大长度初值
		for (j = 0; j < g.n; j++)		//选取不在S中(即U中)且具有最小最短路径长度的顶点u
			if (S[j] == 0 && dist[j] < Mindis)
			{
				u = j;
				Mindis = dist[j];
			}
		printf("  求出U中最小的顶点%d\n", u);
		printf("(%d)将顶点%d添加到S集合\n", ++count, u);
		S[u] = 1;					//顶点u加入S中
		flag = false;
		for (j = 0; j < g.n; j++)		//修改不在S中(即U中)的顶点的最短路径
			if (S[j] == 0)
			{
				if (g.edges[u][j] < INF)
				{
					flag = true;
					printf("  考虑顶点%d的邻接点%d:", u, j);
					if (dist[u] + g.edges[u][j] < dist[j])
					{
						dist[j] = dist[u] + g.edges[u][j];
						printf("修改其最短路径长度dist[%d]为%d,", j, dist[j]);
						path[j] = u;
						printf("修改最短路径path[%d]为%d\n", j, u);
					}
					else
						printf("顶点%d的最短路径长度没有修改\n", j);
				}
			}
		if (!flag)
			printf("   顶点%d没有未考虑的邻接点(不修改)\n", u);
		disp(dist, path, g.n);
	}
	Dispath(g, dist, path, S, v);	//输出最短路径
}

int main()
{
	MatGraph g;
	
	int A[MAXV][MAXV] = {
	{0,  6, INF,INF,2},
	{INF,0, INF,INF,INF},
	{INF,1, 0,  3,  INF},
	{2,  INF,INF,0, INF},
	{INF,3,  1,  3, 0}
	};
	
	int n = 5, e = 8;
	CreateMat(&g, A, n, e);			//建立图的邻接矩阵
	
	printf("图G的邻接矩阵:\n");
	DispMat(&g);					//输出邻接矩阵
	
	int v = 0;
	printf("从%d顶点出发的最短路径求解过程如下:\n", v);
	Dijkstra(g, v);
	
	return 0;
}

9.拓扑排序:

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

#define INF 32767				//定义∞
#define	MAXV 100				//最大顶点个数
typedef char InfoType;


typedef struct
{
	int no;						//顶点编号
	InfoType info;				//顶点其他信息
} VertexType;					//顶点类型

typedef struct ANode
{
	int adjvex;					//该边的邻接点编号
	struct ANode* nextarc;		//指向下一条边的指针
	int weight;					//该边的相关信息,如权值(用整型表示)
} ArcNode;						//边结点类型

typedef struct Vnode
{
	InfoType info;				//顶点其他信息
	int count;					//存放顶点入度,仅仅用于拓扑排序
	ArcNode* firstarc;			//指向第一条边
} VNode;

typedef struct
{
	VNode adjlist[MAXV];		//邻接表头结点数组
	int n, e;					//图中顶点数n和边数e
} AdjGraph;						//完整的图邻接表类型


//邻接表的基本运算算法
void CreateAdj(AdjGraph** G, int A[MAXV][MAXV], int n, int e) {
	int i, j;
	ArcNode* p;
	*G = (AdjGraph*)malloc(sizeof(AdjGraph));
	if (!*G) {
		printf("Memory allocation failed.\n");
		return;
	}
	for (i = 0; i < n; i++) {
		(*G)->adjlist[i].firstarc = NULL;
	}

	int actualEdges = 0; // 实际边数计数器
	for (i = 0; i < n; i++) {
		for (j = n - 1; j >= 0; j--) {
			if (A[i][j] != 0 && A[i][j] != INF) {
				p = (ArcNode*)malloc(sizeof(ArcNode));
				if (!p) {
					printf("Memory allocation failed.\n");
					return;
				}
				p->adjvex = j;
				p->weight = A[i][j];
				p->nextarc = (*G)->adjlist[i].firstarc;
				(*G)->adjlist[i].firstarc = p;
				actualEdges++; // 增加实际边数
			}
		}
	}

	(*G)->n = n;
	(*G)->e = actualEdges; // 设置正确的边数
}

void DispAdj(AdjGraph* G) {
	int i;
	ArcNode* p;
	for (i = 0; i < G->n; i++) {
		p = G->adjlist[i].firstarc;
		printf("%3d: ", i);
		while (p != NULL) {
			printf("%3d[%d]→", p->adjvex, p->weight);
			p = p->nextarc;
		}
		printf("∧\n");
	}
}

void DestroyAdj(AdjGraph** G)		//销毁图的邻接表
{
	int i;
	ArcNode* pre, * p;
	for (i = 0; i < (*G)->n; i++)			//扫描所有的单链表
	{
		pre = (*G)->adjlist[i].firstarc;	//p指向第i个单链表的首结点
		if (pre != NULL)
		{
			p = pre->nextarc;
			while (p != NULL)			//释放第i个单链表的所有边结点
			{
				free(pre);
				pre = p; p = p->nextarc;
			}
			free(pre);
		}
	}
	free(*G);						//释放头结点数组
}

void TopSort(AdjGraph* G)			//拓扑排序算法
{
	int i, j;
	int St[MAXV], top = -1;			//栈St的指针为top
	ArcNode* p;
	for (i = 0; i < G->n; i++)			//入度置初值0
		G->adjlist[i].count = 0;
	for (i = 0; i < G->n; i++)			//求所有顶点的入度
	{
		p = G->adjlist[i].firstarc;
		while (p != NULL)
		{
			G->adjlist[p->adjvex].count++;
			p = p->nextarc;
		}
	}
	for (i = 0; i < G->n; i++)			//将入度为0的顶点进栈
		if (G->adjlist[i].count == 0)
		{
			top++;
			St[top] = i;
		}
	while (top > -1)					//栈不空循环
	{
		i = St[top]; top--;			//出栈一个顶点i
		printf("%d ", i);			//输出该顶点
		p = G->adjlist[i].firstarc;	//找第一个邻接点
		while (p != NULL)				//将顶点i的出边邻接点的入度减1
		{
			j = p->adjvex;
			G->adjlist[j].count--;
			if (G->adjlist[j].count == 0)//将入度为0的邻接点进栈
			{
				top++;
				St[top] = j;
			}
			p = p->nextarc;			//找下一个邻接点
		}
	}
}

int main()
{
	AdjGraph* G;
	
	int A[MAXV][MAXV] =
	{ {0,1,INF,INF,INF,INF},
	{INF,0,1,INF,INF,INF},
	{INF,INF,0,1,INF,INF},
	{INF,INF,INF,0,INF,INF},
	{INF,1,INF,INF,0,1},
	{INF,INF,INF,1,INF,0} };
	
	int n = 6, e = 6;
	CreateAdj(&G, A, n, e);			//建立《教程》中图8.44的邻接表
	
	printf("图G的邻接表:\n");
	DispAdj(G);					//输出邻接表G
	
	printf("拓扑序列:"); 
	TopSort(G); 
	printf("\n");
	
	DestroyAdj(&G);				//销毁邻接表

	return 0;
}
相关推荐
爱吃生蚝的于勒20 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~23 分钟前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
脉牛杂德1 小时前
多项式加法——C语言
数据结构·c++·算法
一直学习永不止步2 小时前
LeetCode题练习与总结:赎金信--383
java·数据结构·算法·leetcode·字符串·哈希表·计数
wheeldown9 小时前
【数据结构】选择排序
数据结构·算法·排序算法
躺不平的理查德13 小时前
数据结构-链表【chapter1】【c语言版】
c语言·开发语言·数据结构·链表·visual studio
阿洵Rain13 小时前
【C++】哈希
数据结构·c++·算法·list·哈希算法
Leo.yuan14 小时前
39页PDF | 华为数据架构建设交流材料(限免下载)
数据结构·华为
半夜不咋不困14 小时前
单链表OJ题(3):合并两个有序链表、链表分割、链表的回文结构
数据结构·链表
忘梓.15 小时前
排序的秘密(1)——排序简介以及插入排序
数据结构·c++·算法·排序算法