图
- 图是一种元素关系多对多的数据结构;
- 图分为有向图和无向图;
- 图的遍历方法分为深度遍历(DFS)和广度遍历(BFS);
- 无向图的最小生成树;
- 有向图的拓扑排序和关键路径;
- 有权图的单源最短路径和所有顶点的最短路径;
图数据结构 C语言实现
#define true 1
#define false 0
#define OVERFLOW 1
#define MAX_VERTEX_NUM 20 //最大顶点数
#define INFINITY INT_MAX //最大值无穷,在有权图中使用
//图邻接矩阵表示数据结构
typedef enum {DG, DN, UDG, UDN}; //有向图,有向网,无向图,无向网
typedef struct ArcCell {
int adj; //VRType adj 无权图用0,1表示是否相连
//有权图用权值表示
// InfoType *info; //表示弧相关信息
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
//typedef struct{
// int vexs[MAX_VERTEX_NUM]; //顶点向量 VertexType vexs
// AdjMatrix arcs; //邻接矩阵
// int vexnum; //顶点数
// int arcnum; //弧数
GraphKind kind; //图类型
//}MGraph;
typedef struct{
int* vexs; //顶点向量 VertexType vexs
ArcCell** arcs; //邻接矩阵
int vexnum; //顶点数
int arcnum; //弧数
// GraphKind kind; //图类型
}MGraph;
图基本方法声明和实现 C语言
- 基本函数声明
//函数声明
void InitGraph(MGraph*); //初始化数据
void CreateGraph(MGraph*, int*, AdjMatrix**); //创建图
void PrintGraph(MGraph); //输出图
void DestoryGraph(MGraph*); //销毁图
int FirstAdjVex(MGraph, int);//返回v的第一个邻接点
int NextAdjVex(MGraph, int, int);
void Visit(int);
- 基本函数实现
//初始条件
//操作结果 开辟顶点向量数组和邻接矩阵空间和初始化
void InitGraph(MGraph* G){
printf("%s\n", "please input the number of vertices and arcs in the graph!");
scanf("%d%d", &G->vexnum, &G->arcnum);
int i, j;
//开顶点数组和邻接矩阵空间
int* vexs = (int*)calloc(G->vexnum, sizeof(int));
ArcCell** arcs = (ArcCell**)calloc(G->vexnum, sizeof(ArcCell));
for(i = 0; i < G->vexnum; i++){
arcs[i] = (ArcCell*)calloc(G->vexnum, sizeof(ArcCell));
}
printf("%s\n", "input vertices"); //输入顶点信息 0,1,2,3,4...
for(i = 0; i < G->vexnum; i++)
scanf("%d", &vexs[i]);
//初始化邻接矩阵
for(i = 0; i < G->vexnum; i++)
for(j = 0; j < G->vexnum; j++){
arcs[i][j].adj = 0;
// arcs[i][j]->adj = INT_MAX; //有权图初始化
}
int x, y, adj;
printf("%s\n", "Input arc triples!");
for(i = 0; i < G->arcnum; i++){
scanf("%d%d%d", &x, &y, &adj);
arcs[x][y].adj = adj;
arcs[y][x].adj = adj;
}
CreateGraph(G, vexs, arcs);
}
//初始条件 vexs图的顶点集, arcs图的弧集
//操作结果 按vexs和arcs构造图G
//函数形参传递是地址,需要使用G->vexs或者(*G).vexs,不能使用G.vexs
void CreateGraph(MGraph* G, int* vexs, AdjMatrix** arcs){
//地址,就在它后边用->,如果它不是地址,就在它后边就用.
G->vexs = vexs;
G->arcs = arcs;
}
//初始条件 图存在
//操作结果 打印图的邻接矩阵
//函数形参将图本身传递进来,非地址,需要使用.而非->
void PrintGraph(MGraph G){
if(G.vexs != NULL){
for(int i = 0; i < G.vexnum; i++){
for(int j = 0; j < G.vexnum; j++){
printf("%d ", G.arcs[i][j].adj);
}//for
printf("\n");
}//for
printf("vertices %d arcs %d\n", G.vexnum, G.arcnum);
}else{
printf("%s\n", "graph is not exist!");
}
}
//初始条件 图存在
//操作结果 销毁图
void DestoryGraph(MGraph* G){
if(G->vexs != NULL){
free(G->vexs);
printf("%s","vexs is free\n");
}
if(G->arcs != NULL){
for(int i = 0; i < G->vexnum; i++){
free(G->arcs[i]);
}
free(G->arcs);
printf("%s","arcs is free\n");
}
free(G);
printf("%s","G is free\n");
}
//初始条件 图G存在, V是图的顶点
//操作结果 返回V的第一个邻接顶点,若没有返回为-1
int FirstAdjVex(MGraph G, int v){
for(int i = 0; i < G.vexnum; i++){
//无权图
if(G.arcs[v][i].adj == 1)
return i;
}
return -1;
}
//初始条件 图G存在, V是图的顶点, w是v的邻接矩阵
//操作结果 返回V的相对于w下一个邻接顶点,若w是v的最后一个邻接顶点则返回为-1
int NextAdjVex(MGraph G, int v, int w){
for(int i = w+1; i < G.vexnum; i++){
//无权图
if(G.arcs[v][i].adj == 1)
return i;
}
return -1;
}
//初始条件
//操作结果 输出访问结点的信息
void Visit(int v){
printf("V%d -> ", v);
}
图遍历方法声明和实现 C语言
- 遍历函数声明
void DFSTraverse(MGraph, int*);
void DFS(MGraph, int, int*); //深度遍历 递归
void DFSTraverse_Stack(MGraph, int*); //深度遍历 栈
void BFSTraverse_queue(MGraph, int*); //广度遍历 队列
- 遍历函数实现
//初始条件 图存在, 访问标志数组
//操作结果 深度变量图
void DFSTraverse(MGraph G, int* visited){
for(int v = 0; v < G.vexnum; ++v) visited[v] = false; //初始化visited数组
for(int v = 0; v < G.vexnum; ++v) //对于连通无向图,不需要此循环,直接从一个顶点出发就能变量所有顶点
if(!visited[v]) DFS(G, v, visited);
}
//初始条件 图存在, v是图的顶点, 访问标志数组
//深度遍历的递归函数
void DFS(MGraph G, int v, int* visited){
visited[v] = true; //标记顶点v
Visit(v); //访问顶点v
for(int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w))
if(!visited[w]) DFS(G, w, visited);
}
//初始条件 图存在, v是图的顶点, 访问标志数组
//深度遍历的非递归函数,用栈
//注:非递归DFS遍历顺序可能和递归DFS遍历不同,是由于栈的特性导致
void DFSTraverse_Stack(MGraph G, int* visited){
//声明本函数需要使用的外部函数
extern void InitStack(SqStack*);
extern int StackEmpty(SqStack);
extern void Pop(SqStack*, int*);
extern void Push(SqStack*, int);
extern void DestoryStack(SqStack*);
SqStack* S = (SqStack*)malloc(sizeof(SqStack));
int* v = (int*)calloc(1, sizeof(int));
int* w = (int*)calloc(1, sizeof(int));
InitStack(S);
for(int i = 0; i < G.vexnum; i++) visited[i] = false;
for(int i = 0; i < G.vexnum&&visited[i] == false; i++){
//对于连通无向图不需要此循环,对非连通图避免漏顶点遍历
Push(S, *v); visited[*v] = true; //压入一个顶点栈
while(!StackEmpty(*S)){ //S是SqStack指针,而*S就是S指向的栈
Pop(S, v);
Visit(*v);
for(*w = FirstAdjVex(G, *v); *w >= 0; *w = NextAdjVex(G, *v, *w)){
//w是指针,*w是w指针所指向的值
if(!visited[*w]){
Push(S, *w);
visited[*w] = true;
}//if
}//for
}//while
}//for
//释放空间
DestoryStack(S);
free(v);
free(w);
}
void BFSTraverse_queue(MGraph G, int* visited){
//声明本函数需要使用的外部函数
extern void InitQueue(SqQueue*);
extern int QueueLength(SqQueue);
extern void EnQueue(SqQueue*, int);
extern void DeQueue(SqQueue*, int*);
extern void DestoryQueue(SqQueue*);
extern int QueueEmpty(SqQueue);
SqQueue* Q = (SqQueue*)malloc(sizeof(SqQueue));
int* v = (int*)calloc(1, sizeof(int));
int* u = (int*)calloc(1, sizeof(int));
int* w = (int*)calloc(1, sizeof(int));
for(int i = 0; i < G.vexnum; i++) visited[i] = false;
InitQueue(Q);
for(*v = 0; *v < G.vexnum; ++v){
if(!visited[*v]){
visited[*v] = true; Visit(*v);
EnQueue(Q, *v);
while(!QueueEmpty(*Q)){
DeQueue(Q, u);
for(*w = FirstAdjVex(G, *u); *w >= 0; *w = NextAdjVex(G, *u, *w)){
if(!visited[*w]){
visited[*w] = true;
Visit(*w);
EnQueue(Q, *w);
} //if
} //for
} // while
}//if
}//for
DestoryQueue(Q);
free(v); free(u); free(w);
}
- 图操作的例子
1.主函数
int main(){
MGraph *G = (MGraph*)malloc(sizeof(MGraph));
InitGraph(G);
PrintGraph(*G); //传递图的本身,而非图的地址
int* visited = (int*)calloc(G->vexnum, sizeof(int));
printf("DFS递归\n");
DFSTraverse(*G, visited);
printf("\n");
printf("DFS非递归\n");
DFSTraverse_Stack(*G, visited);
printf("\n");
printf("BFS队列\n");
BFSTraverse_queue(*G, visited);
printf("\n");
DestoryGraph(G);
free(visited);
return 0;
}
2.控制台输入
5 5 //顶点数和边数
0 1 2 3 4 //顶点信息
0 1 1 //弧三元组
0 2 1
1 3 1
1 4 1
2 3 1
控制台输出
参照
严蔚敏 吴伟名 米宁.数据结构(C语言版)[M].出版地:北京 出版社:清华大学出版社,出版年∶2018.