#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<time.h>
#define ERROR 0
#define OK 1
#define Overflow 2 //上溢
#define Underflow 3 //下溢
#define NotPresent 4 //元素不存在
#define Duplicate 5 //有重复元素
#define INFTY 10000 //路径的长度初始值
typedef int Status;
typedef int ElemType;
/***********************************************************************邻接矩阵的实现****************************************************************/
/*定义图结构体*/
typedef struct mGraph
{
ElemType **a; //邻接矩阵
int n; //图的当前顶点数
int e; //图的当前边数
int noEdge; //两顶点间无边时的值
}MGraph;
/*初始化*/
Status Init(MGraph *mg, int nSize, ElemType noEdgeValue)
{
mg->n = nSize;
mg->noEdge = noEdgeValue;
mg->e = 0;
mg->a = (ElemType**)malloc(nSize * sizeof(ElemType*));
if (!(mg->a)) return ERROR;
for (int i = 0; i < nSize; i++) //初始化邻接矩阵
{
mg->a[i] = (ElemType*)malloc(nSize * sizeof(ElemType));
for (int j = 0; j < mg->n; mg->a[i][j++] = mg->noEdge);
mg->a[i][i] = 0;
}
return OK;
}
/*撤销*/
void Destory(MGraph *mg)
{
for (int i = 0; i < mg->n; free(mg->a[i++])); //释放n个一维数组的存储空间
free(mg->a); //释放一维指针数组的存储空间
}
/*查*/
Status Exist(MGraph *mg, int u, int v)
{
if (u<0 || v<0 || u>mg->n - 1 || v>mg->n - 1 || u == v || mg->a[u][v] == mg->noEdge) return ERROR;
return OK;
}
/*增*/
Status Insert(MGraph *mg, int u, int v, ElemType w)
{
if (u<0 || v<0 || u>mg->n - 1 || v>mg->n - 1 || u == v ) return ERROR; //验证插入位置
if (mg->a[u][v] != mg->noEdge) return Duplicate; //验证插入边是否已存在
mg->a[u][v] = w; //插入新边
mg->e++; //边数自增1
return OK;
}
/*删*/
Status Remove(MGraph *mg,int u,int v)
{
if (u<0 || v<0 || u>mg->n - 1 || v>mg->n - 1 || u == v) return ERROR; //验证删除位置
if (mg->a[u][v] == mg->noEdge) return NotPresent; //验证删除边是否存在
mg->a[u][v] = mg->noEdge; //删除边
mg->e--; //边数自减1
return OK;
}
/*DFS深度优先遍历*/
void DFS(int v, int visited[], MGraph *mg)
{
printf("%d ", v);
visited[v] = 1; //给访问过的顶点打标记
for (int i = 0; i < (mg->n); i++)
if (Exist(mg, v, i) && visited[i] == 0)
DFS(i, visited, mg); //递归调用
}
void DFSGraph(MGraph *mg)
{
int *visited = (int *)malloc((mg->n) * sizeof(int));//动态创建标记数组的空间
for (int i = 0; i < mg->n; visited[i++] = 0); //初始化标记数组
for (int i = 0; i < mg->n; i++)
if (!visited[i])
DFS(i, visited, mg); //更新起始遍历的顶点
free(visited); //释放临时空间
printf("\n");
}
/*BFS宽度优先遍历*/
typedef struct queue //队列结构体定义
{
int front; //队列首部元素的序号
int rear; //队列尾部元素的序号
int maxSize; //队列容纳的最大值
ElemType *element; //队列元素组成的数组
}Queue;
void Create(Queue *Q, int mSize)//队列初始化
{
Q->maxSize = mSize;
Q->front = Q->rear = 0;
Q->element = (ElemType *)malloc(sizeof(ElemType)*mSize);
}
void DestoryQueue(Queue *Q)//队列撤销
{
Q->maxSize = 0;
free(Q->element);
Q->rear = Q->front = 0;
}
int IsEmpty(Queue *Q)//判断队列是否为空
{
return Q->front == Q->rear;
}
int IsFULL(Queue *Q)//判断队列是否已满
{
return (Q->rear + 1) % Q->maxSize == Q->front;
}
Status EnQueue(Queue *Q, ElemType *x)//入队
{
if (IsFULL(Q)) return ERROR; //判断是否溢出
Q->rear = (Q->rear + 1) % Q->maxSize; //更新队尾元素序号
Q->element[Q->rear] = x; //插入的元素存入数组
return OK;
}
Status DeQueue(Queue *Q)//出队
{
if (IsEmpty(Q)) return ERROR;
Q->front = (Q->front + 1) % Q->maxSize; //更新队头元素序号
return OK;
}
Status Front(Queue *Q, ElemType *x)//获取队头元素
{
if (IsEmpty(Q)) return ERROR;
*x = Q->element[(Q->front + 1) % Q->maxSize];
return OK;
}
void BFS(int v, int visited[], MGraph *mg)
{
Queue q;
Create(&q, mg->n);
printf("%d ", v);
visited[v] = 1;
EnQueue(&q, v);
while (!IsEmpty(&q))
{
Front(&q, &v);
DeQueue(&q);
for (int i = 0; Exist(mg, v, i); i++) //遍历序号为v的顶点的所有邻接点
{
if (!visited[i]) //如果某邻接点未被访问就入队,作为本轮循环之后的循环的队头元素
{
visited[i] = 1;
printf("%d ", i);
EnQueue(&q, i);
}
}
}
}
void BFSGraph(MGraph *mg)
{
int *visited = (int *)malloc((mg->n) * sizeof(int));//动态创建标记数组的空间
for (int i = 0; i < mg->n; visited[i++] = 0); //初始化标记数组
for (int i = 0; i < mg->n; i++)
if (!visited[i]) BFS(i, visited, mg);
free(visited);
}
/***********************************************************************邻接表的实现*****************************************************************/
/*定义边结点结构体*/
typedef struct eNode
{
int adjVex; //与任意顶点u相邻接的顶点
ElemType w; //边的权值
struct eNode* nextArc; //指向下一个边结点
}ENode;
/*定义图结构体*/
typedef struct lGraph
{
int n; //图当前结点数
int e; //图当前边数
ENode **a;
}LGraph;
/*初始化*/
Status Init1(LGraph *lg, int nSize)
{
lg->n = nSize;
lg->e = 0;
lg->a = (ENode**)malloc(sizeof(ENode*)*nSize);
if (!lg->a) return ERROR;
else
{
for (int i = 0; i < lg->n; i++) lg->a[i] = NULL;
return OK;
}
}
/*撤销*/
void Destory1(LGraph *lg)
{
ENode *p, *q;
for (int i = 0; i < lg->n; i++)
{
p = lg->a[i]; //p指向顶点i的单链表的第一个边结点
q = p;
while (p) //释放顶点i的单链表中的所有边结点
{
p = p->nextArc;
free(p);
q = p;
}
}
free(lg->a); //释放一维数组指针的空间
}
/*查*/
Status Exist1(LGraph *lg, int u, int v)
{
ENode *p;
if (u<0 || v<0 || u>lg->n - 1 || v>lg->n - 1 || u == v) return ERROR;
p = lg->a[u];
while (p&&p->adjVex != v) p = p->nextArc;
if (!p) return ERROR;
return OK;
}
/*插入以u(起始),v(中止)为顶点权值为w的边*/
Status Insert1(LGraph *lg,int u,int v,ElemType w)
{
ENode *p;
if(u<0 || v<0 || u>lg->n - 1 || v>lg->n - 1 || u == v) return ERROR;
if (Exist(lg, u, v)) return Duplicate;
p = (ENode *)malloc(sizeof(ENode));
/*新结点的初始化*/
p->adjVex = v;
p->w = w;
/*插入操作*/
p->nextArc = lg->a[u]; //新结点插入单链表最前面
lg->a[u] = p;
/*数目更新*/
lg->e++;
return OK;
}
/*删*/
Status Remove1(LGraph *lg, int u, int v)
{
ENode *p, *q;
if (u<0 || v<0 || u>lg->n - 1 || v>lg->n - 1 || u == v) return ERROR;
p = lg->a[u], q = NULL;
while (p&&p->adjVex != v) //搜索以验证是否存在删除边
{
q = p;
p = p->nextArc;
}
if (!p) return NotPresent; //p为空则不存在待删除边
if (q) q->nextArc = p->nextArc; //从单链表中删除该边
else lg->a[u] = p->nextArc;
free(p);
lg->e--;
return OK;
}
/*DFS深度优先遍历*/
void DFS1(int v, int visited[], LGraph *lg)
{
ENode *w;
printf("%d ", v);
visited[v] = 1; //给访问过的顶点打标记
for (w = lg->a[v]; w; w = w->nextArc)
if (!visited[w->adjVex])
DFS(w->adjVex, visited, lg);
}
void DFSGraph1(LGraph *lg)
{
int *visited = (int *)malloc((lg->n) * sizeof(int));//动态创建标记数组的空间
for (int i = 0; i < lg->n; visited[i++] = 0); //初始化标记数组
for (int i = 0; i < lg->n; i++)
if (!visited[i]) DFS(i, visited, lg); //更新起始遍历的顶点
free(visited); //释放临时空间
}
/*BFS宽度优先遍历*/
void BFS1(int v, int visited[], LGraph *lg)
{
ENode *w;
Queue q;
Create(&q, lg->n);
printf("%d ", v);
visited[v] = 1;
EnQueue(&q, v);
while (!IsEmpty(&q))
{
Front(&q, &v);
DeQueue(&q);
for (w = lg->a[v]; w;w=w->nextArc) //遍历序号为v的顶点的所有邻接点
{
if (!visited[w->adjVex]) //如果某邻接点未被访问就入队,作为本轮循环之后的循环的队头元素
{
visited[w->adjVex] = 1;
printf("%d ", w->adjVex);
EnQueue(&q, w->adjVex);
}
}
}
}
void BFSGraph1(LGraph *lg)
{
int *visited = (int *)malloc((lg->n) * sizeof(int));//动态创建标记数组的空间
for (int i = 0; i < lg->n; visited[i++] = 0); //初始化标记数组
for (int i = 0; i < lg->n; i++)
if (!visited[i]) BFS(i, visited, lg);
free(visited);
}
/***********************************************************************智能交通*********************************************************************/
int Choose(int *d, int *s, int n)
{
ElemType min=INFTY; //最小路径长度初始化为INITY
int minpos=-1; //前驱结点初始化序号为-1
for (int i = 0; i < n; i++) //选出最短的d[i]
if (d[i] < min && !s[i])
{
min = d[i];
minpos = i;
}
return minpos; //返回序号
}
Status Dijkstra(int v,int u,MGraph *mg)
{
int k, *s = (int*)malloc((mg->n) * sizeof(int)),*path= (int*)malloc((mg->n) * sizeof(int));
ElemType *d = (ElemType*)malloc((mg->n) * sizeof(ElemType)), pass[20] = {0};
if (v<0 || v>mg->n - 1)
return ERROR;
for (int i = 0; i < mg->n; i++) //初始化
{
s[i] = 0; //s数组记录最短路径的确定状态
d[i] = mg->a[v][i]; //d数组存储v到下标对应序号的顶点的最短路径长度,如d[i]代表v到i的最短路径的长度
//printf("%d ", d[i]);
if (i != v && d[i] < INFTY) path[i] = v; //设置前驱结点
else path[i] = -1; //无前驱结点的值是-1
}
s[v] = -1;
d[v] = 0; //v顶点到v顶点的距离是0
for (int i = 1; i < mg->n-1; i++)
{
k = Choose(d, s, mg->n); //选出当前最短的d[i],并获取下标
if (k == -1) continue;
s[k] = 1;
for(int j=0;j<mg->n;j++) //每一轮外循环都要进行一次内循环来更新d和path
if (!s[j] && d[k] + mg->a[k][j] < d[j])
{
d[j] = d[k] + mg->a[k][j];
path[j] = k;
}
}
k = 0;
printf(">>>从%d号地点到%d号地点的最短路径是:", v, u); //把路径输出
for (int i = u; i != v; i = path[i]) pass[k++]=i;
for(;k>0;k--) printf("%d -> ", pass[k]);
printf("%d", u);
printf("\n>>>最短距离是:%d\n", d[u]); //最短距离输出
free(s); //释放动态空间
free(path);
free(d);
return OK;
}
int main()
{
MGraph *mg = (MGraph*)malloc(sizeof(MGraph));
LGraph *lg = (LGraph*)malloc(sizeof(LGraph));
int nSize = 0,
noEdgeValue = 0,
u, v, w, operation = 0;
char judge,tmpbuf[] = { 0 };
_tzset(); // 初始化时区
_strdate(tmpbuf);
printf("当前时间: %s\n", tmpbuf);
system("title MADE BY YQC");
label:
printf("*1.邻接矩阵实现图\n*2.邻接表实现图\n*3.智能交通\n——请选择:");
scanf("%d", &operation);
switch (operation)
{
case 1:
system("CLS");
while (1)
{
u = 0; v = 0;
printf("###请输入你要进行的操作(1.初始化 2.搜索 3.插入 4.删除 5.撤销 6.退出程序 7.DFS 8.BFS 9.返回首页):");
scanf("%d", &operation);
switch (operation)
{
case 1:
printf("请输入要创建的顶点数目:");
scanf("%d", &nSize);
if (Init(mg, nSize, noEdgeValue)) printf("初始化成功……\n");
else printf("WARNING:初始化失败\n");
break;
case 2:
printf("请输入起始顶点的序号:");
scanf("%d", &u);
printf("请输入中止顶点的序号:");
scanf("%d", &v);
if (Exist(mg, u, v) == 1) printf("从%d号顶点到%d号顶点存在边\n", u, v);
else if (Exist(mg, u, v) == 4)
printf("该边已经被删除");
else printf("这两个结点不存在边\n");
break;
case 3:
printf("请输入起始顶点的序号:");
scanf("%d", &u);
printf("请输入中止顶点的序号:");
scanf("%d", &v);
printf("请输入边的权值:");
scanf("%d", &w);
if (Insert(mg, u, v, w) == OK) printf("插入成功\n");
else if (Insert(mg, u, v, w) == Duplicate) printf("已存在该边\n");
else printf("WARNING:插入失败\n");
break;
case 4:
printf("请输入起始顶点的序号:");
scanf("%d", &u);
printf("请输入中止顶点的序号:");
scanf("%d", &v);
if (Remove(mg, u, v)==OK) printf("删除成功\n");
else if (Remove(mg, u, v) == NotPresent) printf("待删除边不存在\n");
else printf("WARNING:删除失败\n");
break;
case 5:
Destory(mg);
break;
case 6:
exit(0);
case 7:
printf("深度遍历路径如下:\n");
DFSGraph(mg);
break;
case 8:
printf("宽度遍历路径如下:\n");
BFSGraph(mg);
printf("\n");
break;
case 9:
while (1)
{
printf("当前图将会被注销,是否继续(Y/N):\n");
scanf("%c", &judge);
if (judge == 'y' || judge == 'Y')
{
system("CLS");
if(mg->n)
Destory(mg);
goto label;
}
if (judge == 'n' || judge == 'N') break;
}
break;
label1:
break;
default:
printf("WARNING:输入异常!!!\n");
break;
}
}
case 2:
system("CLS");
while (1)
{
u = 0; v = 0;
printf("###请输入你要进行的操作(1.初始化 2.搜索 3.插入 4.删除 5.撤销 6.退出程序 7.DFS 8.BFS 9.返回首页):");
scanf("%d", &operation);
switch (operation)
{
case 1:
printf("请输入要创建的顶点数目:");
scanf("%d", &nSize);
if (Init1(lg, nSize)) printf("初始化成功……\n");
else printf("WARNING:初始化失败\n");
break;
case 2:
printf("请输入起始顶点的序号:");
scanf("%d", &u);
printf("请输入中止顶点的序号:");
scanf("%d", &v);
if (Exist1(lg, u, v) == 1) printf("从%d号顶点到%d号顶点存在边\n", u, v);
else printf("这两个结点不存在边\n");
break;
case 3:
printf("请输入起始顶点的序号:");
scanf("%d", &u);
printf("请输入中止顶点的序号:");
scanf("%d", &v);
printf("请输入边的权值:");
scanf("%d", &w);
if (Insert1(lg, u, v, w)==OK) printf("插入成功\n");
else if (Insert1(lg, u, v, w) == Duplicate) printf("已存在该边\n");
else printf("WARNING:插入失败\n");
break;
case 4:
printf("请输入起始顶点的序号:");
scanf("%d", &u);
printf("请输入中止顶点的序号:");
scanf("%d", &v);
if (Remove1(lg, u, v) == OK) printf("删除成功\n");
else if (Remove1(lg, u, v) == NotPresent) printf("待删除边不存在\n");
else printf("WARNING:删除失败\n");
break;
case 5:
Destory1(lg);
break;
case 6:
exit(0);
case 7:
printf("深度遍历路径如下:\n");
DFSGraph1(lg);
break;
case 8:
printf("宽度遍历路径如下:\n");
BFSGraph1(lg);
printf("\n");
break;
case 9:
while (1)
{
printf("当前图将会被注销,是否继续(Y/N):\n");
scanf("%c", &judge);
if (judge == 'y' || judge == 'Y')
{
system("CLS");
if (lg->a)
Destory1(lg);
goto label;
}
if (judge == 'n' || judge == 'N') break;
}
break;
default:
printf("WARNING:输入异常!!!\n");
break;
}
}
case 3:
system("CLS");
label3:
printf(">在创建方案前需要获取一些数据~~~\n");
printf(">请输入地点的数目:");
scanf("%d", &nSize);
if (Init(mg, nSize, INFTY)) printf(">初始化成功……\n");
else printf(">WARNING:初始化失败\n");
while (1)
{
printf(" 1.插入路径\n 2.计算最短路径\n 3.显示当前图\n 4.重新初始化\n>>请选择你要进行的操作:");
scanf("%d", &operation);
switch (operation)
{
case 1:
system("CLS");
printf(">>>请输入起始地点的序号:");
scanf("%d", &u);
printf(">>>请输入中止地点的序号:");
scanf("%d", &v);
printf(">>>请输入两地点间的距离(km):");
scanf("%d", &w);
if (Insert(mg, u, v, w) == OK) printf("——新添加从%d号地点到%d号地点的路径\n",u,v);
else if (Insert(mg, u, v, w) == Duplicate) printf("——已存在该路径\n");
else printf("——WARNING:添加失败\n");
break;
case 2:
system("CLS");
printf("请输入起点的序号:");
scanf("%d", &v);
printf("请输入终点的序号:");
scanf("%d", &u);
Dijkstra(v, u, mg);
break;
case 3:
system("CLS");
printf("当前图遍历如下:\n");
DFSGraph(mg);
break;
case 4:
system("CLS");
while (1)
{
printf("当前图将会被注销,是否继续(Y/N):\n");
scanf("%c", &judge);
if (judge == 'y' || judge == 'Y')
{
system("CLS");
Destory(mg);
goto label3;
}
if (judge == 'n' || judge == 'N') break;
}
break;
default:
system("CLS");
printf("WARNING:输入异常!!!请输入合理代号\n");
break;
}
}
default:
printf("WARNING:输入异常!!!\n");
break;
}
return 0;
}
【数据结构(C语言)】图论
最新推荐文章于 2022-09-25 10:37:05 发布