一个带有Kruskal、Prim、Dijkstra算法的图类型 - C++ for C Programmers

C++ for C Programmers 这门课讲了图论中三个重要的算法: Kruskal's Minimum Spanning Tree, Prim's Minimum Spanning Tree, Dijkstra's Shortest Path.

这里把三个算法实现后作为成员函数写在一个图的类里,图是用邻接矩阵存储的,支持随机生成。

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <fstream>
#include <string>
#include <climits>
using namespace std;


//Enumeration type: D for directed; W for weighted
enum GraphKind { DG, WDG, UDG, WUDG };

class MatrixGraph
{
private:
	double **edge;                         //adjacency matrix
	string *vertexlist;                    //storing the keywords of the vertexes
	int vexnum;                          //number of vertexes
	int edgenum;                         //number of edges
	GraphKind kind;                 //identifier of the graph
	const double UNCONNECTED = DBL_MAX;
	struct arc                        //used in Kruskal()
	{
		int head, end;
		double weight;
	};
	void quickSort_by_weight(arc a[], int i, int j)    //Quichsort function modulated for arc
	{
		if (i<j)
		{
			int f = i, l = j;
			arc k;
			k.weight = a[i].weight;
			k.head = a[i].head;
			k.end = a[i].end;
			while (i < j)
			{
				while (a[j].weight >= k.weight && i < j) j--;
				if (i < j)
				{
					a[i].weight = a[j].weight;
					a[i].head = a[j].head;
					a[i].end = a[j].end;
					i++;
				}
				while (a[i].weight <= k.weight && i < j)    i++;
				if (i < j)
				{
					a[j].weight = a[i].weight;
					a[j].head = a[i].head;
					a[j].end = a[i].end;
					j--;
				}
			}
			a[i].weight = k.weight;
			a[i].head = k.head;
			a[i].end = k.end;
			quickSort_by_weight(a, f, i - 1);
			quickSort_by_weight(a, i + 1, l);
		}
	}
	double prob()
	{
		return (static_cast<double>(rand()) / RAND_MAX);
	}
public:
	MatrixGraph(int vexNum, GraphKind graphkind) : vexnum(vexNum), edgenum(0), kind(graphkind)
	{
		vertexlist = new string[vexnum];
		edge = new double*[vexnum];
		for (int i = 0; i < vexnum; i++)
			edge[i] = new double[vexnum];
		for (int i = 0; i < vexnum; i++)
			for (int j = 0; j < vexnum; j++)
				edge[i][j] = UNCONNECTED;
	}

	MatrixGraph& operator=(MatrixGraph graph)
	{
		for (int i = 0; i < vexnum; i++)
			vertexlist[i] = graph.vertexlist[i];
		for (int i = 0; i < vexnum; i++)
			for (int j = 0; j < vexnum; j++)
				edge[i][j] = graph.edge[i][j];
		return *this;
	}

	void Create()
	{
		switch (kind)
		{
		case DG:
		{
			CreateDG();
			break;
		}
		case WDG:
		{
			CreateWDG();
			break;
		}
		case UDG:
		{
			CreateUDG();
			break;
		}
		case WUDG:
		{
			CreateWUDG();
			break;
		}
		default:
			return;
		}
	}

	void RandomCreate()
	{
		switch (kind)
		{
		case DG:
		{
			RandomCreateDG();
			break;
		}
		case WDG:
		{
			RandomCreateWDG();
			break;
		}
		case UDG:
		{
			RandomCreateUDG();
			break;
		}
		case WUDG:
		{
			RandomCreateWUDG();
			break;
		}
		default:
			return;
		}
	}

	void RandomCreateDG()
	{
		Init();
		double density;
		srand(time(NULL));
		cout << "graph density?" << endl;
		cin >> density;
		for (int i = 0; i < vexnum; i++)
			for (int j = 0; j < vexnum; j++)
			{
				if (i != j && prob() < density)
				{
					edge[i][j] = true;
					edgenum++;
				}
			}
	}

