当前位置:   article > 正文

数据结构——图的基本操作实现_数据结构图的基本操作

数据结构图的基本操作

数据结构——图的基本操作实现

  图的基本操作不算很多,但是从记忆的角度来看算法比较的长,相对而言比较的困难。图的操作以遍历为主,其应用为最小生成树、最短路径、拓扑排序和关键路径求解。其中,最小生成树和最短路径的求法及过程需要大家掌握,而关键路径和拓扑排序只需要掌握过程,算法不要求掌握。这里为了更好的帮助大家理解以及掌握相应的算法,图的每一个操作本人都进行了实现。如果其中有什么不对的地方,还请各位大神指出!

一、图的类型定义。

1.邻接矩阵存储

typedef struct
{
	VerTexType vexs[MVNum];
	ArcType arcs[MVNum][MVNum];
	int vexnum,arcnum;
}AMGraph;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

  这个存储方式是图的常用存储方式,后面的应用中主要以邻接矩阵的形式呈现。

2.邻接表存储

typedef struct ArcNode
{
	int adjvex;
	struct ArcNode *nextarc;
//	OtherInfo info;
}ArcNode;
typedef struct VNode
{
	VerTexType data;
	ArcNode *firstarc;
}VNode,AdjList[MVNum];
typedef struct
{
	AdjList vertices;
	int vexnum,arcnum;
}ALGraph;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

  相较于邻接矩阵,邻接表的形式比较的复杂,在后面的关键路径中采用这种方式实现。

  此外,书上还介绍了十字链表和邻接多重表进行存储,由于在后面的应用中涉及不到,在这里就不进行展示了,有兴趣的话大家可以自己看看。

二、图的建立

1.邻接矩阵建立无向图(有向图)

