图邻接表实现-C++

namespace Graph
{
	enum GraphKind { DG, DN, UDG, UDN };//图的种类,分别为有向图,有向网,无向图,无向网(带权图称为网)
	class ALGraph
	{
	private:
		struct ArcNode
		{
			int adjvex; //邻接顶点编号
			ArcNode* nextArc; //对应顶点的下一条边
			int weight;//边的权值
			string info;//边的信息
			explicit ArcNode(int adj, ArcNode* nexta = nullptr, int w = 1, const string& inf = string{}) :
				adjvex(adj), nextArc(nexta), weight(w), info(inf) {}
		};
		struct Vnode//顶点表
		{
			string data;//顶点信息
			ArcNode* firstArc; //指向顶点对应边表的第一个结点
		};
		static const int MAX_VERTEX_NUM = 1000; //图的最大顶点数

		Vnode vertices[MAX_VERTEX_NUM]; //顶点表
		int vexnum, arcnum; //分别为图的顶点数和边数
		GraphKind kind; //图的种类

		bool visited[MAX_VERTEX_NUM];
		deque<int> que;
	public:
		explicit ALGraph(int vn = 0, int an = 0, GraphKind k = DG) : //初始化图,提供顶点数,边数和图的种类
			vexnum(vn), arcnum(an), kind(k) 
		{
			for (int i = 0; i < MAX_VERTEX_NUM; i++)//顶点表的指针结点初始化为nullptr
			{
				vertices[i].firstArc = nullptr;
			}
		}

		~ALGraph()//析构函数
		{
			for (int i = 0; i < vexnum; i++) //删除每个顶点对应的边链表。
			{
				ArcNode* deleteArc, *p = vertices[i].firstArc;
				while (p != nullptr)
				{
					deleteArc = p;
					p = p->nextArc;
					delete deleteArc;
				}
			}
		}

		const string& getVex(int n) //求编号为n的顶点的信息,如A/B/C编号为0,1, 2, 则编号为1的顶点返回B
		{
			if (n < 0 || n >= vexnum)
			{
				throw UnderflowException{};
			}
			return vertices[n].data;
		}

		int locateVex(const string& s)
		{
			int ret = -1;
			for (int i = 0; i < vexnum; i++)
			{
				if (vertices[i].data == s)
				{
					ret = i;
					break;
				}
			}
			return ret;
		}

		void putVex(int n, const string& value)//修改顶点编号为n的值
		{
			if (n < 0 || n >= vexnum)
			{
				throw UnderflowException{};
			}
			vertices[n].data = value;
		}

		void insertVex(const string& s)//添加顶点
		{
			if (vexnum > MAX_VERTEX_NUM)
			{
				throw UnderflowException{};
			}
			vertices[vexnum++].data = s;
		}

		void deleteVex(const string& s) //删除顶点
		{
			int k = locateVex(s);
			if (k < 0)
			{
				return;
			}
			for (int i = k + 1; i < vexnum; i++) //调整顶点表
			{
				vertices[i - 1] = vertices[i];
			}
			vexnum--;
			ArcNode* pre = nullptr, * cur = nullptr, * deleteArc = nullptr;
			for (int i = 0; i < vexnum; i++) //对于每个顶点的边表:删除边表中adjvex = k的边,如果边的adjvex > k,将其自减1
			{
				for (cur = vertices[i].firstArc; cur != nullptr;)
				{
					if (cur->adjvex == k)
					{
						deleteArc = cur;
						cur = cur->nextArc;
						if (cur == vertices[i].firstArc)
						{
							vertices[i].firstArc = cur;
						}
						else
						{
							pre->nextArc = cur;
						}
						delete deleteArc;
					}
					else
					{
						if (cur->adjvex > k)
						{
							cur->adjvex -= 1;
						}
						pre = cur;
						cur = cur->nextArc;
					}
				}
			}


		}

