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;
}