	void RandomCreateWDG()
	{
		Init();
		double density;
		double upp;
		srand(time(NULL));
		cout << "graph density [0,1] ?" << endl;
		cin >> density;
		cout << "the upper bound of edge cost?" << endl;
		cin >> upp;
		for (int i = 0; i < vexnum; i++)
			for (int j = 0; j < vexnum; j++)
			{
				if (i != j && prob() < density)
				{
					edge[i][j] = prob()*upp;
					edgenum++;
				}
			}
	}

	void RandomCreateUDG()
	{
		Init();
		double density;
		srand(time(NULL));
		cout << "graph density [0,1] ?" << endl;
		cin >> density;
		for (int i = 0; i < vexnum; i++)
			for (int j = i; j < vexnum; j++)
			{
				if (i != j && prob() < density)
				{
					edge[i][j] = edge[j][i] = true;
					edgenum += 2;
				}
			}
	}

	void RandomCreateWUDG()
	{
		Init();
		double density;
		double upp;
		srand(time(NULL));
		cout << "graph density [0,1] ?" << endl;
		cin >> density;
		cout << "the upper bound of edge cost?" << endl;
		cin >> upp;
		for (int i = 0; i < vexnum; i++)
			for (int j = i; j < vexnum; j++)
			{
				if (i != j && prob() < density)
				{
					edge[i][j] = edge[j][i] = prob()*upp;
					edgenum += 2;
				}
			}
	}

	void Init()        //initializer of the graph
	{
		cout << "Enter the keyword for each of the " << vexnum << " vertex(es):" << endl;
		for (int i = 0; i < vexnum; i++)
			cin >> vertexlist[i];
	}

	void CreateDG()            //Directed Graph
	{
		Init();
		int vhead, vtail;
		cout << "Describe each edge. You can enter a single '/' to quit." << endl;
		while ((cout << "Enter the serial number of the head, and that of the terminal:" << endl) && (cin >> vhead >> vtail))
		{
			edgenum++;
			edge[vhead][vtail] = 1;
		}
	}

	void CreateWDG()        //weighted directed graph
	{
		Init();
		int vhead, vtail;
		double w;
		cout << "Describe each edge. You can enter a single '/' to quit." << endl;
		while ((cout << "Enter the serial number of the head, and that of the terminal, and then enter the weight:" << endl) && (cin >> vhead >> vtail >> w))
		{
			edgenum++;
			edge[vhead][vtail] = w;
		}
	}

	void CreateUDG()            //undirected graph
	{
		Init();
		int vhead, vtail;
		cout << "Describe each edge. You can enter a single '/' to quit." << endl;
		while ((cout << "Enter the serial number of the head, and that of the terminal:" << endl) && (cin >> vhead >> vtail))
		{
			edgenum += 2;
			edge[vhead][vtail] = edge[vtail][vhead] = 1;
		}
	}

	void CreateWUDG()        //weighted undirected graph
	{
		Init();
		int vhead, vtail;
		double w;
		cout << "Describe each edge. You can enter a single '/' to quit." << endl;
		while ((cout << "Enter the serial number of the head, and that of the terminal, and then enter the weight:" << endl) && (cin >> vhead >> vtail >> w))
		{
			edgenum++;
			edge[vhead][vtail] = edge[vtail][vhead] = w;
		}
	}

	void displayGraph()
	{
		cout << vexnum << " vertex(es) in total." << endl;
		cout << edgenum << " edge(s) in total." << endl;
		for (int i = 0; i < vexnum; i++)
		{
			cout << "Vertex " << i + 1 << " is: " << vertexlist[i] << endl;
			for (int j = 0; j < vexnum; j++)
				if (edge[i][j] != UNCONNECTED)
					cout << "  " << "- Vertex " << vertexlist[j] << " is connected with edge value of " << edge[i][j] << endl;
		}
	}

