1.图常用的两种存储结构:邻接矩阵和邻接表。
2. 邻接矩阵结构和操作定义
SeqQueue.h
//功能:邻接矩阵图的广度遍历用到的队列结构体
#define QUEUE_MAXSIZE 256
typedef struct{
int Data[QUEUE_MAXSIZE]; //QUEUE_MAXSIZE在GraphTest.cpp文件中定义
int head;
int tail;
}SeqQueue;
//队列相关操作
void QueueInit(SeqQueue *Q){
Q->head=Q->tail = 0;
}
//因为判断空函数不设计改变队列Q,所以参数不是指针变量
int QueueIsEmpty(SeqQueue *Q){
return (Q->head == Q->tail);
}
int QueueIsFull(SeqQueue *Q){
return ((Q->tail + 1) %QUEUE_MAXSIZE == Q->head);
}
int QueueIn(SeqQueue *Q, int ch){
if(QueueIsFull(Q)){
printf("队列已满,无法再插入!!");
return 0;
}
Q->Data[Q->tail] = ch;
Q->tail = (Q->tail + 1)%QUEUE_MAXSIZE;
return 1;
}
int QueueOut(SeqQueue *Q, int *ch){
if(QueueIsEmpty(Q)){
printf("队列已空!!");
return 0;
}
*ch = Q->Data[Q->head];
Q->head = (Q->head + 1)%QUEUE_MAXSIZE;
return 1;
}
AdjMatrixGraph.h
#include"SeqQueue.h"
#define VERTEX_MAX 26 //图的最大顶点数,26个字母
#define MAXVALUE 32767 //表示两点间不构成边
//Prim算法用到
#define USED 0 //已使用,加入U集合
#define NOADJ -1 //非邻接点
//功能:邻接矩阵结构体
typedef struct{
char Vertex[VERTEX_MAX]; //保存顶点信息
int Endges[VERTEX_MAX][VERTEX_MAX]; //保存边的权
int isTrav[VERTEX_MAX]; //顶点遍历标识
int VertexNum; //顶点总数
int EndgeNum; //边总数
int GraphType; //图的类型
}MatrixGraph;
/*--------------------------函数原型声明 start----------------------*/
void CreateMatrixGraph(MatrixGraph *G); //功能:创建邻接矩阵图
void OutMatrix(MatrixGraph *G); //功能:输出邻接矩阵图
void BFSTraverse(MatrixGraph *G); //功能:广度优先遍历主函数
void BFSM(MatrixGraph *G, int k); //功能:广度优先遍历具体实现
void DFSTraverse(MatrixGraph *G); //功能:深度优先遍历主函数
void DFSM(MatrixGraph *G, int k); //功能:深度优先遍历具体实现
void Prim(MatrixGraph G); //功能:Prim最小生成树算法具体实现
void Dijkstra(MatrixGraph G); //功能:Dijkstra最短路径算法具体实现
/*--------------------------函数原型声明 end----------------------*/
/*--------------------------函数具体实现 start----------------------*/
//功能:创建邻接矩阵图
void CreateMatrixGraph(MatrixGraph *G){
char start, end;
int i,j,k;
int weight;
printf("请输入生成图的类型(0:无向图, 1:有向图):");
fflush(stdin);
scanf("%d", &G->GraphType);
printf("请输入图的顶点数和边数:");
fflush(stdin);
scanf("%d %d", &G->VertexNum, &G->EndgeNum);
for(i=0; i<G->VertexNum; i++) //清空邻接矩阵
for(j=0; j<G->VertexNum; j++)
G->Endges[i][j] = MAXVALUE;
printf("请输入各顶点信息:\n");
for(i=0; i<G->VertexNum; i++){
printf("请输入第%d个顶点的信息:", i+1);
fflush(stdin);
scanf("%c", &(G->Vertex[i]));
}
printf("请输入构成各边的两个顶点及权值:\n");
for(k=0; k<G->EndgeNum; k++){
printf("请输入第%d条边的两个顶点及权值(用空格分隔):", k+1);
fflush(stdin);
scanf("%c %c %d", &start, &end, &weight);
for(i=0; start!=G->Vertex[i]; i++);
for(j=0; end!=G->Vertex[j]; j++);
G->Endges[i][j] = weight;
if(G->GraphType == 0)
G->Endges[j][i] = weight;
}
return;
}
//功能:输出邻接矩阵图
void OutMatrix(MatrixGraph *G){
int i, j;
for(i=0; i<G->VertexNum; i++)
printf("\t%c", G->Vertex[i]);
printf("\n");
for(i=0; i<G->VertexNum; i++){
printf("%c\t", G->Vertex[i]);
for(j=0; j<G->VertexNum; j++){
if(G->Endges[i][j] == MAXVALUE)
printf("∞\t");
else
printf("%d\t", G->Endges[i][j]);
}
printf("\n");
}
return;
}
//功能:广度优先遍历主函数
void BFSTraverse(MatrixGraph *G){
int i;
for(i=0; i<G->VertexNum; i++)
G->isTrav[i] =0;
printf("广度优先遍历节点:");
for(i=0; i<G->VertexNum; i++)
if(!G->isTrav[i])
BFSM(G, i);
printf("\n");
}
//功能:广度优先遍历具体实现
void BFSM(MatrixGraph *G, int k){
int i,j;
SeqQueue Q;
QueueInit(&Q);
G->isTrav[k] = 1;
printf("->%c", G->Vertex[k]);
QueueIn(&Q, k);
while(!QueueIsEmpty(&Q)){
QueueOut(&Q, &i);
for(j=0; j<G->VertexNum; j++)
if(G->Endges[i][j] != MAXVALUE && !G->isTrav[j]){
G->isTrav[j] = 1;
printf("->%c", G->Vertex[j]);
QueueIn(&Q, j);
}
}
}
//功能:深度优先遍历主函数
void DFSTraverse(MatrixGraph *G){
int i;
for(i=0; i<G->VertexNum; i++)
G->isTrav[i] = 0;
printf("深度优先遍历节点:");
for(i=0; i<G->VertexNum; i++)
if(!G->isTrav[i])
DFSM(G, i);
printf("\n");
}
//功能:深度优先遍历具体实现(递归)
void DFSM(MatrixGraph *G, int k){
int i,j;
G->isTrav[k] = 1;
printf("->%c",G->Vertex[k]);
for(j=0; j<G->VertexNum; j++)
if(G->Endges[k][j] != MAXVALUE && !G->isTrav[j])
DFSM(G, j);
}
//功能:Prim最小生成树算法具体实现
void Prim(MatrixGraph G){
int i,j,k,min,sum=0;
//Prim算法两个辅助数组
int weight[VERTEX_MAX]; //保存tmpvertex中对应邻接边的权值
char tmpvertex[VERTEX_MAX]; //保存邻接顶点信息
//初始化:保存邻接矩阵中的一行数据,即0号顶点的邻接顶点、权值
for(i=1; i<G.VertexNum; i++){
weight[i] = G.Endges[0][i];
if(weight[i] == MAXVALUE)
tmpvertex[i] = NOADJ; //非邻接点
else
tmpvertex[i] = G.Vertex[0]; //邻接点
}
tmpvertex[0] = USED;
weight[0] = MAXVALUE;
//生成最小生成树:即包含所有顶点
for(i=1; i<G.VertexNum; i++){
min = weight[0];
k=i;
for(j=1; j<G.VertexNum; j++)
if(weight[j] < min && tmpvertex[j]!=0){
min = weight[j];
k=j;
}
sum +=min;
printf("(%c,%c),", tmpvertex[k],G.Vertex[k]);
tmpvertex[k] = USED;
weight[k] = MAXVALUE;
for(j=0; j<G.VertexNum; j++)
if(G.Endges[k][j] < weight[j] && tmpvertex[j] != 0){
weight[j] = G.Endges[k][j];
tmpvertex[j] = G.Vertex[k];
}
}
printf("\n最小生成树的总权值为:%d\n", sum);
}
//功能:Dijkstra最短路径算法具体实现
void Dijkstra(MatrixGraph G){
//Dijkstra算法辅助数组
int weight[VERTEX_MAX];
int path[VERTEX_MAX];
int tmpvertex[VERTEX_MAX];
int i,j,k,v0,min;
printf("\n请输入源点的编号:");
fflush(stdin);
scanf("%d", &v0);
v0--; //编号减1(因为数组从0开始)
//初始辅助数组
for(i=0; i<G.VertexNum;i++){
weight[i] = G.Endges[v0][i]; //保存最小权值
if(weight[i]<MAXVALUE && weight[i] > 0) //有效权值
path[i] = v0;
tmpvertex[i] =0;
}
tmpvertex[v0] = 1; //将顶点v0添加到集合U中
weight[v0] = 0; //将源顶点的权值设为0
for(i=0; i<G.VertexNum; i++){
min = MAXVALUE;
k = v0;
for(j=0;j<G.VertexNum;j++)
if(tmpvertex[j] == 0 && weight[j]<min){
min = weight[j];
k = j;
}
tmpvertex[k] = 1;
for(j=0; j<G.VertexNum; j++)
if(tmpvertex[j] == 0 && weight[k] + G.Endges[k][j] < weight[j]){
weight[j] = weight[k] + G.Endges[k][j];
path[j] = k;
}
}
//输出结果
printf("\n顶点%c到各顶点的最短路径为(终点 < 源点):\n", G.Vertex[v0]);
for(i=0; i<G.VertexNum; i++){
if(tmpvertex[i]==1){
k=i;
while(k!=v0){
printf("%c < ", G.Vertex[k]);
k = path[k]; //上一个顶点
}
printf("%c\n", G.Vertex[k]);
}
else
printf("%c<-%c:无路径\n", G.Vertex[i], G.Vertex[v0]);
}
}
/*--------------------------函数具体实现 end----------------------*/
3. 邻接表结构和操作定义
AdjListGraph.h
#define VERTEX_MAX 20
//功能:邻接表边的结构体
typedef struct edgeNode{
int Vertex; //顶点序号
int weight; //权值
struct edgeNode *next; //指向下一个顶点
}EdgeNode;
//功能:图的邻接表存储结构体
typedef struct{
EdgeNode *AdjList[VERTEX_MAX];
int VertexNum;
int EndgeNum;
int GraphType;
}ListGraph;
/*--------------------------函数原型声明 start----------------------*/
void CreateListGraph(ListGraph *G); //功能:创建邻接表图
void OutList(ListGraph *G); //功能:输出表图
/*--------------------------函数原型声明 end----------------------*/
/*--------------------------函数具体实现 start----------------------*/
//功能:创建表图
void CreateListGraph(ListGraph *G){
int i, weight;
int start, end;
EdgeNode *s;
printf("请输入生成图的类型(0:无向图, 1:有向图):");
fflush(stdin);
scanf("%d", &G->GraphType);
printf("请输入图的顶点数和边数:");
fflush(stdin);
scanf("%d %d", &G->VertexNum, &G->EndgeNum);
for(i=0; i<G->VertexNum; i++) //将图中各顶点指针清空
G->AdjList[i] = NULL;
for(i=1; i<=G->EndgeNum; i++){
printf("请输入第%d条边的两个顶点及权值:", i);
fflush(stdin);
scanf("%d %d %d", &start, &end, &weight);
s = (EdgeNode *)malloc(sizeof(EdgeNode));
if(s==NULL){
printf("申请内存失败!!");
return ;
}
s->next = G->AdjList[start]; //头插法,将顶点插入到链表中
s->weight = weight;
s->Vertex = end;
G->AdjList[start] = s;
if(G->GraphType == 0){
s = (EdgeNode *)malloc(sizeof(EdgeNode));
if(s==NULL){
printf("申请内存失败!!");
return ;
}
s->next = G->AdjList[end];
s->weight = weight;
s->Vertex = start;
G->AdjList[end] = s;
}
}
return;
}
//功能:输出表图
void OutList(ListGraph *G){
int i;
EdgeNode *s;
for(i=1; i<=G->VertexNum; i++){
printf("顶点%d", i);
s = G->AdjList[i];
while(s){
printf("->%d(%d)",s->Vertex, s->weight);
s = s->next;
}
printf("\n");
}
return;
}
/*--------------------------函数具体实现 end----------------------*/
4.图操作测试函数
GraphTest.cpp
#include<stdio.h>
#include<stdlib.h>
#define QUEUE_MAXSIZE 30 //SeqQueue.h头文件中队列元素最大值
#include"AdjListGraph.h"
#include"AdjMatrixGraph.h"
int main(){
int select;
ListGraph LG;
MatrixGraph G;
do{
printf("---------------------------\n");
printf("1.用邻接矩阵法创建图 2.输出邻接矩阵\n");
printf("3.用邻接表法创建图 4.输出邻接表\n");
printf("5.广度优先遍历邻接矩阵图 6.深度优先遍历邻接矩阵图\n");
printf("7.求邻接矩阵图的最小生成树 8.求邻接矩阵图指定顶点到其他顶点的最短路径\n");
printf("0.退出\n");
printf("请选择执行的操作序号:");
//select = getch();
fflush(stdin);
scanf("%d", &select);
switch(select){
case 1:
CreateMatrixGraph(&G);
break;
case 2:
printf("邻接矩阵数据如下:\n");
OutMatrix(&G);
break;
case 3:
CreateListGraph(&LG);
break;
case 4:
printf("邻接矩阵数据如下:\n");
OutList(&LG);
break;
case 5:
BFSTraverse(&G);
break;
case 6:
DFSTraverse(&G);
break;
case 7:
printf("构成最小生成树的边如下:\n");
Prim(G);
break;
case 8:
printf("最短路径算法开始执行:\n");
Dijkstra(G);
break;
}
}while(select != 0);
system("pause");
return 1;
}