图的综合问题

#include<iostream>
#include<string>
using namespace std;


typedef char VertexType;        //顶点类型应由用户定义
typedef int EdgeType;           //边上的权值类型应由用户定义

#define MAXVEX  100             //最大顶点数,应由用户定义
#define INFINITY    65535       //用65535来代表无穷大
#define DEBUG

bool visit[MAXVEX];
int n = 0;
								//邻接矩阵结构
typedef struct
{
	VertexType vexs[MAXVEX];    //顶点表
	EdgeType   arc[MAXVEX][MAXVEX]; //邻接矩阵,可看作边
	int numVertexes, numEdges;      //图中当前的顶点数和边数
}Graph;

//边集数组
#define MAXEDGE   100
typedef struct
{
	int begin;
	int end;
	int weight;
}Edge;



//定位
int locates(Graph *g, char ch)
{
	int i = 0;
	for (i = 0; i < g->numVertexes; i++)
	{
		if (g->vexs[i] == ch)
		{
			break;
		}
	}
	if (i >= g->numVertexes)
	{
		return -1;
	}

	return i;
}

//建立一个无向网图的邻接矩阵表示
void CreateGraph(Graph *g)
{
	int i, j, k, w;
	printf("输入顶点数和边数:\n");
	cin >> g->numVertexes >> g->numEdges;

#ifdef DEBUG

	cout << g->numVertexes << " " << g->numEdges << endl;
#endif

	cout << "请输入顶点:";
	for (i = 0; i < g->numVertexes; i++)
	{
		cin >> g->vexs[i];
	}

#ifdef DEBUG
	for (i = 0; i < g->numVertexes; i++)
	{
		cout<<g->vexs[i];
	}
	cout << endl;
#endif


	for (i = 0; i < g->numVertexes; i++)
	{
		for (j = 0; j < g->numVertexes; j++)
		{
			g->arc[i][j] = INFINITY; //邻接矩阵初始化
		}
	}
	for (k = 0; k < g->numEdges; k++)
	{
		char p, q;
		cout << "输入边(vi,vj)上的下标i,下标j和权值:" << endl;
		cin >> p >> q >> w;
		int m = -1;
		int n = -1;
		m = locates(g, p);
		n = locates(g, q);
		if (n == -1 || m == -1)
		{
			fprintf(stderr, "there is no this vertex.\n");
			return;
		}
		g->arc[m][n] = w;
		g->arc[n][m] = g->arc[m][n];  //因为是无向图,矩阵对称
	}
}





//建立图的邻接表的表现形式
#define SUCCESS 1
#define UNSUCCESS 0
typedef int Status;
bool visited[MAXVEX]; //全局数组,记录结点是否已补访问

typedef int EdgeWeight;
typedef struct EdgeNode
{
	int adjvex; //邻接点
	EdgeWeight weight; //权值
	struct EdgeNode* next; //指向下一条边

}EdgeNode;

typedef char VertexType; //顶点类型
typedef struct
{
	VertexType data;
	EdgeNode* pFirstEdge; //指示第一条边
}VertexNode;

typedef VertexNode AdjList[MAXVEX];//邻接表

typedef struct
{
	AdjList adjList; //邻接表
	int iVexNum; //顶点个数
	int iEdgeNum; //边数
}AdjListGraph;


//由顶点值得到顶点索引
int GetIndexByVertexVal(const AdjListGraph& G, VertexType val)
{
	for (int i = 0; i < G.iVexNum; ++i)
	{
		if (val == G.adjList[i].data)
			return i;
	}
	return -1;
}