		void insertArc(const string& v1, const string& v2, int weight = 1, const string& inf = string{})
		{
			int n1 = locateVex(v1), n2 = locateVex(v2);
			bool flag;
			if (n1 >= 0 && n2 >= 0 && n1 != n2)
			{
				flag = true;
				for (ArcNode* temp = vertices[n1].firstArc; temp != nullptr; temp = temp->nextArc)
				{
					if (temp->adjvex == n2)
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					ArcNode* newArc = new ArcNode(n2, vertices[n1].firstArc, weight, inf);
					vertices[n1].firstArc = newArc;
					if (kind == UDG || kind == UDN)
					{
						ArcNode* copyArc = new ArcNode(n1, vertices[n2].firstArc, weight, inf);
						vertices[n2].firstArc = copyArc;
					}
					arcnum++;
				}
			}
		}

		void deleteArc(const string& v1, const string& v2)
		{
			int n1 = locateVex(v1), n2 = locateVex(v2);
			bool flag;
			ArcNode* pre = nullptr, *cur = nullptr, *deleteArc = nullptr;
			if (n1 >= 0 && n2 >= 0 && n1 != n2)
			{
				flag = false; //判断是否删除了边
				cur = vertices[n1].firstArc;
				while (cur != nullptr)
				{
					if (cur->adjvex == n2) //存在这条边
					{
						flag = true;
						deleteArc = cur;
						if (cur == vertices[n1].firstArc)
						{
							vertices[n1].firstArc = cur->nextArc;
						}
						else
						{
							pre->nextArc = cur->nextArc;
						}
						delete deleteArc;

						if (kind == UDG || kind == UDN) //如果是无向图/网,则要额外删除一条边
						{
							cur = vertices[n2].firstArc;
							while (cur != nullptr)
							{
								if (cur->adjvex == n1)
								{
									deleteArc = cur;
									if (cur == vertices[n2].firstArc)
									{
										vertices[n2].firstArc = cur->nextArc;
									}
									else
									{
										pre->nextArc = cur->nextArc;
									}
									delete deleteArc;
								}
								else
								{
									pre = cur;
									cur = cur->nextArc;
								}
							}
						}

						break;
					}
					else
					{
						pre = cur;
						cur = cur->nextArc;
					}
				}
				if (flag)
				{
					arcnum--;
				}
			}
		}

		void createGraph()
		{
			cout << "Enter vertex information:\n";
			for (int i = 0; i < vexnum; i++)//输入顶点表信息,如A/B/C/D
			{
				cout << "vertex " << i << ": ";
				getline(cin, vertices[i].data);
			}
			int containInfo;//用于判断是否要额外提供边的相关信息
			cout << "Whether contain information in arcs(yes 1, no 0): ";
			(cin >> containInfo).get();
			switch (kind)
			{
			case DG: createDG(containInfo); break;
			case DN: createDN(containInfo); break;
			case UDG: createUDG(containInfo); break;
			case UDN: createUDN(containInfo); break;
			}
		}

		void createDG(int cInfo) //生成有向图
		{
			
			string v1, v2, arcInfo = "";
			for (int i = 0; i < arcnum; )
			{
				cout << "enter arc " << i << " <v1,v2>\n";
				cout << "v1: ";
				getline(cin, v1);
				cout << "v2: ";
				getline(cin, v2);
				int n1 = locateVex(v1), n2 = locateVex(v2);
				bool flag; //判断需要添加的边是否已经在邻接表中
				if (n1 != -1 && n2 != -1 && n1 != n2) //边有效
				{
					flag = true;
					for (ArcNode* p = vertices[n1].firstArc; p != nullptr; p = p->nextArc) //确保输入的边不重复
					{
						if (p->adjvex == n2)
						{
							flag = false;
							break;
						}
					}
					if (flag)
					{
						i++;
						if (cInfo)
						{
							cout << "info: ";
							getline(cin, arcInfo);
						}
						ArcNode* newArc = new ArcNode(n2, vertices[n1].firstArc, 1, arcInfo);
						vertices[n1].firstArc = newArc;
					}
				}
			}
		}

