数据结构图的操作与实现c++

一、实验目的

1、图的邻接表和邻接矩阵存储

2、图的各种遍历算法实现

3、最小生成树的算法实现

4、最短路径的算法实现

二、使用仪器、器材

微机一台

操作系统:Win7及以上

编程软件:C/C++

三、实验内容及原理

利用图的邻接表或邻接矩阵存储结构设计并实现各种操作算法(任选一种存储结构来实现算法)。

1.图的邻接表和邻接矩阵存储

建立下图的邻接表或邻接矩阵,并输出之;

2.图的各种遍历算法实现

以0结点为起点实现上述图的深度优先和广度优先遍历算法;

3、最小生成树的算法实现

利用普里姆(Prim)算法或克鲁斯卡尔(Kruskal)算法求上图的最小生成树,算法实现代码必须有注释。

4、最短路径的算法实现

利用狄克斯特拉(Dijkstra)算法求上图中0结点到其它结点的最短路径,算法实现代码必须有注释。

四、实验过程原始数据记录

截屏及解读

1.建立下图的邻接表或邻接矩阵,并输出之;

邻接表

#include<iostream>
#include<queue>
using namespace std;
#define Maxint 32767   //极大值
constexpr auto MVNum = 100;      //最大顶点数

struct AMGraph
{
	char vexs[MVNum];   //顶点表
	int arcs[MVNum][MVNum];   //邻接矩阵
	int vexnum, arcnum;
};

int LocateVex(AMGraph G, char v)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.vexs[i] == v)
			return i;
	}
	cout << "顶点输入错误!" << endl;
	return -1;
}

void createUDN(AMGraph& G)
{
	cout << "请输入总顶点数:";
	cin >> G.vexnum;
	cout << "请输入总边数:";
	cin >> G.arcnum;

	cout << "请输入点的信息:" << endl;
	for (int i = 0; i < G.vexnum; i++)
		cin >> G.vexs[i];

	for (int i = 0; i < G.vexnum; i++)
		for (int j = 0; j < G.vexnum; j++)
			G.arcs[i][j] = Maxint;  //初始化邻接矩阵,边的权值均置为极大值

	for (int k = 0; k < G.arcnum; k++)
	{
		char v1, v2; //两顶点
		int w; //权值
		cout << "请输入第" << k + 1 << "条边的两个顶点及权值:";
		cin >> v1 >> v2 >> w;
		int i = LocateVex(G, v1);
		int j = LocateVex(G, v2);
		if (i != -1 && j != -1) //无向图
		{
			G.arcs[i][j] = w;
			G.arcs[j][i] = w;
		}
	}
}
int main()
{
	AMGraph G;
	createUDN(G);
	return 0;
}

2.以0结点为起点实现上述图的深度优先和广度优先遍历算法;

以下代码是在上面代码的基础上实现的

bool visited[MVNum];
//采用邻接矩阵表示图的深度优先搜索遍历
void DFS_AM(AMGraph G, int v)
{
	cout << 'v' << G.vexs[v];
	visited[v] = true;
	for (int w = 0; w < G.vexnum; w++)
	{
		if ((G.arcs[v][w] < Maxint) && (!visited[w]))
			DFS_AM(G, w);
	}
}

void TraDFS(AMGraph G)
{
	for (int i = 0; i < G.vexnum; i++)
		visited[i] = false;
	for (int i = 0; i < G.vexnum; i++)
	{
		if (!visited[i])
		{
			DFS_AM(G, i);
			cout << ' '; //看有多少个连通子图
		}

	}
}

//广度优先访问连通图
void BFS(AMGraph G, int v)
{
	cout << 'v' << G.vexs[v];
	visited[v] = true;
	queue<int> Q;
	Q.push(v);
	int u;
	while (!Q.empty())
	{
		u = Q.front();
		Q.pop();
		for (int w = 0; w < G.vexnum; w++)
		{
			if ((!visited[w]) && (G.arcs[u][w] < Maxint))
			{
				cout << "v" << G.vexs[w];
				visited[w] = true;
				Q.push(w);
			}
		}
	}
}