//创建有向图
Status CreateAdjListGraph(AdjListGraph& G)
{
	cout << "输入顶点个数以及边数:";
	cin >> G.iVexNum >> G.iEdgeNum;
	cout << "请输入" << G.iVexNum << "个顶点:";
	for (int i = 0; i < G.iVexNum; ++i)
	{
		cin >> G.adjList[i].data;
		G.adjList[i].pFirstEdge = NULL;
	}

	cout << "请输入由两点构成的边(" << G.iEdgeNum << "条):"<<"以及对应的权值";
	int wg;
	for (int i = 0; i < G.iEdgeNum; ++i)
	{
		VertexType first;
		VertexType second;
		cin >> first >> second >> wg;
		int m = GetIndexByVertexVal(G, first);
		int n = GetIndexByVertexVal(G, second);
		if (m == -1 || n == -1)
			return UNSUCCESS;

		EdgeNode* pEdgeNode = new EdgeNode;
		pEdgeNode->adjvex = n;
		pEdgeNode->weight = wg;  //权值暂时不用

								//表头插入法
		pEdgeNode->next = G.adjList[m].pFirstEdge;
		G.adjList[m].pFirstEdge = pEdgeNode;
	}
	return SUCCESS;
}


//销毁图
void DestroyGraph(AdjListGraph& G)
{
	for (int i = 0; i < G.iVexNum; ++i)
	{
		EdgeNode* pEdge = G.adjList[i].pFirstEdge;
		while (pEdge)
		{
			EdgeNode* q = pEdge;
			pEdge = pEdge->next;
			delete q;
		}
		G.adjList[i].pFirstEdge = NULL;
	}
	G.iVexNum = 0;
	G.iEdgeNum = 0;
}


//得到顶点的度
int GetVertexDegree(const AdjListGraph& G, VertexType val)
{
	int m = GetIndexByVertexVal(G, val);//得到顶点的下标
	int iCount = 0; //顶点的度

	for (int i = 0; i < G.iVexNum; ++i)
	{
		if (i == m)
		{
			EdgeNode* pEdgeOut = G.adjList[i].pFirstEdge;
			while (pEdgeOut)
			{
				++iCount;//累加出度
				pEdgeOut = pEdgeOut->next;
			}
		}
		else
		{
			EdgeNode* pEdgeIn = G.adjList[i].pFirstEdge;
			while (pEdgeIn)
			{
				if (pEdgeIn->adjvex == m)
					++iCount;   //累加入度
				pEdgeIn = pEdgeIn->next;
			}
		}
	}
	return iCount;
}


//打印图,领接矩阵表示法
void printGraph(Graph g)
{
	int i, j;
	cout<<"构建的邻接矩阵如下所示" << endl;;
	for (i = 0; i < g.numVertexes; i++)
	{
		for (j = 0; j < g.numVertexes; j++)
		{
			cout<<g.arc[i][j]<<"\t";
		}
		cout << endl;
	}
}

//打印图,邻接表表示法



void printGraph1(AdjListGraph &g)
{
	int i;
	cout << "构建的邻接表如下所示" << endl;
	for (i = 0; i < g.iVexNum; i++)
	{
		EdgeNode* pEdge = g.adjList[i].pFirstEdge;
		while(pEdge){
			cout << g.adjList[i].data<<"-->";
			cout << pEdge->adjvex << "  ";
			pEdge = pEdge->next;
		}
		cout << endl;
		}
}



//邻接表转换为矩阵
void NodeToForm(AdjListGraph &g, Graph &G) {
	G.numVertexes = g.iVexNum;
	G.numEdges = g.iEdgeNum;
	for (int i = 0; i < g.iVexNum; ++i)
	{
		G.vexs[i] = g.adjList[i].data;
	}

	for (int i = 0; i < G.numVertexes; i++)
	{
		for (int j = 0; j < G.numVertexes; j++)
		{
			G.arc[i][j] = INFINITY; 
		}
	}

	for (int i = 0; i < g.iVexNum; i++)
	{
		EdgeNode* pEdge = g.adjList[i].pFirstEdge;
		while (pEdge) {
			int m = GetIndexByVertexVal(g, g.adjList[i].data);
			int n = pEdge->adjvex;
			G.arc[m][n] = pEdge->weight;
			pEdge = pEdge->next;
		}
	}
}