	double getEdge(int i, int j)
	{
		return edge[i][j];
	}

	string getVertex(int i)
	{
		return vertexlist[i];
	}

	GraphKind getGraphkind()
	{
		return kind;
	}

	MatrixGraph Prim(int u)            //u is the serial number(starting with 0) of the starting point
	{
		MatrixGraph MST(vexnum, kind);
		if (kind != WUDG)
		{
			cout << "This is not a weighted undirected graph!" << endl;
			return MST;
		}
		for (int i = 0; i < vexnum; i++)
		{
			int flag = 0;
			for (int j = 0; j < vexnum; j++)
				if (edge[i][j] == UNCONNECTED)
					flag++;
			if (flag == (vexnum - 1))
			{
				cout << "This is not a connected graph!" << endl;
				return MST;
			}
		}
		for (int i = 0; i < vexnum; i++)
			if (edge[i][i] != UNCONNECTED)
			{
				cout << "Cannot have loops!" << endl;
				return MST;
			}

		for (int i = 0; i < vexnum; i++)
			MST.vertexlist[i] = vertexlist[i];

		struct shortcut {
			int idx;
			double leastcost;
		};
		shortcut *closedge;                                //closedge[i].leastcost stores the leastcost edge to the tree(initialed with u) of vertex i
		closedge = new shortcut[vexnum];                //closedge[i].idx stores the index of the vertex which the edge above (starting with vi) depends on
		for (int i = 0; i < vexnum; i++)
			if (i != u) closedge[i] = { u,edge[u][i] };    //initialize the closedge array
		closedge[u].leastcost = 0;                        //close the initial vertex 'u'
		closedge[u].idx = -1;                            //identify the initial vertex
		for (int i = 1; i < vexnum; i++)
		{
			int k = 0;
			for (k; k < vexnum; k++)
				if (closedge[k].leastcost != 0) break;    //find a 'k' which indexes a vertex not in the closed set
			double min = closedge[k].leastcost;
			for (int j = 0; j < vexnum; j++)
				if (closedge[j].leastcost < min && closedge[j].leastcost > 0)
				{
					min = closedge[j].leastcost;
					k = j;                                //make sure 'k' indexes the vertex with the least cost to link the tree
				}
			closedge[k].leastcost = 0;                    //close vertex 'k'
			for (int j = 0; j < vexnum; j++)
				if (edge[k][j] < closedge[j].leastcost)
					closedge[j] = { k,edge[k][j] };        //include 'k' and its leastcost edge into the Minimum Spanning Tree
		}                                                //After every inclusion of k, closedge is still directing to a minimum spanning tree.So MST is also one.
		for (int i = 0; i < vexnum; i++)                //update the closedge(update is needed only when the newly included vertex brings a shorter edge, so just check this)
			if (i != u) MST.edge[closedge[i].idx][i] = MST.edge[i][closedge[i].idx] = edge[closedge[i].idx][i];
		delete[] closedge;
		MST.edgenum = vexnum - 1;
		return MST;    //MST generated with greedy manner.
	}