		void createDN(int cInfo) //生成有向网
		{

			string v1, v2, arcInfo = "";
			int weight;
			for (int i = 0; i < arcnum; )
			{
				cout << "enter arc " << i << " <v1,v2> and its weight\n";
				cout << "v1: ";
				getline(cin, v1);
				cout << "v2: ";
				getline(cin, v2);
				int n1 = locateVex(v1), n2 = locateVex(v2);
				bool flag;
				if (n1 != -1 && n2 != -1 && n1 != n2)
				{
					flag = true;
					for (ArcNode* p = vertices[n1].firstArc; p != nullptr; p = p->nextArc) //确保输入的边不重复
					{
						if (p->adjvex == n2)
						{
							flag = false;
							break;
						}
					}
					if (flag)
					{
						i++;
						cout << "weight: ";
						(cin >> weight).get();
						if (cInfo)
						{
							cout << "info: ";
							getline(cin, arcInfo);
						}
						ArcNode* newArc = new ArcNode(n2, vertices[n1].firstArc, weight, arcInfo);
						vertices[n1].firstArc = newArc;
					}
				}
			}
		}

		void createUDG(int cInfo) //生成有向图
		{

			string v1, v2, arcInfo = "";
			for (int i = 0; i < arcnum; )
			{
				cout << "enter arc " << i << " <v1,v2>\n";
				cout << "v1: ";
				getline(cin, v1);
				cout << "v2: ";
				getline(cin, v2);
				int n1 = locateVex(v1), n2 = locateVex(v2);
				bool flag;
				if (n1 != -1 && n2 != -1 && n1 != n2) //边有效
				{
					flag = true;
					for (ArcNode* p = vertices[n1].firstArc; p != nullptr; p = p->nextArc) //确保输入的边不重复
					{
						if (p->adjvex == n2)
						{
							flag = false;
							break;
						}
					}
					if (flag)
					{
						i++;
						if (cInfo)
						{
							cout << "info: ";
							getline(cin, arcInfo);
						}
						ArcNode* newArc1 = new ArcNode(n2, vertices[n1].firstArc, 1, arcInfo),
							* newArc2 = new ArcNode(n1, vertices[n2].firstArc, 1, arcInfo);
						vertices[n1].firstArc = newArc1;
						vertices[n2].firstArc = newArc2;
					}
				}
			}
		}

		void createUDN(int cInfo) //生成有向网
		{

			string v1, v2, arcInfo = "";
			int weight;
			for (int i = 0; i < arcnum; )
			{
				cout << "enter arc " << i << " <v1,v2> and its weight\n";
				cout << "v1: ";
				getline(cin, v1);
				cout << "v2: ";
				getline(cin, v2);
				int n1 = locateVex(v1), n2 = locateVex(v2);
				bool flag;
				if (n1 != -1 && n2 != -1 && n1 != n2)
				{
					flag = true;
					for (ArcNode* p = vertices[n1].firstArc; p != nullptr; p = p->nextArc) //确保输入的边不重复
					{
						if (p->adjvex == n2)
						{
							flag = false;
							break;
						}
					}
					if (flag)
					{
						i++;
						cout << "weight: ";
						(cin >> weight).get();
						if (cInfo)
						{
							cout << "info: ";
							getline(cin, arcInfo);
						}
						ArcNode* newArc1 = new ArcNode(n2, vertices[n1].firstArc, weight, arcInfo),
							* newArc2 = new ArcNode(n1, vertices[n2].firstArc, weight, arcInfo);
						vertices[n1].firstArc = newArc1;
						vertices[n2].firstArc = newArc2;
					}
				}
			}
		}

		const ArcNode* firstNeighbor(int v) const
		{
			if (v < 0 || v > arcnum)
			{
				throw UnderflowException{};
			}
			return vertices[v].firstArc;
		}

