zoukankan      html  css  js  c++  java
  • 图——克鲁斯算法——构建最小生成树(采用邻接矩阵的方式存储)

    include "stdafx.h"

    #include<iostream>
    #include<vector>
    #include<string>
    #include<queue>
    #include<stack>
    #include<cstring>
    #include<string.h>
    #include<deque>
    #include <forward_list>
    #include<set>
    #include<list>
    
    using namespace std;
    
    typedef struct
    {
    	vector<int> vexs;//顶点表
    	vector<vector<int>> arcs;//边表
    	int vexnums, arcnums;
    }AMGraph; //邻接矩阵表示一个图
    
    class Solution {
    public:
    	void CreateGraph(AMGraph &G)
    	{
    		int num = 0;
    		cout << "请输入顶点个数:";
    		cin >> num;
    		G.vexnums = num;
    		cout << "请输入边的个数:";
    		cin >> num;
    		G.arcnums = num;
    		//依次输入各个顶点
    		cout << "依次输入各个顶点:" << endl;
    		for (int i = 0; i < G.vexnums; ++i)
    		{
    			int ch;
    			cin >> ch;
    			G.vexs.push_back(ch);
    		}
    		for (int i = 0; i < G.vexnums; ++i)//初始化各个边
    		{
    			vector<int> vec;
    			vec.clear();
    			for (int j = 0; j < G.vexnums; ++j)
    			{
    				vec.push_back(0);
    			}
    			G.arcs.push_back(vec);
    
    		}
    		cout << "依次输入两个关联的顶点:" << endl;
    		for (int i = 0; i < G.arcnums; ++i)
    		{
    			int vex1;
    			int vex2;
    			cin >> vex1 >> vex2;
    			G.arcs[vex1][vex2] = 1;
    			G.arcs[vex2][vex1] = 1;//
    			cout << "一条边构建成功!" << endl;
    		}
    		GetGraph(G);
    	}
    
    	//为了试验方便,我们自己创建一个固定的图
    	void CreatAGraph(AMGraph &G)
    	{
    		//创建顶点
    		G.vexnums = 6;
    		G.arcnums = 6;
    		for (int i = 0; i < G.vexnums; ++i)
    		{
    			G.vexs.push_back(i);
    		}
    		for (int i = 0; i < G.vexnums; ++i)//初始化各个边
    		{
    			vector<int> vec;
    			vec.clear();
    			for (int j = 0; j < G.vexnums; ++j)
    			{
    				vec.push_back(0);
    			}
    			G.arcs.push_back(vec);
    		}
    		G.arcs[0][1] = 6;
    		G.arcs[1][0] = 6;
    		G.arcs[0][2] = 1;
    		G.arcs[2][0] = 1;
    		G.arcs[0][3] = 5;
    		G.arcs[3][0] = 5;
    
    		G.arcs[1][2] = 5;
    		G.arcs[2][1] = 5;
    		G.arcs[1][4] = 3;
    		G.arcs[4][1] = 3;
    
    		G.arcs[2][4] = 6;
    		G.arcs[4][2] = 6;
    		G.arcs[2][5] = 4;
    		G.arcs[5][2] = 4;
    
    		G.arcs[3][2] = 5;
    		G.arcs[2][3] = 5;
    		G.arcs[3][5] = 2;
    		G.arcs[5][3] = 2;
    
    
    		G.arcs[4][5] = 6;
    		G.arcs[5][4] = 6;
    
    		GetGraph(G);
    	}
    
    
    	vector<int> visited;//用来标注对应的节点是否被访问,如果被访问,则访问下一个节点
    	void DFSTraverse(AMGraph G)//深度优先遍历
    	{
    		visited.clear();
    		//初始化,假设每个节点都没有被访问
    		for (int i = 0; i < G.vexnums; ++i)
    		{
    			visited.push_back(0);//没访问的都设置为0,访问过的都设置为1
    		}
    		for (int v = 0; v < G.vexnums; ++v)
    		{
    			if (visited[v] == 0)//保证节点没有被访问
    				DFS(G, v);
    		}
    		cout << endl;
    	}
    	void DFS(AMGraph G, int v) //对i节点进行深度优先遍历
    	{
    		cout << "v_" << v << "  ";
    		visited[v] = 1;
    		for (int i = 0; i < G.vexnums; ++i)
    		{
    			if (G.arcs[v][i] != 0 && visited[i] == 0)//存在边,且i节点没有访问过
    				DFS(G, i);
    		}
    		return;
    	}
    
    	void  BFSTraverse(AMGraph G)//广度优先遍历
    	{
    		visited.clear();
    		for (int i = 0; i < G.vexnums; ++i)
    		{
    			visited.push_back(0);//没访问的都设置为0,访问过的都设置为1
    		}
    		for (int v = 0; v < G.vexnums; ++v)
    		{
    			if (visited[v] == 0)
    			{
    				cout << "v_" << v << "  ";//节点没有被访问
    				visited[v] = 1;
    			}
    			for (int i = 0; i < G.vexnums; ++i)
    			{
    				if (visited[i] == 0 && G.arcs[v][i] != 0)
    				{
    					cout << "v_" << i << "  ";//节点没有被访问
    					visited[i] = 1;
    				}
    			}
    		}
    		cout << endl;
    	}
    	void BFS(AMGraph G, int v)
    	{
    		if (visited[v] == 0)
    		{
    			cout << "v_" << v << "  ";//节点没有被访问
    			visited[v] = 1;
    		}
    
    		for (int i = 0; i < G.vexnums; ++i)
    		{
    			if (visited[i] == 0)
    			{
    				cout << "v_" << v << "  ";//节点没有被访问
    				visited[v] = 1;
    			}
    		}
    	}
    
    	void  GetGraph(AMGraph G)
    	{
    		cout << "顶点信息:" << endl;
    		for (int i = 0; i < G.vexnums; ++i)
    		{
    			cout << G.vexs[i] << "  ";
    		}
    		cout << endl;
    		cout << "边的信息:" << endl;
    		for (int i = 0; i < G.vexnums; ++i)
    		{
    			for (int j = 0; j < G.vexnums; ++j)
    			{
    				cout << G.arcs[i][j] << "  ";
    			}
    			cout << endl;
    		}
    	}
    	//用普利姆算法构建最小生成树,最小生成树存在返回T
    	vector<int>nodes;//存储已经存在在U集合里面的点,每次从剩下的节点选择离nodes集合里面距离最小的节点
    	vector<int>renodes;//存储剩余的节点
    
    	AMGraph  MinSpanTree_Prim(AMGraph G)
    	{
    
    		AMGraph T;
    		T.vexnums = G.vexnums;
    		//初始化顶点
    		for (int i = 0; i < T.vexnums; ++i)
    		{
    			T.vexs.push_back(i);
    		}
    		//初始化边
    		for (int i = 0; i < T.vexnums; ++i)
    		{
    			renodes.push_back(i);//向renodes中插入节点
    			vector<int> vec;
    
    			for (int j = 0; j < T.vexnums; ++j)
    			{
    				//	T.arcs[i][j] = 0;   //初始化T
    
    				vec.push_back(0);
    			}
    			T.arcs.push_back(vec);
    		}
    
    		//从v_0开始选边
    		nodes.push_back(0);//第0个边给node节点
    		renodes.erase(renodes.begin() + 0);
    
    
    		while (nodes.size() != T.vexnums)
    		{
    			int minDistance = G.arcs[nodes[0]][renodes[0]];//记录最小距离
    
    			int minNode1 = nodes[0];
    			int minNode2 = renodes[0];//记录离最小距离的节点
    			int flag = 0;//renodes中要删除的节点
    			bool visist = false;
    			int i = 0, j = 0;
    			for (i = 0; i < nodes.size(); ++i)//选择距离最小的边
    			{
    				for (j = 0; j < renodes.size(); ++j)
    				{
    					//找到最小距离,且最小距离和原来节点不形成回路
    					//if (visist == false && minDistance==0 && G.arcs[nodes[i]][renodes[j]] != 0 ) //距离不等于0 //只执行一次,找到最短距离
    					if (minDistance == 0 && G.arcs[nodes[i]][renodes[j]] != 0) //距离不等于0 //只执行一次,找到最短距离
    					{
    						minDistance = G.arcs[nodes[i]][renodes[j]];
    						minNode1 = nodes[i];
    						minNode2 = renodes[j];
    						flag = j;
    						//	visist = true;  //visit保证这条语句只访问一次
    						//	cout << "flag:" << flag << endl;
    					}
    					if (G.arcs[nodes[i]][renodes[j]] != 0 && minDistance > G.arcs[nodes[i]][renodes[j]])
    					{
    						minDistance = G.arcs[nodes[i]][renodes[j]];
    						minNode1 = nodes[i];
    						minNode2 = renodes[j];
    						flag = j;
    						//	cout << "flag:" << flag << endl;
    					}
    
    				}
    				//	cout << "最短距离是:" << minDistance << endl;
    			}
    
    			T.arcs[minNode1][minNode2] = minDistance;
    			T.arcs[minNode2][minNode1] = minDistance;
    			T.arcnums++;
    			nodes.push_back(minNode2);
    			//cout << "flag:" << flag << endl;
    			cout << "nodes:";
    			print(nodes);
    			cout << endl;
    
    			renodes.erase(renodes.begin() + flag);
    			//cout << "renodes:";
    			//print(renodes);
    			//cout << endl;
    			//cout << endl;
    			//cout << "T.vexnums:" << T.vexnums;
    			//cout << "nodes.size():" << nodes.size();
    		}
    		return T;
    	}
    	void print(vector<int> vec)
    	{
    		for (int i = 0; i < vec.size(); ++i)
    			cout << vec[i] << "  ";
    	}
    	//用克鲁斯算法构建最小生成树,最小生成树返回T
    
    
    	struct Edge {
    		int Head;
    		int Tail;
    		int cost;
    	};
    	vector<int> parentNode;//用来存储所属的连通分量
    	vector<Edge*> edges;//存储边信息
    	void SortEdge(AMGraph G)//对边进行排序
    	{
    		for (int i = 0; i < G.vexnums; ++i)
    		{
    			for (int j = 0; j < G.vexnums; ++j)
    			{
    				Edge *edge = new Edge();;
    				if (G.arcs[i][j] != 0)
    				{
    					edge->Head = i;
    					edge->Tail = j;
    					edge->cost = G.arcs[i][j];
    					if (!edges.empty())
    					{
    						auto beg = edges.begin();
    						while (beg != edges.end() && edge->cost > (*beg)->cost)
    						{
    							++beg;
    						}
    						if (beg == edges.end())
    							edges.push_back(edge);
    						else
    							edges.insert(beg,edge);
    					}
    					else
    					{
    						edges.push_back(edge);
    					}
    				}
    			}
    		}
    		printEdges(edges);
    	}
    	void printEdges(vector<Edge*> edges)
    	{
    		for (int i = 0; i < edges.size(); ++i)
    		{
    			cout << i << ":" << "Head:" << edges[i]->Head << "  Tail:" << edges[i]->Tail << "  cost:" << edges[i]->cost << endl;
    		}
    	}
    	AMGraph MinSpanTree_Kruskal(AMGraph G)
    	{
    		AMGraph  T;
    		T.vexnums = G.vexnums;
    		//初始化顶点
    		for (int i = 0; i < T.vexnums; ++i)
    		{
    			T.vexs.push_back(i);
    			parentNode.push_back(i);//初始化每个顶点所属的联通分量,一开始每个顶点自成一个连通分量
    		}
    		//初始化边
    		for (int i = 0; i < T.vexnums; ++i)
    		{
    			renodes.push_back(i);//向renodes中插入节点
    			vector<int> vec;
    
    			for (int j = 0; j < T.vexnums; ++j)
    			{
    				//	T.arcs[i][j] = 0;   //初始化T
    
    				vec.push_back(0);
    			}
    			T.arcs.push_back(vec);
    		}
    		SortEdge(G);//对G的边
    		while (!edges.empty())//循环结束条件是edges边集合为空
    		{
    		
    			Edge* edge = *(edges.begin());
    			if (parentNode[edge->Head] != parentNode[edge->Tail])
    			{
    				//设置最小的
    				T.arcs[edge->Head][edge->Tail] = edge->cost;
    				T.arcs[edge->Tail][edge->Head] = edge->cost;
    				cout << "Head:" << edge->Head << "  ";
    				cout << "Tail:" << edge->Tail << "  ";
    				cout << "cost:" << edge->cost <<endl;
    				int flag;
    				int root;
    				if (parentNode[edge->Head]>parentNode[edge->Tail])	//每次最小节点为跟节点
    				{
    					flag = parentNode[edge->Head]; //修改之前的根节点
    					root = parentNode[edge->Tail]; //找到对应的根节点
    		//			parentNode[edge->Head] = root;
    				}
    				else {
    					flag = parentNode[edge->Tail];
    					root= parentNode[edge->Head];
    			//		parentNode[edge->Tail] = parentNode[edge->Head];
    				
    				}
    				for (int i = 0; i < parentNode.size(); i++) 
    				{
    					if (parentNode[i] == flag)//遍历parentNode,修改根节点为flag的根节点
    					{
    						parentNode[i] = root;
    					}
    				}
    				
    				edges.erase(edges.begin());
    			}
    			else
    			{
    				edges.erase(edges.begin());
    			}
    		}
    	
    		return T;
    	}
    };
    int main()
    {
    
    
    	Solution so;
    
    	AMGraph G;
    	//so.CreateGraph(G);
    	so.CreatAGraph(G);
    	cout << "G深度优先遍历:" << endl;
    	so.DFSTraverse(G);
    
    	cout << "G广度优先遍历:" << endl;
    	so.BFSTraverse(G);
    	//so.GetGraph(G);
    
    	//AMGraph T;
    	//T = so.MinSpanTree_Prim(G);
    	//cout << "T深度优先遍历:" << endl;
    	//so.DFSTraverse(T);
    	//cout << "T的信息:" << endl;
    	//so.GetGraph(T);
    
    //	so.SortEdge(G);
    
    	AMGraph T=so.MinSpanTree_Kruskal(G);
    	so.GetGraph(T);
    	return 0;
    }
  • 相关阅读:
    服务上线怎么兼容旧版本?
    abstract class和interface有什么区别?
    Anonymous Inner Class (匿名内部类)是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
    寒假每日日报49(开发家庭记账本APP——进度十)
    寒假每周总结7
    寒假每日日报48(开发家庭记账本APP——进度九)
    寒假每日日报47(开发家庭记账本APP——进度八)
    寒假每日日报46(开发家庭记账本APP——进度七)
    寒假每日日报45(开发家庭记账本APP——进度六)
    寒假每日日报44(开发家庭记账本APP——进度五)
  • 原文地址:https://www.cnblogs.com/wdan2016/p/6186086.html
Copyright © 2011-2022 走看看