1 作业题目
7.1 试基于图的深度优先搜索策略写一算法,判别以邻接表方式存储的有向图中是否存在由顶点vi到顶点vj的路径(i<>j)。注意:算法中涉及的图的基本操作必须在此存储结构上实现。
7.2 同7.1 题要求,试基于广度优先搜索策略写一算法。
7.3 采用邻接表存储结构,编写一个判别无向图中任意给定的两个顶点之间是否存在一条长度为k的简单路径的算法。
7.4 输入任意的一个网,用普里姆(Prim)算法构造最小生成树
2 作业题目解答
7.1
试基于图的深度优先搜索策略写一算法,判别以邻接表方式存储的有向图中是否存在由顶点vi到顶点vj的路径(i<>j)。注意:算法中涉及的图的基本操作必须在此存储结构上实现。
答:
算法思想:对于深度优先采用递归的模式,不断调用下个结点,当这一过程执行到底,不再有结点的时候,开始回溯。同时需要设立一个数组来记录是否被调用过的信息
源代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAXN 100 //最大边数
typedef struct ArcNode {//弧结点
int ajdVex; //弧终点指针位置
ArcNode* next; //下一条弧的指针
};
typedef struct Node {//顶点结点
ArcNode* Arc; //指向依附该顶点的弧指针
};
typedef struct Graph {//邻接表
Node adjlist[MAXN]; //点集
bool visited[MAXN]; //是否被遍历
int n, m; //顶点数和弧数
};
Graph* G = (Graph*)malloc(sizeof(Graph));
int i, j, k;
bool hasPath = false;
void createLink() {//创建邻接表
printf("请输入顶点数n 弧数m:");
scanf("%d %d", &G->n, &G->m);
printf("创建的所有点:");
for (i = 0; i < G->n; i++) { G->adjlist[i].Arc = 0; printf("V%d ", i); }printf("\n");
for (j = 0; j < G->m; j++) {
printf("第%d条弧起点编号、终点编号:", j + 1);
scanf("%d %d", &i, &k);
ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
p->ajdVex = k; //将边所指向的点编号赋值
p->next = G->adjlist[i].Arc;
G->adjlist[i].Arc = p;
}
}
void setFlase() {//visited置零
hasPath = false;
for (i = 0; i < G->n; i++) G->visited[i] = false;
}
//深度优先算法
int DFS(ALGraph G, int n, char a, char b, int& flag) {
DFSvisited[n] = 1;
ArcNode* p;
p = G.vertices[n].firstarc;
while (p != NULL) {
if (DFSvisited[p->adjvex] == 0) {
if (G.vertices[p->adjvex].data == b) {
printf("%c到%c有通路\n", a, b);
flag = 1;
}
DFS(G, p->adjvex, a, b, flag);
}
p = p->nextarc;
}
return 1;
}
void existPath(int d, int z) {//两点是否连通
G->visited[d] = true;
ArcNode* p = G->adjlist[d].Arc;
if (d == z)hasPath = true;
while (p) {
if (p->ajdVex == z)hasPath = true;
if (!G->visited[p->ajdVex])existPath(p->ajdVex, z);
p = p->next;
}
}
void print_Graph() {//输出邻接表
ArcNode* p;
for (i = 0; i < G->n; i++) {
p = G->adjlist[i].Arc;
printf("V%d", i);
while (p) {
printf("->V%d", p->ajdVex);
p = p->next;
}printf("\n");
}
}
void print_Path(int d, int z) {//输出两点连接路径
ArcNode* p = G->adjlist[d].Arc;
printf("路径为:V%d", d);
while (p) {
printf("->V%d", p->ajdVex);
if (p->ajdVex == z)break;
p = G->adjlist[p->ajdVex].Arc;
}printf("\n");
}
int main() {
createLink();
while (true) {
printf("\n");
printf("请输入操作(1.打印信息 2.判断路径 3.退出):");
int choice; scanf("%d", &choice); setFlase();
if (choice == 1) print_Graph();
if (choice == 2) {
printf("请输入两点编号:"); scanf("%d %d", &i, &k); existPath(i, k);
if (hasPath) { printf("两点连通!\n"); print_Path(i, k); }
else printf("两点不连通!\n");
}
if (choice == 3)break;
}
return 0;
}
测试用例截屏
运行结果截屏:
7.2
同7.1 题要求,试基于广度优先搜索策略写一算法。
答:
源代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -1
#define TRUE 1
#define FALSE 0
typedef int Status;
#define MAXN 100 //最大边数
typedef struct ArcNode {//弧结点
int ajdVex; //弧终点指针位置
ArcNode* next; //下一条弧的指针
};
typedef struct Node {//顶点结点
ArcNode* Arc; //指向依附该顶点的弧指针
};
typedef struct Graph {//邻接表
Node adjlist[MAXN]; //点集
bool visited[MAXN]; //是否被遍历
int n, m; //顶点数和弧数
};
typedef struct QNode//链队列
{
int data;
struct QNode* next;
} QNode, * QueuePtr;
typedef struct
{
QueuePtr front; //对头指针
QueuePtr rear; //队尾指针
} LinkQueue;
Graph* G = (Graph*)malloc(sizeof(Graph));
int i, j, k;
bool hasPath = false;
Status InitQueue(LinkQueue& Q)
{
//构造一个空队列Q
Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
if (!Q.front)
exit(OVERFLOW);
Q.front->next = NULL;
return OK;
}
Status QueueEmpty(LinkQueue Q)
{
//判断队列是否为空
if (Q.front->next == NULL)
return TRUE;
return FALSE;
}
Status EnQueue(LinkQueue& Q, int e)
{
//插入元素e为Q的新的队尾元素
QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
if (!p)
return ERROR;
p->next = NULL;
p->data = e;
Q.rear->next = p;
Q.rear = p;
return OK;
}
Status DeQueue(LinkQueue& Q, int& e)
{
//若队列不空,则删除Q的队头元素,用e返回其值,并返回OK
if (Q.front == Q.rear)
return ERROR;
QueuePtr p;
p = Q.front->next;
e = p->data;
Q.front->next = p->next;
if (Q.rear == p)
Q.rear = Q.front;
free(p);
return OK;
}
void createLink() {//创建邻接表
printf("请输入顶点数n 弧数m:");
scanf("%d %d", &G->n, &G->m);
printf("创建的所有点:");
for (i = 0; i < G->n; i++) { G->adjlist[i].Arc = 0; printf("V%d ", i);
for (j = 0; j < G->m; j++) {
printf("第%d条弧起点编号、终点编号:", j + 1);
scanf("%d %d", &i, &k);
ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
p->ajdVex = k; //将边所指向的点编号赋值
p->next = G->adjlist[i].Arc;
G->adjlist[i].Arc = p;
}
}
void setFlase() {//visited置零
hasPath = false;
for (i = 0; i < G->n; i++) G->visited[i] = false;
}
void existPath(int d, int z) {//两点是否连通
G->visited[d] = true;
LinkQueue Q;
int u;
int v, w;
ArcNode* p;
InitQueue(Q);//置空的辅助队列Q
//广度优先判断是否存在路径
for (v = 0; v < G.vexnum; v++)
{
if (!visited[v])//v尚未访问
{
visited[v] = TRUE;
printf("%s ", G.vertices[v].data);
EnQueue(Q, v);//v入队列
while (!QueueEmpty(Q))
{
DeQueue(Q, u);//队头元素出队并置为u
p = G.vertices[u].firstarc;
while (p)
{
if (!visited[p->adjvex])
{
visited[p->adjvex] = TRUE;
printf("%s ", G.vertices[p->adjvex].data);
EnQueue(Q, p->adjvex);
}
p = p->nextarc;
}
}
}
}
}
void print_Graph() {//输出邻接表
ArcNode* p;
for (i = 0; i < G->n; i++) {
p = G->adjlist[i].Arc;
printf("V%d", i);
while (p) {
printf("->V%d", p->ajdVex);
p = p->next;
}printf("\n");
}
}
void print_Path(int d, int z) {//输出两点连接路径
ArcNode* p = G->adjlist[d].Arc;
printf("路径为:V%d", d);
while (p) {
printf("->V%d", p->ajdVex);
if (p->ajdVex == z)break;
p = G->adjlist[p->ajdVex].Arc;
}printf("\n");
}
int main() {
createLink();
while (true) {
printf("\n");
printf("请输入操作(1.打印信息 2.判断路径 3.退出):");
int choice; scanf("%d", &choice); setFlase();
if (choice == 1) print_Graph();
if (choice == 2) {
printf("请输入两点编号:"); scanf("%d %d", &i, &k); existPath(i, k);
if (hasPath) { printf("两点连通!\n"); print_Path(i, k); }
else printf("两点不连通!\n");
}
if (choice == 3)break;
}
return 0;
}
测试用例截图:
运行结果截图
7.3
采用邻接表存储结构,编写一个判别无向图中任意给定的两个顶点之间是否存在一条长度为k的简单路径的算法。
算法思路:在深度优先搜索上经行改进,每走一步就将步长加一,但步长到达k并且该节点和目标结点的值相等时则表示找到了。
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#define True 1
#define False 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define max_vertex_num 20
#define VertexType char//点类型
#define VRType int //边类型
#define maxsize 20
typedef int Status;
//typedef int bool;
void Visit(VertexType e) {
printf("%c", e);
}
typedef struct ArcNode {
int adjV;//边指向的点
struct ArcNode* next;
}ArcNode;//边
typedef struct VNode {
VertexType data;
ArcNode* firstarc;
}VNode,AdjList[max_vertex_num];
typedef struct {
int vernum, arcnum;
AdjList vers;
}ALGraph;
Status InitGraph(ALGraph* G) {
int i;
G->arcnum = 0;
G->vernum = 0;
for (i = 0; i < max_vertex_num; i++)
G->vers[i].firstarc = NULL;
return OK;
}
int LocateVex(ALGraph G, VertexType e) {
//定位元素为e的下标
int i;
for (i = 0; i < G.vernum; i++) {
if (G.vers[i].data == e) {
return i;
}
}
return -1;
}
Status CreateALG(ALGraph* G) {
//创建无向图的邻接表
int i, a, b;
char tmp[max_vertex_num];
char h, t;
ArcNode* p, * q;
InitGraph(G);
//printf("顶点数目:");
scanf("%d", &i);
G->vernum = i;
//printf("弧的数目:");
scanf("%d", &i);
G->arcnum = i;
//printf("各顶点信息:");
scanf("%s", tmp);
for (i = 0; i < G->vernum; i++)
G->vers[i].data = tmp[i];
//printf("请输入弧的信息,两顶点间,隔开");
for (i = 0; i < G->arcnum; i++)
{
scanf("%s", tmp);
h = tmp[0];
t = tmp[2];
a = LocateVex(*G, h);
b = LocateVex(*G, t);
if (a < 0 || b < 0)
return ERROR;
p = (ArcNode*)malloc(sizeof(ArcNode));
if (!p) exit(OVERFLOW);
p->adjV = b;
p->next = NULL;
if (G->vers[a].firstarc) {
for (q = G->vers[a].firstarc; q->next; q = q->next);
q->next = p;
}
else {
G->vers[a].firstarc = p;
}
p = (ArcNode*)malloc(sizeof(ArcNode));
if (!p) exit(OVERFLOW);
p->adjV = a;
p->next = NULL;
if(G->vers[b].firstarc){
for (q = G->vers[b].firstarc; q->next; q = q->next) {
q->next = p;
}
}
else{
G->vers[b].firstarc = p;
}
}
return OK;
}
//判断无向图是否存在路径为k
int visit[max_vertex_num];
int nodenum = 0;
Status ExistPath(ALGraph G, int v, int w, int k) {
ArcNode* p;
visit[v] = ++nodenum;
if (v == w && k == 0)
return True;
else if (k > 0) {
for (p = G.vers[v].firstarc; p; p = p->next) {
if (visit[p->adjV] == 0) {
if (ExistPath(G, p->adjV, w, k - 1))
return True;
else
visit[p->adjV] = 0; nodenum--;
}
else
continue;
}
}
return False;
}
int main() {
int i, j, k;
int cnt;
ALGraph G;
char tmp[20];
while (1) {
scanf("%s", tmp); //A-B,1
i = LocateVex(G, tmp[0]);
j = LocateVex(G, tmp[2]);
k = tmp[4] - '0';
for (cnt = 0; cnt < max_vertex_num; cnt++) visit[cnt] = 0;
nodenum = 0;
printf(" %c 到 %c 长度为 %d 的路径:%d", tmp[0], tmp[2], k, ExistPath(G, i, j, k));
//输出路径
printf("\t路径是:");
for (i = 1; i <= k + 1; i++) {
for (j = 0; j < G.vernum; j++) {
if (visit[j] == i) {
Visit(G.vers[j].data);
}
}
}
printf("\n");
}
return 0;
}
测试用例截图:
7.4
输入任意的一个网,用普里姆(Prim)算法构造最小生成树
#include <stdio.h>
#include <stdlib.h>
#define maxint 32767
typedef struct {
char vexs[100];
int arc[100][100];
int vernum, arcnum;
}AMGraph;
struct {
char adjvex;
int lowcost;
}closedge[100];
//已知顶点,获取编号
int LocateVex(AMGraph G, char v) {
for (int i = 0; i < G.vernum; ++i)
if (G.vexs[i] == v)
return i;
return -1;
}
void CreateUDN(AMGraph& G) {
int i, j, k;
printf("输入顶点数和边数(空格隔开)\n");
scanf("%d %d", &G.vernum, &G.arcnum);
printf("请输入顶点的值:");
for (i = 0; i < G.vernum; i++) {
printf("第%d个顶点数值:", i + 1);
scanf("%c\n", &G.vexs[i]);
//printf("\n");
}
for (i = 0; i < G.vernum; ++i) {
for (j = 0; j < G.vernum; ++j) {
G.arc[i][j] = maxint;//初始化
}
}
printf("\n");
printf("请输入权值和对应的编号(eg 12 a b)\n");
for ( k = 0; k < G.arcnum; k++) {
int weight;
char v1, v2;
printf("请输入第%d个:",k + 1);
scanf("%d %c %c", &weight,&v1,&v2);
i = LocateVex(G,v1);
j = LocateVex(G,v2);
G.arc[i][j] = weight;
G.arc[j][i] = G.arc[i][j];
}
}
int Min(AMGraph G) {
int i;
int index = -1;
int min = maxint;
for (i = 0; i < G.vernum; ++i) {
if (min > closedge[i].lowcost && closedge[i].lowcost != 0) {
min = closedge[i].lowcost;
index = i;
}
return index;
}
}
void prim(AMGraph G, char u) {
int i, j, k;
char u0, v0;
k = LocateVex(G, u);
for (j = 0; j < G.vernum; ++j) {
if (j != k) {
closedge[j].adjvex = u;
closedge[j].lowcost = G.arc[k][j];
}
}
closedge[k].lowcost = 0;
for (i = 1; i < G.vernum; ++i) {
k = Min(G);
u0 = closedge[k].adjvex;
v0 = G.vexs[k];
printf("arc %c --> %c", u0, v0);
closedge[k].lowcost = 0;
for (j = 0; j < G.vernum; ++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;
CreateUDN(G);
printf("\n");
prim(G, 'a');//指定顶点a
}
测试用例截图: