https://blog.csdn.net/weixin_51538341/article/details/122265865?spm=1001.2014.3001.5501
1、邻接矩阵
#include <stdio.h>
#include <stdlib.h>
typedef char datatype;
typedef int edgetype;
#define MAXVEX 20 //顶点最大数,由使用者自定义
#define INFINITY 65535 //代指无限大
typedef struct
{
datatype data[MAXVEX]; //顶点表
edgetype arc[MAXVEX][MAXVEX]; //存储边或弧的权的邻接矩阵
int numVertexes,numEdges; //顶点数,边或弧的个数
}MGraph;//图结构--邻接矩阵
void Creat_MGraph(MGraph *G);
int main()
{
MGraph G;
Creat_MGraph(&G);
int i,j;
//将边表进行输出检查
printf
for(i=0;i<G.numVertexes;i++)
{
for(j=0;j<G.numVertexes;j++)
printf("%10d",G.arc[i][j]);
printf("\n");
}
}
//使用图的邻接矩阵存储方式创建网图 无向网图
void Creat_MGraph(MGraph *G)
{
int a,b,i,j;
int x,y;
datatype ch;
edgetype w;
printf("Please input numVertexes,numEdges:");
scanf("%d,%d",&a,&b); //a:顶点个数 , b:边或弧的个数
G->numVertexes=a;
G->numEdges=b;
//初始化邻接矩阵
for(i=0;i<a;i++)
{
for(j=0;j<a;j++)
{
if(i==j)
G->arc[i][j]=0;
else
G->arc[i][j]=INFINITY;
}
}
//给每个顶点赋值
for(i=0;i<a;i++)
{
printf("Please input data[%d]:",i);
scanf(" %c",&ch);
G->data[i]=ch;
}
//给每条边或弧赋值
for(i=0;i<b;i++)
{
printf("Please input (vi,vj)的下标,和对应的权:\n");
scanf(" %d,%d,%d",&x,&y,&w);
G->arc[x][y]=w;
G->arc[y][x]= G->arc[x][y]; // 若为无向图,矩阵对称。否则删除即可
}
//n:顶点数,e:边数 时间复杂度O(n^2+n+e)--------->O(n^2)
}
2、邻接表
#include <stdio.h>
#include <stdlib.h>
typedef char datatype;
typedef int edgetype;
#define MAXVEX 20
typedef struct ENode
{
int adjvex; //当前顶点的邻接点在顶点表中的下标
edgetype w; //权数
struct ENode *next; //指向下一个邻接点
}EdgeNode;//边表结构
typedef struct VNode
{
datatype data;
EdgeNode *firstedge; //当前顶点的第一个邻接点,边表头指针
}VertexNode,AdjList[MAXVEX];//顶点结构
typedef struct
{
AdjList adjList; //储存所有的顶点的数组
int numVertexes,numEdges;//图中顶点数,边或弧的个数
}GraphAdjList;//图结构--邻接表
void Creat_GraphAdjList(GraphAdjList *G);
int main()
{
GraphAdjList G;
Creat_GraphAdjList(&G);
}
//使用图的邻接表存储方式创建网图 无向网图
void Creat_GraphAdjList(GraphAdjList *G)
{
int v_num,e_num;
int i,x,y;
EdgeNode *e;
datatype ch;
edgetype w;
printf("Please input numVertexes,numEdges:");
scanf("%d,%d",&v_num,&e_num); //顶点个数 , 边或弧的个数
G->numVertexes=v_num;
G->numEdges=e_num;
//给每个顶点赋值
for(i=0;i<v_num;i++)
{
printf("Please input adjList[%d].data:",i);
scanf(" %c",&ch);
G->adjList[i].data=ch;
G->adjList[i].firstedge=NULL;
}
//建立边表
/*建立有向图时,输入一次下标时
只需将其中一个顶点作为弧尾或弧头的形式 进行建立边表
不用管另一个顶点的边也要反向建立*/
for(i=0;i<e_num;i++)
{
printf("Please input (vi,vj) or <vi,vj>的下标,和对应的权:\n");
scanf(" %d,%d,%d",&x,&y,&w);
e=(EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex=y;
e->w=w;
e->next=G->adjList[x].firstedge; //以头插法的形式将边插入到边表中
G->adjList[x].firstedge=e;
e=(EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex=x;
e->w=w;
e->next=G->adjList[y].firstedge;
G->adjList[y].firstedge=e;
}
//n:顶点数,e:边数 时间复杂度--------->O(n+e)
//打印邻接表
printf("邻接表为:\n");
for(i=0;i<G->numVertexes;i++){
e=G->adjList[i].firstedge;
while(e){
printf("(%c,%c)",G->adjList[i].data,G->adjList[e->adjvex].data);
e=e->next;
}
printf("\n");
}
}
3、十字链表法
#include <stdio.h>
#include <stdlib.h>
typedef char datatype;
typedef int edgetype; //权值类型,建立网图时需引进
#define MAXVEX 20
typedef struct ENode
{
int tailvex,headvex; //弧起点在顶点表的下标,弧终点在顶点表的下标
struct ENode *taillink,*headlink; //指向起点相同的下条边,指向终点相同的下条边
}EdgeNode;//边表结构
typedef struct VNode
{
datatype data;
EdgeNode *firstin,*firstout;//入边表头指针 ,出边表头指针
}VertexNode,OrtList[MAXVEX];//顶点结构
typedef struct
{
OrtList OrtList; //储存所有的顶点的数组
int numVertexes,numEdges;//图中顶点数,边或弧的个数
}GraphOrtList;//图结构--邻接表
void Creat_GraphOrtList(GraphOrtList *G);
void Print_GraphOrtList(GraphOrtList G);
int main()
{
GraphOrtList G;
Creat_GraphOrtList(&G);
Print_GraphOrtList(G);
}
//使用图的十字链表存储方式创建图 针对有向图的优化
void Creat_GraphOrtList(GraphOrtList *G)
{
int v_num,e_num;
int i,x,y;
EdgeNode *e;
datatype ch;
printf("Please input numVertexes,numEdges:");
scanf("%d,%d",&v_num,&e_num); //顶点个数 , 边或弧的个数
G->numVertexes=v_num;
G->numEdges=e_num;
//给每个顶点赋值
for(i=0;i<v_num;i++)
{
printf("Please input adjList[%d].data:",i);
scanf(" %c",&ch);
G->OrtList[i].data=ch;
G->OrtList[i].firstin=NULL;
G->OrtList[i].firstout=NULL; //入边表头指针,出边表头指针赋值NULL
}
//建立边表
for(i=0;i<e_num;i++)
{
printf("Please input <vi,vj>的下标:\n");
scanf(" %d,%d",&x,&y);
e=(EdgeNode*)malloc(sizeof(EdgeNode));
e->tailvex=x;
e->headvex=y;
//firstin:入边表头指针 firstout:出边表头指针
e->taillink=G->OrtList[x].firstout;//taillink:指向起点相同的下条边
G->OrtList[x].firstout=e;
e->headlink=G->OrtList[y].firstin;//headlink:指向终点相同的下条边
G->OrtList[y].firstin=e;
}
//n:顶点数,e:边数 时间复杂度--------->O(n+e)
}
//打印十字链表
void Print_GraphOrtList(GraphOrtList G)
{
int i;
EdgeNode *p;
printf("邻接表为:\n");
for(i=0;i<G.numVertexes;i++){
p=G.OrtList[i].firstout;
while(p){
printf("(%c,%c)",G.OrtList[i].data,G.OrtList[p->headvex].data);
p=p->taillink;
}
printf("\n");
}
printf("逆邻接表为:\n");
for(i=0;i<G.numVertexes;i++){
p=G.OrtList[i].firstin;
while(p){
printf("(%c,%c)",G.OrtList[p->tailvex].data,G.OrtList[i].data);
p=p->headlink;
}
printf("\n");
}
}
4、邻接多重表
#include<stdio.h>
#include<stdlib.h>
#define MAX_SIZE 20
typedef struct EdgeNode //边结点
{
int info; //边的数据信息
int mark; //访问标记
int iVex, jVex; //边所连接的两个顶点
struct EdgeNode *tailEdge, *headEdge; //分别指向头、尾顶点的边链表
}EdgeNode;
typedef struct VexNode //顶点结点
{
char data; //顶点数据信息
EdgeNode *firstEdge ; //分别指向第一个条边
}VexNode;
typedef struct
{
VexNode MutiList[MAX_SIZE]; //顶点数组
int numVexs, numEdge; //图的顶点数和边数
}AMLGraph;
void CreateAMLGraph(AMLGraph *G)
{
int i, j, k, w;
printf("请输入顶点数和边数:");
scanf("%d %d", &G->numVexs, &G->numEdge);
for(i = 0; i < G->numVexs; i++)
{
fflush(stdin);
printf("请输入第%d个顶点信息:", i+1);
scanf("%c", &G->MutiList[i].data);
G->MutiList[i].firstEdge = NULL;
}
printf("\n");
for(k = 0; k < G->numEdge; k++)
{
printf("请输入弧(Ai, Aj)的头尾顶点及其权值:");
scanf("%d %d %d", &i, &j, &w);
//创建新的弧结点
EdgeNode *s;
s = (EdgeNode *)malloc(sizeof(EdgeNode));
s->info = w;
s->mark = 0;
s->jVex = i - 1;
s->iVex = j - 1;
//头插法插入,(插入边结点链表<——头顶点i——尾顶点j)
s->headEdge = G->MutiList[i-1].firstEdge;
G->MutiList[i-1].firstEdge = s;
//头插法插入,(头顶点i——尾顶点j——>插入边结点链表)
s->tailEdge = G->MutiList[j-1].firstEdge;
G->MutiList[j-1].firstEdge = s;
}
}
void TraverseEdge(AMLGraph &G) //遍历各个顶点的所有连接着的边
{
EdgeNode *p;
printf("图G:\n");
for(int i = 0; i < G.numVexs; i++)
{
p = G.MutiList[i].firstEdge;
while (p && !p->mark)
{
printf("%c----%c(%d)\n",G.MutiList[p->jVex].data, G.MutiList[p->iVex].data, p->info);
p->mark = 1;
p = p->headEdge;
}
}
}
int main()
{
AMLGraph G;
CreateAMLGraph(&G);
TraverseEdge(G);
return 0;
}
5、最短路径 Dijkstra算法
#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 100
#define INF 65535
typedef char VertexType;
typedef int EdgeType;
typedef struct //邻接矩阵结构
{
VertexType vexs[MAXVEX];
EdgeType arc[MAXVEX][MAXVEX];
int numVexs, numEdges;
}AMGraph;
int Flag[MAXVEX]; //标志每个顶点是否加入最短路径的顶点集合S中
int minLen[MAXVEX]; //表示从源顶点到各个顶点最短路径长度
int Path[MAXVEX]; //表示最短路径中每个顶点的前驱顶点
void CreateAMGraph(AMGraph &G) //创建邻接矩阵
{
int i, j, k, w;
printf("请输入顶点数和边数:");
scanf("%d %d", &G.numVexs, &G.numEdges);
fflush(stdin);
for(i = 0; i < G.numVexs; i++)
{
printf("请第%d个顶点信息:", i + 1);
scanf("%c", &G.vexs[i]);
fflush(stdin);
}
for(i = 0; i < G.numVexs; i++)
for(j = 0; j < G.numVexs; j++)
G.arc[i][j] = INF;
for(k = 0; k < G.numEdges; k++)
{
printf("请输入第%d条边的两个顶点及其权值:", k+1);
scanf("%d %d %d", &i, &j, &w);
G.arc[i-1][j-1] = w;
}
}
void ShortestPath_DIJ(AMGraph G, int v0)
{
//初始化
for(int v = 0; v < G.numVexs; v++)
{
Flag[v] = 0; //初始化所有顶点都未加入集合S
minLen[v] = G.arc[v0][v]; //初始化v0到各个顶点的最短距离
if(minLen[v] < INF)
Path[v] = v0; //若有直接通路,则前驱置为v0
else
Path[v] = -1; //若无直接通路,则前驱置为-1
}
Flag[v0] = 1; //源点v0已访问
minLen[v0] = 0; //源点到源点的距离为0
//除源点v0外, 访问其他n-1个顶点
for(int i = 1; i < G.numVexs; i++)
{
int w, min = INF;
//遍历所有顶点,找出当前最短的一条通路,终点为v
for(w = 0; w < G.numVexs; w++)
{
if(!Flag[w] && minLen[w] < min)
{
v = w;
min = minLen[w];
}
}
Flag[v] = 1; //将顶点v加入最短路径集合S中
//更新从v0到集合S中所有顶点的最小路径
for(w = 0; w < G.numVexs; w++)
{
if(!Flag[w] && minLen[v] + G.arc[v][w] < minLen[w]) //比较v0->v->w和v0->w两段路径长度
{
minLen[w] = minLen[v] + G.arc[v][w]; //替换更短的那条路径
Path[w] = v; //并更改当前最短路径顶点的前驱
}
}
}
}
void DisplayPath(AMGraph G, int Path[], int ve) //打印路径
{
int v = ve;
printf("min = %d\n", minLen[v]);
printf("%c<--", G.vexs[v]);
while(Path[v] != -1)
{
printf("%c<--", G.vexs[Path[v]]);
v = Path[v];
}
printf("\n");
}
int main()
{
AMGraph G;
CreateAMGraph(G);
int v0, ve;
printf("请输入源点v0和终点ve:");
scanf("%d %d", &v0, &ve);
ShortestPath_DIJ(G, v0 - 1);
DisplayPath(G, Path, ve - 1);
return 0;
}
6、图的遍历————深度优先
//深度优先遍历
void DFS(LGraph* g,int *visit,int v)
{
printf("Node: %d\n",v);
ENode* p = g->a[v];
visit[v] =1;
for(;p;p = p->nextArc)
{
if(visit[p->adjVex]==0)
DFS(g,visit,p->adjVex);
}
}
void DFSGraph(LGraph* g)
{
int *visit = (int*)malloc(sizeof(int)*g->n);
int i = 0;
for(;i<g->n;i++)
visit[i]= 0;
for(i = 0;i<g->n;i++)
{
if(visit[i]==0)
DFS(g,visit,i);
}
free(visit);
}
7、图的遍历————广度优先
//广度优先遍历
void BFS(LGraph* g,int v,int* visit)
{
ENode *q[50];
int front = 0,rear = 0;
visit[v] = 1;
printf("Node: %d\n",v);
q[rear] = g->a[v];
rear = (rear+1)%10;
while(front!=rear)
{
ENode* p = q[front];
front = (front+1)%10;
for(;p;p = p->nextArc)
{
if(visit[p->adjVex]==0)
{
visit[p->adjVex]=1;
printf("Node: %d\n",p->adjVex);
q[rear] = g->a[p->adjVex];
rear = (rear+1)%10;
}
}
}
}
void BFSGraph(LGraph* g)
{
int *visit = (int*)malloc(sizeof(int)*g->n);
int i = 0;
for(;i<g->n;i++)
visit[i]= 0;
for(i = 0;i<g->n;i++)
{
if(visit[i]==0)
BFS(g,i,visit);
}
free(visit);
}
8、AOV网的——拓扑排序
#include"stdio.h"
#include"stdlib.h"
#define M 20
typedef char vertextype;
typedef struct node //边结点类型定义
{
int adjvex;
struct node *next;
}EdgeNode;
typedef struct //带顶点入度的头结点定义
{
EdgeNode *firstedge;
vertextype vertex;
int id; //顶点的入度域
}VertexNode;
typedef struct //AOV网的邻接表结构
{
VertexNode adjlist[M];
int n,e; //图的顶点数与边数
}AovGraph;
void creataov(AovGraph *g) //建立AOV网的邻接表
{
int i,j,k;
EdgeNode *s;
printf("输入图的顶点数与边数:");
scanf("%d%d",&g->n,&g->e);
printf("输入顶点及顶点的入度\n");
for(i=0;i<g->n;i++)
{
scanf("%ls%d",&g->adjlist[i].vertex,&g->adjlist[i].id);
g->adjlist[i].firstedge=NULL;
}
printf("输入有序对\n");
for(k=0;k<g->e;k++)
{
scanf("%d%d",&i,&j);
s=(EdgeNode*)malloc(sizeof(EdgeNode));
s->adjvex=j;
s->next=g->adjlist[i].firstedge;
g->adjlist[i].firstedge=s;
}
}
void TopSort(Aovgraph g) //AOV网拓扑排序
{
int i,j,v,flag[M],queue[M],rear,front;
EdgeNode *p;
front=rear=0; //初始化空队列
for(i=0;i<g.n;i++)
flag[i]=0; //初始化访问标记
for(i=0;i<g.n;i++) //入度为0的结点进队
{
if(g.adjlist[i].id==0&&flag[i]==0)
{
queue[rear++]=i;
flag[i]=1;
}
}
printf("输出AOV网的拓扑序列:");
while(front<rear) //队列不为空
{
v=queue[front++]; //队首元出队
printf("%c ",g.adjlist[v].vertex);
p=g.adjlist[v].firstedge;
while(p) //所有与v邻接的顶点的入度减1
{
j=p->adjvex;
if(--g.adjlist[j].id==0&&flag[j]==0) //入度为0则进队
{
queue[rear++]=j;
flag[j]=1;
}
p=p->next;
}
}
}
int main()
{
AovGraph ag;
printf("创建一个AOV网的邻接表\n");
creataov(&ag);
TopSort(ag);
return 0;
}
9、最小生成树 prim算法
#include<stdio.h>
#define MAXVEX 100
#define INF 65535
typedef char VertexType;
typedef int EdgeType;
typedef struct //邻接矩阵结构
{
VertexType vexs[MAXVEX];
EdgeType arc[MAXVEX][MAXVEX];
int numVexs, numEdges;
}AMGraph;
typedef struct //最小边的结构
{
VertexType adjvex; //最小边所对应的生成树内顶点
EdgeType lowcost; //最小边上的权值
}MinEdge;
MinEdge closedge[MAXVEX]; //定义最小边数组
void CreateAMGraph(AMGraph &G) //创建邻接矩阵
{
int i, j, k, w;
printf("请输入顶点数和边数:");
scanf("%d %d", &G.numVexs, &G.numEdges);
fflush(stdin);
for(i = 0; i < G.numVexs; i++)
{
printf("请第%d个顶点信息:", i + 1);
scanf("%c", &G.vexs[i]);
fflush(stdin);
}
for(i = 0; i < G.numVexs; i++)
for(j = 0; j < G.numVexs; j++)
G.arc[i][j] = INF;
for(k = 0; k < G.numEdges; k++)
{
printf("请输入第%d条边的两个顶点及其权值:", k+1);
scanf("%d %d %d", &i, &j, &w);
G.arc[i-1][j-1] = w;
G.arc[j-1][i-1] = w;
}
}
int LocateAMGraph(AMGraph G, VertexType u) //取顶点u的位置
{
for(int i = 0; i < G.numVexs; i++)
{
if(G.vexs[i] == u)
return i;
}
return -1;
}
int Min(MinEdge closedge[], int size) //取最小权值边的顶点位置
{
int k = -1;
for(int i = 0; i < size; i++)
{
if(closedge[i].lowcost > 0)
{
int min = closedge[i].lowcost;
for(int j = i; j < size; j++)
{
if(closedge[j].lowcost > 0 && min >= closedge[j].lowcost)
{
min = closedge[j].lowcost;
k = j;
}
}
break;
}
}
return k;
}
void Display(AMGraph G, MinEdge closedge[]) //遍历最小边数组和顶点
{
for(int i = 0; i < G.numVexs; i++)
{
printf("%c\t", closedge[i].adjvex);
}
printf("\n");
for(int j = 0; j < G.numVexs; j++)
{
printf("%c\t", G.vexs[j]);
}
printf("\n");
for(int k = 0; k < G.numVexs; k++)
{
if(closedge[k].lowcost == INF)
printf("∞\t");
else
printf("%d\t", closedge[k].lowcost);
}
printf("\n");
}
void MiniSpanTree_Prim(AMGraph G, VertexType u) //最小生成树Prim算法
{
int i, j, k = LocateAMGraph(G, u);
//初始化每个顶点到顶点u的最小边权值
for(i = 0; i < G.numVexs; i++)
{
closedge[i].adjvex = u;
closedge[i].lowcost = G.arc[k][i];
}
//边权值置为0,表示该顶点已加入最小生成树中
closedge[k].lowcost = 0;
//Display(G, closedge);
//printf("最小边数组初始化完成!\n");
//对剩余的n-1条边进行操作
for(i = 1; i < G.numVexs; i++)
{
//取最小边的顶点位置
k = Min(closedge, G.numVexs);
printf("---(%d)--->%c\n", closedge[k].lowcost, G.vexs[k]);
//边权值置为0,表示该顶点已加入最小生成树中
closedge[k].lowcost = 0;
//更新边的权值,使得生成树内顶点到其他顶点的边值最小
for(j = 0; j < G.numVexs; j++)
{
if(G.arc[k][j] < closedge[j].lowcost)
{
closedge[j].adjvex = G.vexs[k];
closedge[j].lowcost = G.arc[k][j];
}
}
}
}
int main()
{
AMGraph G;
CreateAMGraph(G);
//从顶点'A'开始创建最小生成树
MiniSpanTree_Prim(G, 'A');
return 0;
}