//G可能是非连通图
void TraBFS(AMGraph G)
{
	for (int i = 0; i < G.vexnum; i++)
		visited[i] = false;
	for (int i = 0; i < G.vexnum; i++)
	{
		if (!visited[i])
		{
			BFS(G, i);
			cout << ' '; //区分访问了多少个连通子图
		}
	}
}
int main()
{
	AMGraph G;
	createUDN(G);

	for (int i = 0; i < G.vexnum; i++)
		cout << '\t' << 'v' << G.vexs[i];
	cout << endl;
	for (int i = 0; i < G.vexnum; i++)
	{
		cout << 'v' << i << '\t';
		for (int j = 0; j < G.vexnum; j++)
			cout << G.arcs[i][j] << '\t';
		cout << endl;
	}

	cout << "\n请输入起点在顶点表中的序号(0为第一个):";
	int v;
	cin >> v;
	cout << "\n深度优先遍历图:" << endl;
	TraDFS(G);
	cout << endl;

	cout << "\n广度优先遍历图:" << endl;
	TraBFS(G);
	cout << endl;

	return 0;

 

3.利用普里姆(Prim)算法或克鲁斯卡尔(Kruskal)算法求上图的最小生成树,算法实现代码必须有注释。

#include<iostream>
#include<algorithm>
#define Maxint 32767   //极大值
using namespace std;
constexpr auto MVNum = 100;      //最大顶点数


struct AMGraph
{
	char vexs[MVNum];   //顶点表
	int arcs[MVNum][MVNum];   //邻接矩阵
	int vexnum, arcnum;
};

int LocateVex(AMGraph G, char v)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.vexs[i] == v)
			return i;
	}
	cout << "顶点输入错误!" << endl;
	return -1;
}

//普里姆算法
struct
{
	int adjvex;
	int lowcost;
}closedg[MVNum];

void MinSpanTree_Prim(AMGraph G, int u)
{
	int length = 0;  //带权路径长度
	int k = u;  //k为顶点u的下标
	for (int j = 0; j < G.vexnum; j++)  //对V-U的每一个顶点vj,初始化closedg[j]
	{
		if (j != k)
			closedg[j] = { u,G.arcs[k][j] };
	}
	closedg[k].lowcost = 0;
	for (int i = 1; i < G.vexnum; i++)  //选择其余n-1个顶点,生成n-1条边
	{
		int mincost = Maxint; //记录与U相连的最小边的顶点下标和最小边权值
		for (int j = 0; j < G.vexnum; j++)
		{
			if (closedg[j].lowcost > 0 && mincost > closedg[j].lowcost)
			{
				mincost = closedg[j].lowcost;
				k = j;
			}
		}
		//输出prim算法最小生成树形成路径
		cout << 'v' << G.vexs[k] << ':' << mincost << endl;
		length += mincost;

		closedg[k].lowcost = 0; 
		for (int j = 0; j < G.vexnum; j++) //新顶点并入U后重新选择最小边
		{
			if (G.arcs[k][j] < closedg[j].lowcost)
				closedg[j] = { G.vexs[k], G.arcs[k][j] };
		}
	}
	cout << "该路径的权值为:" << length << endl;; //输出最小权值
}

//克鲁斯卡尔算法
struct Edge
{
	char head;
	char tail; //边的头和尾
	int lowcost; //边上的权值
}edge[MVNum];

int Vexset[MVNum]; //辅助数组
void MiniSpanTree_Kruskal(AMGraph G)
{
	//冒泡排序
	for (int i = 0; i < G.arcnum; i++)	
	{
		for (int j = 0; j < G.arcnum - i - 1; j++)
		{
			if (edge[j].lowcost > edge[j + 1].lowcost)
			{
				Edge temp = edge[j];
				edge[j] = edge[j + 1];
				edge[j + 1] = temp;
			}
		}
	}

	for (int i = 0; i < G.vexnum; i++)
		Vexset[i] = i;  //各顶点自成一个连通分量
	for (int i = 0; i < G.arcnum; i++)
	{
		int v1 = LocateVex(G, edge[i].head);
		int v2 = LocateVex(G, edge[i].tail);  //起点和终点的下标
		int vs1 = Vexset[v1];
		int vs2 = Vexset[v2];	//获取边起点/终点所在的连通分量
		if (vs1 != vs2)
		{
			cout << 'v' << edge[i].head << "--" << 'v' << edge[i].tail << " 权值:" << edge[i].lowcost << endl; //输出此边
			for (int j = 0; j < G.vexnum; j++)
			{
				if (Vexset[j] == vs2)
					Vexset[j] = vs1;	//合并两个连通分量
			}
		}
	}
}

void createUDN(AMGraph& G)
{
	cout << "请输入总顶点数:";
	cin >> G.vexnum;
	cout << "请输入总边数:";
	cin >> G.arcnum;

	cout << "请输入点的信息(顶点表):" << endl;
	for (int i = 0; i < G.vexnum; i++)
		cin >> G.vexs[i];

	for (int i = 0; i < G.vexnum; i++)
		for (int j = 0; j < G.vexnum; j++)
			G.arcs[i][j] = Maxint;  //初始化邻接矩阵,边的权值均置为极大值

	for (int k = 0; k < G.arcnum; k++)
	{
		char v1, v2; //两顶点
		int w; //权值
		cout << "请输入第" << k + 1 << "条边的两个顶点及权值:";
		cin >> v1 >> v2 >> w;

		edge[k] = { v1,v2,w };

		int i = LocateVex(G, v1);
		int j = LocateVex(G, v2);
		if (i != -1 && j != -1) //无向图
		{
			G.arcs[i][j] = w;
			G.arcs[j][i] = w;
		}
	}
}