//矩阵转换为邻接表
void FormToNode(AdjListGraph &g, Graph &G) {
	g.iVexNum = G.numVertexes;
	g.iEdgeNum = G.numEdges;

	for (int i = 0; i < G.numVertexes; i++) {
		g.adjList[i].data = G.vexs[i];
	}

	for (int i = 0; i < G.numVertexes; ++i)
	{
		g.adjList[i].pFirstEdge = NULL;
	}

	for (int i = 0; i < G.numVertexes; i++)
	{
		for (int j = 0; j < G.numVertexes; j++)
		{
			if (G.arc[i][j] != INFINITY) {
				EdgeNode* pEdgeNode = new EdgeNode;
				pEdgeNode->weight= G.arc[i][j];
				pEdgeNode->adjvex = j;
				pEdgeNode->next = g.adjList[i].pFirstEdge;
				g.adjList[i].pFirstEdge = pEdgeNode;
			}
		}
	}
}


//验证握手定理
bool HandShake(Graph g) {
	int count = 0;
	for (int i = 0; i < g.numVertexes; i++) {
		for (int j = 0; j < g.numVertexes; j++) {
			if (g.arc[i][j] != INFINITY) {
				count++;
			}
		}
	}
	return g.numEdges*2 == count;
}


//判断连通性
int firstadj(Graph G, int v) {
	for (int i = 0; i < G.numVertexes; i++) {
		if (G.arc[v][i] != INFINITY && visit[i] != true) {
			return i;
			break;
		}
	}
	return -1;
}


int nextadj(Graph G, int v) {
	for (int i = 0; i < G.numVertexes; i++) {
		if (G.arc[v][i] != INFINITY && visit[i] != true) {
			return i;
			break;
		}
	}
	return -1;
}


void dfs(Graph G,int v) {
	visit[v] = true;
	n = n + 1;
	int w = firstadj(G, v);
	while (w != -1) {
		if (!visit[w])
			dfs(G,w);
		w = nextadj(G, v);
	}
}

bool IsCutPoint(Graph G, int v) {
	for (int i = 0; i < G.numVertexes; i++) {
		visit[i] = false;
	}
	dfs(G,v);
	return G.numVertexes == n;
}



//判断是否为树

bool IsTree(Graph G) {

	if (G.numEdges == G.numVertexes - 1) {
		return 1;
	} else return 0;
}


//prime算法最小生成树
void MiniSpanTree_Prime(Graph g)
{
	int min, i, j, k;
	int adjvex[MAXVEX];         //保存相关顶点下标
	int lowcost[MAXVEX];        //保存相关顶点间边的权值
	lowcost[0] = 0;             //初始化第一个权值为0,即v0加入生成树

	adjvex[0] = 0;              //初始化第一个顶点下标为0
	for (i = 1; i < g.numVertexes; i++)
	{
		//循环除下标为0外的全部顶点
		lowcost[i] = g.arc[0][i];   //将v0顶点与之有边的权值存入数组
		adjvex[i] = 0;              //初始化都为v0下标
	}
	for (i = 1; i < g.numVertexes; i++)
	{
		min = INFINITY;             //初始化最小权值为无穷大
		j = 1;
		k = 0;
		while (j < g.numVertexes) //循环全部顶点
		{
			//如果权值不为0,且权值小于min
			if (lowcost[j] != 0 && lowcost[j] < min)
			{
				min = lowcost[j];       //则让当前权值成为最小值
				k = j;                  //将当前最小值的下标存入k
			}
			j++;
		}
		cout<<"("<<adjvex[k]<<","<< k<<")"; //打印当前顶点边中权值最小边
		lowcost[k] = 0;                 //将当前顶点的权值设置为0,表示此顶点已经完成任务

		for (j = 1; j < g.numVertexes; j++)//循环所有顶点
		{
			if (lowcost[j] != 0 && g.arc[k][j] < lowcost[j])
			{
				//若下标为k的顶点各边权值小于此前这些顶点未被加入的生成树权值
				lowcost[j] = g.arc[k][j];
				adjvex[j] = k;              //将下标为k的顶点存入adjvex
			}
		}
	}
	cout << endl;
}