		void bfsTraverse()
		{
			cout << "\nBreadth first serach :\n";
			for (int i = 0; i < vexnum; i++)
			{
				visited[i] = false;
			}
			que.clear();
			for (int i = 0; i < vexnum; i++)
			{
				if (!visited[i])
				{
					BFS(i);
				}
			}
		}
		void BFS(int v)
		{
			visited[v] = true;
			que.push_back(v);
			while (!que.empty())
			{
				v = que.front();
				que.pop_front();
				cout << vertices[v].data << endl;
				int w;
				for (const ArcNode* temp = firstNeighbor(v); temp != nullptr; temp = temp->nextArc)
				{
					w = temp->adjvex;
					if (!visited[w])
					{
						visited[w] = true;
						que.push_back(w);
					}
				}
			}
		}

		void dfsTraverse()
		{
			cout << "\nDepth first search:\n";
			for (int i = 0; i < vexnum; i++)
			{
				visited[i] = false;
			}
			for (int i = 0; i < vexnum; i++)
			{
				if (!visited[i])
				{
					DFS(i);
				}
			}
		}
		void DFS(int v)
		{
			visited[v] = true;
			cout << vertices[v].data << endl;
			int w;
			for (const ArcNode* temp = firstNeighbor(v); temp != nullptr; temp = temp->nextArc)
			{
				w = temp->adjvex;
				if (!visited[w])
				{
					DFS(w);
				}
			}
		}

		void shortestPath_dij(const string& s0)
		{
			int v;
			bool flag;//如果找不到最短距离时,退出查找最短路径的循环。
			vector<int> dist(vexnum, INT_MAX); //记录最短距离
			vector<int> path(vexnum); //用于记录最短路径
			int v0 = locateVex(s0); //找到顶点对应的编号
			if (v0 < 0) //顶点编号无效
			{
				throw UnderflowException{};
			}
			for (int i = 0; i < vexnum; i++) //集合S初始为空
			{
				visited[i] = false;
			}
			dist[v0] = 0; //v0到v0的距离为0,所以循环开始选择顶点v0
			for (int i = 0; i < vexnum; i++)
			{
				flag = false;
				int min = INT_MAX;
				int w;
				for (w = 0; w < vexnum; ++w)//选择源点通过集合S到集合V - S中每个的点最短路径Dk(k∈V-S)(简称最短距离集合)
				{
					if (!visited[w])//查找min{Dk|k∈V-S}
					{
						if (dist[w] < min)
						{
							v = w;
							min = dist[w];
							flag = true;
						}
					}
				}
				if (flag)//如果可以找到最小的Dk则继续循环
				{
					visited[v] = true; //假设最短路径为Dv,将v加入集合S
					for (const ArcNode* temp = firstNeighbor(v); temp != nullptr; temp = temp->nextArc) //更新最短距离集合
					{
						w = temp->adjvex;
						if (!visited[w] && (long(min) + temp->weight < dist[w]))
						{
							dist[w] = min + temp->weight;
							path[w] = v;//记录边的另一个顶点。用于追溯到源点。
						}
					}
				}
				else
				{
					break;
				}
			}
			vector<int> route; //用于记录最小距离的路径
			for (int i = 0; i < vexnum; i++)//输出最短距离
			{
				if (i != v0)
				{
					cout << "\nshortest path from " << vertices[v0].data << " to " << vertices[i].data << ":\n";
					cout << "Distance: ";
					cout << dist[i] << endl;
					cout << "Path: ";
					if (dist[i] < INT_MAX) //假设有最短路径
					{
						route.clear();
						int k = i;
						while (k != v0)//追溯到v0
						{
							route.push_back(k);
							k = path[k];
						}
						route.push_back(v0);
						reverse(begin(route), end(route));//由于路径是反序排列,所以需要反转。
						for (int j = 0; j < route.size(); j++)//打印路径
						{
							cout << vertices[route[j]].data << " ";
						}
					}
					cout << endl;
				}
			}
		}



	};


}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值