	MatrixGraph Kruskal()
	{
		MatrixGraph MST(vexnum, kind);
		if (kind != WUDG)
		{
			cout << "This is not a weighted undirected graph!" << endl;
			return MST;
		}
		for (int i = 0; i < vexnum; i++)
		{
			int flag = 0;
			for (int j = 0; j < vexnum; j++)
				if (edge[i][j] == UNCONNECTED)
					flag++;
			if (flag == (vexnum - 1))
			{
				cout << "This is not a connected graph!" << endl;
				return MST;
			}
		}
		for (int i = 0; i < vexnum; i++)
			if (edge[i][i] != UNCONNECTED)
			{
				cout << "Cannot have loops!" << endl;
				return MST;
			}

		for (int i = 0; i < vexnum; i++)
			MST.vertexlist[i] = vertexlist[i];
		arc *arclist;
		arclist = new arc[edgenum];
		int *forestlist;
		forestlist = new int[vexnum];    //used for vertex[i] to identify to which tree it belongs so as to avoid including an edge of the same tree
		for (int i = 0; i < vexnum; i++)
			forestlist[i] = i;            //initializing each vertex as a independent tree with the serial number of itself
		int c = 0;
		for (int i = 0; i < vexnum; i++)
			for (int j = i + 1; j < vexnum; j++)
			{
				if (edge[i][j] < UNCONNECTED)
				{
					arclist[c].head = i;
					arclist[c].end = j;
					arclist[c].weight = edge[i][j];
					c++;
				}
			}
		quickSort_by_weight(arclist, 0, edgenum - 1);

		for (int i = 0; i < edgenum; i++)
		{
			if (forestlist[arclist[i].head] != forestlist[arclist[i].end])        //not in the same tree
			{
				MST.edge[arclist[i].head][arclist[i].end] = MST.edge[arclist[i].end][arclist[i].head] = arclist[i].weight;
				for (int j = 0; j < vexnum; j++)
					if (forestlist[j] == forestlist[arclist[i].end] && j != arclist[i].end)
						forestlist[j] = forestlist[arclist[i].head];
				forestlist[arclist[i].end] = forestlist[arclist[i].head];    //synthesize the tree to which the end vertex belongs into the tree of the head
			}
		}
		MST.edgenum = vexnum - 1;
		delete[] forestlist;
		delete[] arclist;
		return MST;
	}

	MatrixGraph Dijkstra(int head, int terminal)
	{
		MatrixGraph SP(vexnum, kind);
		if (kind != WUDG)
		{
			cout << "This is not a weighted undirected graph!" << endl;
			return SP;
		}
		for (int i = 0; i < vexnum; i++)
		{
			int flag = 0;
			for (int j = 0; j < vexnum; j++)
				if (edge[i][j] == UNCONNECTED)
					flag++;
			if (flag == (vexnum - 1))
			{
				cout << "This is not a connected graph!" << endl;
				return SP;
			}
		}
		for (int i = 0; i < vexnum; i++)
			if (edge[i][i] != UNCONNECTED)
			{
				cout << "Cannot have loops!" << endl;
				return SP;
			}

		double *path = new double[vexnum];
		int *closed = new int[vexnum];
		int *prev = new int[vexnum];
		for (int i = 0; i < vexnum; i++)
		{
			SP.vertexlist[i] = vertexlist[i];
			closed[i] = 0;                        //initialize every vertex as unclosed
			path[i] = edge[head][i];            //initialize path[],which stores the minimum cost from vertex i to vertex head
			if (path[i] == UNCONNECTED)
				prev[i] = -1;
			else
				prev[i] = head;
		}
		closed[head] = 1;                        //close the head vertex
		do {
			double min = UNCONNECTED;
			int tmp = head;
			for (int i = 0; i < vexnum; i++)
			{
				if (closed[i] == 0 && min > path[i])
				{
					min = path[i];
					tmp = i;
				}
			}
			closed[tmp] = 1;
			for (int i = 0; i < vexnum; i++)
			{
				if (closed[i] == 0 && edge[tmp][i] != UNCONNECTED && (path[tmp] + edge[tmp][i]) < path[i])
				{
					path[i] = edge[tmp][i] + path[tmp];
					prev[i] = tmp;
				}

			}
		} while (closed[terminal] == 0);
		int i = terminal, j = 0;
		while (prev[i] != -1)
		{
			SP.edge[i][prev[i]] = SP.edge[prev[i]][i] = edge[i][prev[i]];
			i = prev[i];
			j++;
		}
		SP.edgenum = j;
		delete[] path;
		delete[] closed;
		delete[] prev;
		return SP;
	}
};
int main()
{
	MatrixGraph graph(6, WUDG);
	graph.RandomCreate();
	MatrixGraph SP = graph.Prim(0);
	graph.displayGraph();
	SP.displayGraph();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值