//查找连线顶点的尾部
int Find(int *parent, int f)
{
	while (parent[f] > 0)
	{
		f = parent[f];
	}
	return f;
}

//直接插入排序
void InsertSort(Edge edges[], int k)
{
	int i, j;
	Edge ss;
	for (i = 1; i <= k; i++)
	{
		if (edges[i].weight < edges[i - 1].weight)
		{
			ss = edges[i];
			for (j = i - 1; edges[j].weight > ss.weight; j--)
			{
				edges[j + 1] = edges[j];
			}
			edges[j + 1] = ss;
		}
	}
}


//将邻接矩阵转化为边集数组
void Convert(Graph g, Edge edges[])
{
	int i;
	int j;
	int k;

	k = 0;
	for (i = 0; i < g.numVertexes; i++)
	{
		for (j = i; j < g.numVertexes; j++)
		{
			if (g.arc[i][j] < 65535)
			{
				edges[k].begin = i;
				edges[k].end = j;
				edges[k].weight = g.arc[i][j];
				k++;
			}
		}
	}
	k--;

#ifdef DEBUG
	cout << "k = " << k << endl;
	cout<<"边集数组排序前,如下所示.\n";
	cout<<"edges[]"<<"\t"<<"beign"<<"\t"<<"end"<<"\t"<<"weight"<<"\n";
	for (i = 0; i < k; i++)
	{
		cout<<i;
		cout<<"\t"<<edges[i].begin;
		cout<<"\t"<<edges[i].end;
		cout<<"\t"<<edges[i].weight;
		cout << endl;
	}
#endif

	//下面进行排序
	InsertSort(edges, k);
#ifdef DEBUG
	cout<<"边集数组排序后,如下所示.\n";
	cout << "edges[]" << "\t" << "beign" << "\t" << "end" << "\t" << "weight" << "\n";
	for (i = 0; i < k; i++)
	{
		cout << i;
		cout << "\t" << edges[i].begin;
		cout << "\t" << edges[i].end;
		cout << "\t" << edges[i].weight;
		cout << endl;
	}
#endif
}

//克鲁斯卡尔算法实现
void MiniSpanTree_Kruskal(Graph g)
{
	int i, n, m;
	Edge edges[MAXEDGE];    //定义边集数组
	int parent[MAXVEX];     //定义一数组用来判断边与边是否形成环

							//此处为将邻接矩阵转化为边集数组edges并按权值由小到大排序

	Convert(g, edges);
	//

	for (i = 0; i < g.numVertexes; i++)
	{
		parent[i] = 0;  //初始化数组值为0
	}

	for (i = 0; i < g.numEdges; i++)          //循环每一条边
	{
		n = Find(parent, edges[i].begin);
		m = Find(parent, edges[i].end);
		if (n != m)      //假如n与m不等,说明此边没有与现有生成树形成环路
		{
			parent[n] = m;  //将此边的结尾顶点放入下标为起点的parent中
							//表示此顶点已经在生成树集合中
			cout<<"("<<edges[i].begin<<","<<edges[i].end<<")"<<" "<<edges[i].weight;
		}
	}
	cout << endl;
}

int main(int argc, char **argv)
{
	Graph g;

	//邻接矩阵创建图
	CreateGraph(&g);


	//AdjListGraph G;
	//CreateAdjListGraph(G);
	//printGraph1(G);


	//NodeToForm(G, g);
	//打印网图

	cout << HandShake(g) << endl;
	bool m = IsCutPoint(g, 0);
	bool n = m&IsTree(g);
	cout << m << endl;
	cout << n << endl;

	//FormToNode(G, g);
	//printGraph(g);
	//printGraph1(G);

	//普里姆算法求最小生成树
	//MiniSpanTree_Prime(g);

	//克鲁斯卡尔算法求最小生成树
	//MiniSpanTree_Kruskal(g);

	system("pause");
	return 0;
}
//输入格式:4,4
//输入格式:43 1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值