#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
图的综合问题
最新推荐文章于 2022-02-08 15:37:01 发布