Status CreateUDN(AMGraph &G)
{
	cout<<"\n请输入顶点个数:"; 
	cin>>G.vexnum;
	cout<<"请输入边的个数:";
	cin>>G.arcnum;
	cout<<"请输入顶点名称:"<<endl;
	for (int i=0;i<G.vexnum;i++)
		cin>>G.vexs[i];
	for (int i=0;i<G.vexnum;i++)
	{
		for (int j=0;j<G.vexnum;j++)
			G.arcs[i][j]=MaxInt;
	}
	cout<<"请输入顶点与边权:"<<endl;
	for (int k=0;k<G.arcnum;k++)
	{
		VerTexType v1,v2;
		ArcType w;
		cin>>v1>>v2>>w;
		int i=LocateVexAMG(G,v1);
		int j=LocateVexAMG(G,v2);
		G.arcs[i][j]=w;
		G.arcs[j][i]=G.arcs[i][j];	//这一句话在建立有向图时注释掉
	}
	return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

2.邻接表建立无向图

Status CreateUDG(ALGraph &G)
{
	cout<<"\n请输入顶点个数:"; 
	cin>>G.vexnum;
	cout<<"请输入边的个数:";
	cin>>G.arcnum;
	cout<<"请输入顶点名称:"<<endl;
	for (int i=0;i<G.vexnum;i++)
	{
		cin>>G.vertices[i].data;
		G.vertices[i].firstarc=NULL;
	}
	cout<<"请输入边连接的顶点:"<<endl; 
	for (int k=0;k<G.arcnum;k++)
	{
		VerTexType v1,v2;
		cin>>v1>>v2;
		int i=LocateVexALG(G,v1);
		int j=LocateVexALG(G,v2);
		ArcNode *p1,*p2;
		p1=new ArcNode;
		p1->adjvex=j;
		p1->nextarc=G.vertices[i].firstarc;
		G.vertices[i].firstarc=p1;
		p2=new ArcNode;
		p2->adjvex=i;
		p2->nextarc=G.vertices[j].firstarc;
		G.vertices[j].firstarc=p2;
	}
	return OK;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

  关于图的建立这部分,一个比较重要的函数是LocateVex这个函数,具体的实现过程在最后的完整代码中实现。

三、图的遍历

1.DFS——深度优先搜索

  深度优先算法是图的一个很重要的算法,不管是利用邻接表还是邻接矩阵,都要牢牢掌握其算法要领,这里完成二者在连通图的条件下的代码实现:

bool visited[MVNum];
void DFS_AM(AMGraph G,int v)
{
	cout<<v;
	visited[v]=true;
	for (int w=0;w<G.vexnum;w++)
	{
		if ((G.arcs[v][w]!=0)&&(!visited[w]))
			DFS_AM(G,w);
	}
}

void DFS_AL(ALGraph G,int v)
{
	cout<<v;
	visited[v]=true;
	ArcNode *p;
	p=G.vertices[v].firstarc;
	while (p!=NULL)
	{
		int w=p->adjvex;
		if (!visited[w])
			DFS_AL(G,w);
		p=p->nextarc;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

2.BFS——广度优先搜索

  广度优先搜索的算法实现在这里就不再阐述了,其算法步骤是以广度为参考,不再像DFS一样一条路走到底,具体的代码大家可以参考模板或者其他博主的博客。


在这里插入图片描述

四、图的应用

1.最小生成树

(1)Prim算法

  Prim算法的精髓是根据点的不同,最小生成树也可能不同。根据起始点,找到与该点相关联的其他顶点,选择其中边权值最小的纳入集合,以此类推,最终将所有顶点都纳入集合中,这个就是Prim算法的最小生成树。

struct
{
	VerTexType adjvex;
	ArcType lowcost;
}closeedge[MVNum];
void MiniSpanTree_Prim(AMGraph G,VerTexType u)
{
	int k=LocateVexAMG(G,u);
	for (int j=0;j<G.vexnum;j++)
	{
		if (j!=k)
			closeedge[j]={u,G.arcs[k][j]};
	}
	closeedge[k].lowcost=0;
	int wpl=0;
	for (int i=1;i<G.vexnum;i++)
	{
		int min=MaxInt;
		for (int j=0;j<G.vexnum;j++)
		{
			if (closeedge[j].lowcost!=0&&closeedge[j].lowcost<min)
			{
				min=closeedge[j].lowcost;
				k=j;
			}
		}
		VerTexType u0,v0;
		u0=closeedge[k].adjvex;
		v0=G.vexs[k];
		cout<<u0<<" "<<v0<<" "<<closeedge[k].lowcost<<endl;
		wpl+=closeedge[k].lowcost;
		closeedge[k].lowcost=0;
		for (int j=0;j<G.vexnum;j++)
		{
			if (G.arcs[k][j]<closeedge[j].lowcost)
				closeedge[j]={G.vexs[k],G.arcs[k][j]};
		}
	}
	cout<<"最小生成树总权值为:"<<wpl<<endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
(2)Kruskal算法

  Kruskal算法和Prim算法的不同之处在于:这个图选的是边,以边集为单位,记录各个点是否在同一连通分量上,如果不在则纳入,实现的时候常用并查集(算法)进行实现,但在这里以书上的为标准,采用书上的算法进行实现。

struct node
{
	VerTexType Head;
	VerTexType Tail;
	ArcType lowcost;
}Edge[1000];
int Vexset[MVNum];
bool cmp(node a,node b)
{
	return a.lowcost<b.lowcost;
}
void MiniSpanTree_Kruskal(AMGraph G)
{
	int k=0;
	for (int i=0;i<G.vexnum;i++)
	{
		for (int j=0;j<G.vexnum;j++)
		{
			if (G.arcs[i][j]!=MaxInt)
			{
				Edge[k].Head=G.vexs[i];
				Edge[k].Tail=G.vexs[j];
				Edge[k].lowcost=G.arcs[i][j];
				k++;
			}
		}
	}
	sort(Edge,Edge+k,cmp);
	for (int i=0;i<k;i++)
		Vexset[i]=i;
	int wpl=0;
	for (int i=0;i<k;i++)
	{
		int v1=LocateVexAMG(G,Edge[i].Head);
		int v2=LocateVexAMG(G,Edge[i].Tail);
		int vs1=Vexset[v1];
		int vs2=Vexset[v2];
		if (vs1!=vs2)
		{
			cout<<Edge[i].Head<<" "<<Edge[i].Tail<<" "<<Edge[i].lowcost<<endl;
			wpl+=Edge[i].lowcost;
			for (int j=0;j<G.vexnum;j++)
			{
				if (Vexset[j]==vs2)
					Vexset[j]=vs1;
			}
		}
	}
	cout<<"最小生成树总权值为:"<<wpl<<endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

2.最短路径

  最短路径的算法就不过多的叙述了,直接上代码:

(1)Dijkstra算法——求解从一个点到各个顶点之间的最短路径
void ShortestPath_DIJ(AMGraph G,int v0)
{
	int n=G.vexnum;
	int ans=0;
	int S[MVNum],D[MVNum],Path[MVNum];
	for (int v=0;v<n;v++)
	{
		S[v]=false;
		D[v]=G.arcs[v0][v];
		if (D[v]<MaxInt)
			Path[v]=v0;
		else
			Path[v]=-1;
	}
	S[v0]=true;
	D[v0]=0;
	int v,w;
	for (int i=1;i<n;i++)
	{
		int min=MaxInt;
		for (w=0;w<n;w++)
		{
			if (!S[w]&&D[w]<min)
			{
				v=w;
				min=D[w];
			}
		}
		S[v]=true;
		for (w=0;w<n;w++)
		{
			if (!S[w]&&(D[v]+G.arcs[v][w]<D[w]))
			{
				D[w]=D[v]+G.arcs[v][w];
				Path[w]=v;
			}
		}
	}
	for (int i=0;i<n;i++)
		cout<<G.vexs[v0]<<"---->"<<G.vexs[i]<<":"<<D[i]<<endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
(2)Floyd算法——求解每个顶点之间的最短路径
void ShortestPath_Floyd(AMGraph G)
{
	int D[MVNum][MVNum],Path[MVNum][MVNum];
	for (int i=0;i<G.vexnum;i++)
	{
		for (int j=0;j<G.vexnum;j++)
		{
			D[i][j]=G.arcs[i][j];
			if (D[i][j]<MaxInt&&i!=j)
				Path[i][j]=i;
			else
				Path[i][j]=-1;
		}
	}
	for (int k=0;k<G.vexnum;k++)
	{
		for (int i=0;i<G.vexnum;i++)
		{
			for (int j=0;j<G.vexnum;j++)
			{
				if (D[i][k]+D[k][j]<D[i][j])
				{
					D[i][j]=D[i][k]+D[k][j];
					Path[i][j]=Path[k][j];
				}
			}
		}
	}
	for (int i=0;i<G.vexnum;i++)
	{
		for (int j=0;j<G.vexnum;j++)
		{
			if (i!=j)
				cout<<G.vexs[i]<<"---->"<<G.vexs[j]<<":"<<D[i][j]<<endl;
		}	
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

3.关键路径

  由于本人实力太菜,书上的算法并没有以代码的形式呈现出来,如果哪个大神用书上的算法实现出来,请一定要及时告诉我,我一定会好好的研究这段代码以及实现的过程。在这里放一个另一位大神的代码,个人觉得这个算法的描述比较的清晰,理解起来比较容易。

#include <stdio.h>
#include <stdlib.h>
#define  MAX_VERTEX_NUM 20//最大顶点个数
#define  VertexType int//顶点数据的类型
//建立全局变量,保存边的最早开始时间
VertexType ve[MAX_VERTEX_NUM];
//建立全局变量,保存边的最晚开始时间
VertexType vl[MAX_VERTEX_NUM];
typedef struct ArcNode{
    int adjvex;//邻接点在数组中的位置下标
    struct ArcNode * nextarc;//指向下一个邻接点的指针
    VertexType dut;
}ArcNode;

typedef struct VNode{
    VertexType data;//顶点的数据域
    ArcNode * firstarc;//指向邻接点的指针
}VNode,AdjList[MAX_VERTEX_NUM];//存储各链表头结点的数组

typedef struct {
    AdjList vertices;//图中顶点及各邻接点数组
    int vexnum,arcnum;//记录图中顶点数和边或弧数
}ALGraph;
//找到顶点对应在邻接表数组中的位置下标
int LocateVex(ALGraph G,VertexType u){
    for (int i=0; i<G.vexnum; i++) {
        if (G.vertices[i].data==u) {
            return i;
        }
    }
    return -1;
}
//创建AOE网,构建邻接表
void CreateAOE(ALGraph **G){
    *G=(ALGraph*)malloc(sizeof(ALGraph));
   
    scanf("%d%d",&((*G)->vexnum),&((*G)->arcnum));
    for (int i=0; i<(*G)->vexnum; i++) {
        scanf("%d",&((*G)->vertices[i].data));
        (*G)->vertices[i].firstarc=NULL;
    }
    VertexType initial,end,dut;
    for (int i=0; i<(*G)->arcnum; i++) {
        scanf("%d%d%d",&initial,&end,&dut);
       
        ArcNode *p=(ArcNode*)malloc(sizeof(ArcNode));
        p->adjvex=LocateVex(*(*G), end);
        p->nextarc=NULL;
        p->dut=dut;
       
        int locate=LocateVex(*(*G), initial);
        p->nextarc=(*G)->vertices[locate].firstarc;
        (*G)->vertices[locate].firstarc=p;
    }
}
//结构体定义栈结构
typedef struct stack{
    VertexType data;
    struct stack * next;
}stack;

stack *T;

//初始化栈结构
void initStack(stack* *S){
    (*S)=(stack*)malloc(sizeof(stack));
    (*S)->next=NULL;
}
//判断栈是否为空
bool StackEmpty(stack S){
    if (S.next==NULL) {
        return true;
    }
    return false;
}
//进栈,以头插法将新结点插入到链表中
void push(stack *S,VertexType u){
    stack *p=(stack*)malloc(sizeof(stack));
    p->data=u;
    p->next=NULL;
    p->next=S->next;
    S->next=p;
}
//弹栈函数,删除链表首元结点的同时,释放该空间,并将该结点中的数据域通过地址传值给变量i;
void pop(stack *S,VertexType *i){
    stack *p=S->next;
    *i=p->data;
    S->next=S->next->next;
    free(p);
}
//统计各顶点的入度
void FindInDegree(ALGraph G,int indegree[]){
    //初始化数组,默认初始值全部为0
    for (int i=0; i<G.vexnum; i++) {
        indegree[i]=0;
    }
    //遍历邻接表,根据各链表中结点的数据域存储的各顶点位置下标,在indegree数组相应位置+1
    for (int i=0; i<G.vexnum; i++) {
        ArcNode *p=G.vertices[i].firstarc;
        while (p) {
            indegree[p->adjvex]++;
            p=p->nextarc;
        }
    }
}

bool TopologicalOrder(ALGraph G){
    int indegree[G.vexnum];//创建记录各顶点入度的数组
    FindInDegree(G,indegree);//统计各顶点的入度
    //建立栈结构,程序中使用的是链表
    stack *S;
    //初始化栈
    initStack(&S);
    for (int i=0; i<G.vexnum; i++) {
        ve[i]=0;
    }
    //查找度为0的顶点,作为起始点
    for (int i=0; i<G.vexnum; i++) {
        if (!indegree[i]) {
            push(S, i);
        }
    }
    int count=0;
    //栈为空为结束标志
    while (!StackEmpty(*S)) {
        int index;
        //弹栈,并记录栈中保存的顶点所在邻接表数组中的位置
        pop(S,&index);
        //压栈,为求各边的最晚开始时间做准备
        push(T, index);
        ++count;
        //依次查找跟该顶点相链接的顶点,如果初始入度为1,当删除前一个顶点后,该顶点入度为0
        for (ArcNode *p=G.vertices[index].firstarc; p ; p=p->nextarc) {
           
            VertexType k=p->adjvex;
           
            if (!(--indegree[k])) {
                //顶点入度为0,入栈
                push(S, k);
            }
            //如果边的源点的最长路径长度加上边的权值比汇点的最长路径长度还长,就覆盖ve数组中对应位置的值,最终结束时,ve数组中存储的就是各顶点的最长路径长度。
            if (ve[index]+p->dut>ve[k]) {
                ve[k]=ve[index]+p->dut;
            }
        }
    }
    //如果count值小于顶点数量,表明有向图有环
    if (count<G.vexnum) {
        printf("该图有回路");
        return false;
    }
    return true;
}
//求各顶点的最晚发生时间并计算出各边的最早和最晚开始时间
void CriticalPath(ALGraph G){
    if (!TopologicalOrder(G)) {
        return ;
    }
    for (int i=0 ; i<G.vexnum ; i++) {
        vl[i]=ve[G.vexnum-1];
    }
    int j,k;
    while (!StackEmpty(*T)) {
        pop(T, &j);
        for (ArcNode* p=G.vertices[j].firstarc ; p ; p=p->nextarc) {
            k=p->adjvex;
            //构建Vl数组,在初始化时,Vl数组中每个单元都是18,如果每个边的汇点-边的权值比源点值小,就保存更小的。
            if (vl[k]-p->dut<vl[j]) {
                vl[j] = vl[k]-p->dut;
            }
        }
    }
    for (j = 0; j < G.vexnum; j++) {
        for (ArcNode*p = G.vertices[j].firstarc; p ;p = p->nextarc) {
            k = p->adjvex;
            //求各边的最早开始时间e[i],等于ve数组中相应源点存储的值
            int ee = ve[j];
            //求各边的最晚开始时间l[i],等于汇点在vl数组中存储的值减改边的权值
            int el = vl[k]-p->dut;
            //判断e[i]和l[i]是否相等,如果相等,该边就是关键活动,相应的用*标记;反之,边后边没标记
            char tag = (ee==el)?'*':' ';
            printf("%3d%3d%3d%3d%3d%2c\n",j,k,p->dut,ee,el,tag);
        }
    }
}
int main(){
    ALGraph *G;
    CreateAOE(&G);//创建AOE网
    initStack(&T);
    TopologicalOrder(*G);
    CriticalPath(*G);
    return  0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
'
运行

五、完整代码的实现

#include <bits/stdc++.h>
#define Status int
#define OK 1
#define MaxInt 32767
#define MVNum 100
using namespace std;

typedef char VerTexType;
typedef int ArcType;
typedef struct
{
	VerTexType vexs[MVNum];
	ArcType arcs[MVNum][MVNum];
	int vexnum,arcnum;
}AMGraph;
typedef struct ArcNode
{
	int adjvex;
	struct ArcNode *nextarc;
//	OtherInfo info;
}ArcNode;
typedef struct VNode
{
	VerTexType data;
	ArcNode *firstarc;
}VNode,AdjList[MVNum];
typedef struct
{
	AdjList vertices;
	int vexnum,arcnum;
}ALGraph;

void Menu()
{
	cout<<"图的操作实现"<<endl;
	cout<<"1.无向图的建立(邻接矩阵)"<<endl;
	cout<<"2.无向图的建立(邻接表)"<<endl;
	cout<<"3.DFS图的遍历(邻接矩阵)"<<endl;
	cout<<"4.DFS图的遍历(邻接表)"<<endl;
	cout<<"5.最小生成树——普利姆算法"<<endl;
	cout<<"6.最小生成树——克鲁斯卡尔算法"<<endl;
	cout<<"7.最短路径——迪杰斯特拉算法"<<endl;
	cout<<"8.最短路径——弗洛伊德算法"<<endl;
	cout<<"0.退出"<<endl;
	cout<<"请选择服务:"; 
}

int LocateVexAMG(AMGraph G,VerTexType v)
{
	for (int i=0;i<G.vexnum;i++)
	{
		if (v==G.vexs[i])
			return i;
	}
}
int LocateVexALG(ALGraph G,VerTexType v)
{
	for (int i=0;i<G.vexnum;i++)
	{
		if (G.vertices[i].data==v)
			return i;
	}
}

Status CreateUDN(AMGraph &G)
{
	cout<<"\n请输入顶点个数:"; 
	cin>>G.vexnum;
	cout<<"请输入边的个数:";
	cin>>G.arcnum;
	cout<<"请输入顶点名称:"<<endl;
	for (int i=0;i<G.vexnum;i++)
		cin>>G.vexs[i];
	for (int i=0;i<G.vexnum;i++)
	{
		for (int j=0;j<G.vexnum;j++)
			G.arcs[i][j]=MaxInt;
	}
	cout<<"请输入顶点与边权:"<<endl;
	for (int k=0;k<G.arcnum;k++)
	{
		VerTexType v1,v2;
		ArcType w;
		cin>>v1>>v2>>w;
		int i=LocateVexAMG(G,v1);
		int j=LocateVexAMG(G,v2);
		G.arcs[i][j]=w;
		G.arcs[j][i]=G.arcs[i][j];
	}
	return OK;
}

void PrintUDN(AMGraph G)
{
	for (int i=0;i<G.vexnum;i++)
	{
		for (int j=0;j<G.vexnum;j++)
			cout<<G.arcs[i][j]<<"\t";
		cout<<endl;
	}
}

Status CreateUDG(ALGraph &G)
{
	cout<<"\n请输入顶点个数:"; 
	cin>>G.vexnum;
	cout<<"请输入边的个数:";
	cin>>G.arcnum;
	cout<<"请输入顶点名称:"<<endl;
	for (int i=0;i<G.vexnum;i++)
	{
		cin>>G.vertices[i].data;
		G.vertices[i].firstarc=NULL;
	}
	cout<<"请输入边连接的顶点:"<<endl; 
	for (int k=0;k<G.arcnum;k++)
	{
		VerTexType v1,v2;
		cin>>v1>>v2;
		int i=LocateVexALG(G,v1);
		int j=LocateVexALG(G,v2);
		ArcNode *p1,*p2;
		p1=new ArcNode;
		p1->adjvex=j;
		p1->nextarc=G.vertices[i].firstarc;
		G.vertices[i].firstarc=p1;
		p2=new ArcNode;
		p2->adjvex=i;
		p2->nextarc=G.vertices[j].firstarc;
		G.vertices[j].firstarc=p2;
	}
	return OK;
}

void PrintUDG(ALGraph G)
{
	for (int i=0;i<G.vexnum;i++)
	{
		ArcNode *p=G.vertices[i].firstarc;
		cout<<G.vertices[i].data<<"\t";
		while (p)
		{
			cout<<p->adjvex<<"\t";
			p=p->nextarc;
		}
		cout<<endl;
	}
}

bool visited[MVNum];
void DFS_AM(AMGraph G,int v)
{
	cout<<v;
	visited[v]=true;
	for (int w=0;w<G.vexnum;w++)
	{
		if ((G.arcs[v][w]!=0)&&(!visited[w]))
			DFS_AM(G,w);
	}
}

void DFS_AL(ALGraph G,int v)
{
	cout<<v;
	visited[v]=true;
	ArcNode *p;
	p=G.vertices[v].firstarc;
	while (p!=NULL)
	{
		int w=p->adjvex;
		if (!visited[w])
			DFS_AL(G,w);
		p=p->nextarc;
	}
}

struct
{
	VerTexType adjvex;
	ArcType lowcost;
}closeedge[MVNum];
void MiniSpanTree_Prim(AMGraph G,VerTexType u)
{
	int k=LocateVexAMG(G,u);
	for (int j=0;j<G.vexnum;j++)
	{
		if (j!=k)
			closeedge[j]={u,G.arcs[k][j]};
	}
	closeedge[k].lowcost=0;
	int wpl=0;
	for (int i=1;i<G.vexnum;i++)
	{
		int min=MaxInt;
		for (int j=0;j<G.vexnum;j++)
		{
			if (closeedge[j].lowcost!=0&&closeedge[j].lowcost<min)
			{
				min=closeedge[j].lowcost;
				k=j;
			}
		}
		VerTexType u0,v0;
		u0=closeedge[k].adjvex;
		v0=G.vexs[k];
		cout<<u0<<" "<<v0<<" "<<closeedge[k].lowcost<<endl;
		wpl+=closeedge[k].lowcost;
		closeedge[k].lowcost=0;
		for (int j=0;j<G.vexnum;j++)
		{
			if (G.arcs[k][j]<closeedge[j].lowcost)
				closeedge[j]={G.vexs[k],G.arcs[k][j]};
		}
	}
	cout<<"最小生成树总权值为:"<<wpl<<endl;
}

struct node
{
	VerTexType Head;
	VerTexType Tail;
	ArcType lowcost;
}Edge[1000];
int Vexset[MVNum];
bool cmp(node a,node b)
{
	return a.lowcost<b.lowcost;
}
void MiniSpanTree_Kruskal(AMGraph G)
{
	int k=0;
	for (int i=0;i<G.vexnum;i++)
	{
		for (int j=0;j<G.vexnum;j++)
		{
			if (G.arcs[i][j]!=MaxInt)
			{
				Edge[k].Head=G.vexs[i];
				Edge[k].Tail=G.vexs[j];
				Edge[k].lowcost=G.arcs[i][j];
				k++;
			}
		}
	}
	sort(Edge,Edge+k,cmp);
	for (int i=0;i<k;i++)
		Vexset[i]=i;
	int wpl=0;
	for (int i=0;i<k;i++)
	{
		int v1=LocateVexAMG(G,Edge[i].Head);
		int v2=LocateVexAMG(G,Edge[i].Tail);
		int vs1=Vexset[v1];
		int vs2=Vexset[v2];
		if (vs1!=vs2)
		{
			cout<<Edge[i].Head<<" "<<Edge[i].Tail<<" "<<Edge[i].lowcost<<endl;
			wpl+=Edge[i].lowcost;
			for (int j=0;j<G.vexnum;j++)
			{
				if (Vexset[j]==vs2)
					Vexset[j]=vs1;
			}
		}
	}
	cout<<"最小生成树总权值为:"<<wpl<<endl;
}

void ShortestPath_DIJ(AMGraph G,int v0)
{
	int n=G.vexnum;
	int ans=0;
	int S[MVNum],D[MVNum],Path[MVNum];
	for (int v=0;v<n;v++)
	{
		S[v]=false;
		D[v]=G.arcs[v0][v];
		if (D[v]<MaxInt)
			Path[v]=v0;
		else
			Path[v]=-1;
	}
	S[v0]=true;
	D[v0]=0;
	int v,w;
	for (int i=1;i<n;i++)
	{
		int min=MaxInt;
		for (w=0;w<n;w++)
		{
			if (!S[w]&&D[w]<min)
			{
				v=w;
				min=D[w];
			}
		}
		S[v]=true;
		for (w=0;w<n;w++)
		{
			if (!S[w]&&(D[v]+G.arcs[v][w]<D[w]))
			{
				D[w]=D[v]+G.arcs[v][w];
				Path[w]=v;
			}
		}
	}
	for (int i=0;i<n;i++)
		cout<<G.vexs[v0]<<"---->"<<G.vexs[i]<<":"<<D[i]<<endl;
}

void ShortestPath_Floyd(AMGraph G)
{
	int D[MVNum][MVNum],Path[MVNum][MVNum];
	for (int i=0;i<G.vexnum;i++)
	{
		for (int j=0;j<G.vexnum;j++)
		{
			D[i][j]=G.arcs[i][j];
			if (D[i][j]<MaxInt&&i!=j)
				Path[i][j]=i;
			else
				Path[i][j]=-1;
		}
	}
	for (int k=0;k<G.vexnum;k++)
	{
		for (int i=0;i<G.vexnum;i++)
		{
			for (int j=0;j<G.vexnum;j++)
			{
				if (D[i][k]+D[k][j]<D[i][j])
				{
					D[i][j]=D[i][k]+D[k][j];
					Path[i][j]=Path[k][j];
				}
			}
		}
	}
	for (int i=0;i<G.vexnum;i++)
	{
		for (int j=0;j<G.vexnum;j++)
		{
			if (i!=j)
				cout<<G.vexs[i]<<"---->"<<G.vexs[j]<<":"<<D[i][j]<<endl;
		}	
	}
}

int main()
{
	while (true)
	{
		system("cls");
		AMGraph G1;
		ALGraph G2;
		Menu();
		int x;
		cin>>x;
		switch(x)
		{
			case 1:
				if (CreateUDN(G1)==1)
				{
					cout<<"\n用邻接矩阵创建无向图成功!\n"<<endl;
					cout<<"\n邻接矩阵为:\n"<<endl;
					PrintUDN(G1);
				}	
				else
					cout<<"\n用邻接矩阵创建无向图失败!\n"<<endl;
				break; 
			case 2:
				if (CreateUDG(G2)==1)
				{
					cout<<"\n用邻接表创建无向图成功!\n"<<endl;
					cout<<"\n邻接表为:\n"<<endl;
					PrintUDG(G2);
				}	
				else
					cout<<"\n用邻接表创建无向图失败!\n"<<endl;
				break;
			case 3:
				memset(visited,false,sizeof(visited));
				int v1;
				cout<<"\n请输入起始点编号:";
				cin>>v1;
				cout<<"深度优先遍历的结果为:\n"<<endl;
				DFS_AM(G1,v1);
				cout<<endl;
				break;
			case 4:
				memset(visited,false,sizeof(visited));
				int v2;
				cout<<"\n请输入起始点编号:";
				cin>>v2;
				cout<<"深度优先遍历的结果为:\n"<<endl;
				DFS_AL(G2,v2);
				cout<<endl;
				break;
			case 5:
				cout<<"\n请输入起始点:";
				VerTexType u1;
				cin>>u1;
				cout<<"以该点作为起始点的最小生成树为:(最后一列为权值)"<<endl;
				MiniSpanTree_Prim(G1,u1);
				break;
			case 6:
				cout<<"\n最小生成树为:(最后一列为权值)"<<endl;
				MiniSpanTree_Kruskal(G1);
				break;
			case 7:
				cout<<"\n请选择起始点:";
				VerTexType v0;
				cin>>v0;
				cout<<"从该点出发到其他点的最短路径为:"<<endl;
				ShortestPath_DIJ(G1,LocateVexAMG(G1,v0));
				break;
			case 8:
				cout<<"\n各个顶点到其他点的最短路径为:"<<endl;
				ShortestPath_Floyd(G1);
				break;
			case 0:
				exit(0);
				break;
		}
		system("pause");
	}
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/984732
推荐阅读
相关标签
  

闽ICP备14008679号