int main()
{
	AMGraph G;
	createUDN(G);

	int u;
	cout << "\n请输入起点在顶点表中的序号(0为第一个):";
	cin >> u;
	
	cout << "prim算法最小路径为:\n" << 'v' << G.vexs[u] << endl;
	MinSpanTree_Prim(G, u);

	cout << "\nKruskal算法合并边的过程为:" << endl;
	MiniSpanTree_Kruskal(G);

	return 0;
}

 

 

4.利用狄克斯特拉(Dijkstra)算法求上图中0结点到其它结点的最短路径,算法实现代码必须有注释。

#include<iostream>
using namespace std;
#define Maxint 32767   //极大值
constexpr auto MVNum = 100;      //最大顶点数

struct AMGraph
{
	char vexs[MVNum];   //顶点表
	int arcs[MVNum][MVNum];   //邻接矩阵
	int vexnum, arcnum;
};

int LocateVex(AMGraph G, char v)
{
	for (int i = 0; i < G.vexnum; i++)
	{
		if (G.vexs[i] == v)
			return i;
	}
	cout << "顶点输入错误!" << endl;
	return -1;
}

void createUDN(AMGraph& G)
{
	cout << "请输入总顶点数:";
	cin >> G.vexnum;
	cout << "请输入总边数:";
	cin >> G.arcnum;

	cout << "请输入点的信息:" << endl;
	for (int i = 0; i < G.vexnum; i++)
		cin >> G.vexs[i];

	for (int i = 0; i < G.vexnum; i++)
		for (int j = 0; j < G.vexnum; j++)
			G.arcs[i][j] = Maxint;  //初始化邻接矩阵,边的权值均置为极大值

	for (int k = 0; k < G.arcnum; k++)
	{
		char v1, v2; //两顶点
		int w; //权值
		cout << "请输入第" << k + 1 << "条边的两个顶点及权值:";
		cin >> v1 >> v2 >> w;
		int i = LocateVex(G, v1);
		int j = LocateVex(G, v2);
		if (i != -1 && j != -1) //无向图
		{
			G.arcs[i][j] = w;
			G.arcs[j][i] = w;
		}
	}
}

void ShorteastPath_DIJ(AMGraph G, int v0)
{
	int n = G.vexnum;	//点数
	int m = G.arcnum;	//边数
	bool* S = new bool[n];	//记录是否已被确定最短路径长度
	int* D = new int[m];	//记录当前最短路径的长度
	int* Path = new int[n]; //记录最短路径上点的直接前驱
	for (int v = 0; v < n; v++)	//n个顶点依次初始化
	{
		S[v] = false;	//S初始为空集
		D[v] = G.arcs[v0][v];	//将v0到各个终点的最短路径长度初始化为弧上的权值
		if (D[v] < Maxint)	//如果v0和v之间有弧,则将v的前驱设为v0
			Path[v] = v0;
		else
			Path[v] = -1;	//如果v0和v之间无弧,则将v的前驱设为-1
	}
	S[v0] = true;	//将v0加入S
	D[v0] = 0;	//源点到源点的距离为0
	for (int i = 0; i < n; i++)		//对其余n-1个顶点,依次进行计算
	{
		int v = v0;
		int min = Maxint;
		for (int w = 0; w < n; w++)
		{
			if (!S[w] && D[w] < min)
			{
				v = w;
				min = D[w];		//选择一条当前的最短路径,终点为v
			}
		}
		S[v] = true;		//将v加入S
		for (int w = 0; w < n; w++)		//更新从v0出发到集合V-S上所有顶点的最短路径长度
		{
			if (!S[w] && (D[v] + G.arcs[v][w] < D[w]))
			{
				D[w] = D[v] + G.arcs[v][w];		//更新D[w]
				Path[w] = v;					//更改w的前驱为v
			}
		}
	}
	cout << "节点 " << "最短路径长度 " << " 前驱" << endl;
	for (int i = 0; i < n; ++i)
		cout << " v" << G.vexs[i] << "       " << D[i] << "        " << Path[i] << endl;

	delete S;
	delete D;
	delete Path;
}

int main()
{
	AMGraph G;
	createUDN(G);

	cout << "\n请输入起点在顶点表中的序号(0为第一个):";
	int v;
	cin >> v;
	cout << "\n迪杰斯特拉算法求解过程为:" << endl;
	ShorteastPath_DIJ(G, v);

	return 0;
}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值