栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

图学习笔记

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

图学习笔记

 图的定义

略 

图的储存结构 邻接矩阵

图的邻接矩阵用两个数组表示:

1、一位数组储存顶点信息

2、二位数组储存边信息

#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXVEX 100 
#define INFINITY 65535

typedef int Status;	
typedef char VertexType; 
typedef int EdgeType; 

typedef struct
{
	VertexType vexs[MAXVEX]; 
	EdgeType arc[MAXVEX][MAXVEX];
	int numNodes, numEdges; 
}MGraph;


void CreateMGraph(MGraph *G)
{
	int i,j,k,w;
	printf("输入顶点数和边数:n");
	scanf("%d,%d",&G->numNodes,&G->numEdges); 
	for(i = 0;i numNodes;i++) 
		scanf(&G->vexs[i]);
	for(i = 0;i numNodes;i++)
		for(j = 0;j numNodes;j++)
			G->arc[i][j]=INFINITY;	
	for(k = 0;k numEdges;k++) 
	{
		printf("输入边(vi,vj)上的下标i,下标j和权w:n");
		scanf("%d,%d,%d",&i,&j,&w); 
		G->arc[i][j]=w; 
		G->arc[j][i]= G->arc[i][j]; 
	}
}

int main(void)
{    
	MGraph G;    
	CreateMGraph(&G);
	
	return 0;
}

时间复杂度:

        邻接矩阵O(n^2)

        整体:O(n+n^2+e)

邻接表

对于边数相对较少的图,邻接矩阵十分浪费。

回忆在树的章节,有一种孩子表示法:将结点存入数组,无论有多少孩子,都用链式存储存在后面。这样不会造成空间的浪费。这种方法同样适用于图的存储。

邻接表——数组与链表相结合的储存方式称之为邻接表。

无向图的邻接表

 有向图

 

带权图

 

 

#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXVEX 100 

typedef int Status;	
typedef char VertexType; 
typedef int EdgeType; 

typedef struct EdgeNode 
{
	int adjvex;    
	EdgeType info;		
	struct EdgeNode *next; 
}EdgeNode;

typedef struct VertexNode 
{
	VertexType data; 
	EdgeNode *firstedge;
}VertexNode, AdjList[MAXVEX];

typedef struct
{
	AdjList adjList; 
	int numNodes,numEdges; 
}GraphAdjList;


void  CreateALGraph(GraphAdjList *G)
{
	int i,j,k;
	EdgeNode *e;
	printf("输入顶点数和边数:n");
	scanf("%d,%d",&G->numNodes,&G->numEdges); 
	for(i = 0;i < G->numNodes;i++) 
	{
		scanf(&G->adjList[i].data); 	
		G->adjList[i].firstedge=NULL; 	
	}
	
	for(k = 0;k < G->numEdges;k++)
	{
		printf("输入边(vi,vj)上的顶点序号:n");
		scanf("%d,%d",&i,&j); 
		e=(EdgeNode *)malloc(sizeof(EdgeNode)); 
		e->adjvex=j;					                         
		e->next=G->adjList[i].firstedge;	
		G->adjList[i].firstedge=e;		               
		
		e=(EdgeNode *)malloc(sizeof(EdgeNode)); 
		e->adjvex=i;					                         
		e->next=G->adjList[j].firstedge;	
		G->adjList[j].firstedge=e;		               
	}
}

int main(void)
{    
	GraphAdjList G;    
	CreateALGraph(&G);
	
	return 0;
}

在插入的时候适用了“头插法”

时间复杂度:O(n+e)

十字链表 邻接多重表 边集数组 图的抽象数据类型

图的基本操作要一个一个实现一下

图的遍历 深度优先遍历 DFS 广度优先遍历 BFS 最小生成树 普里姆算法 Prim 克鲁斯卡尔算法 Kruskal

Prim算法是以某结点为起点,逐步寻找顶点上的最小权值来构造最小生成树。

但事实上,还有另一种思考方式:

就像我们去迪士尼游玩,会先挑选出自己想玩的项目再确定路线,

同样,我们也可以以边为目标来构造,这就是Kruskal算法。

所以现在要构造一棵最小生成树,我们的思路就是先把边按照权值排序(就像游玩的期待值),

之后把它们依次选中(在不会与之前的边生成环的情况下),这样循环完整个图,就可以得到一棵树(不含有环)。

所以我们要解决的主要问题有两个:

1.排序

2.判断是否会形成环

我们一个一个解决:

1.排序

这一步比较简单,程序中通过建立一个数组来完成edges;同时构造了两个辅助函数swap,sort;

2.判断是否会形成环

这是整个算法很重要的部分

设定parent数组,帮助判断,构造Find函数。while循环判断条件为 parent[f] > 0,也就是说直到找到小于0的值,即端点才会停止。

(这里不需要担心边方向问题,因为虽然是无向图,但是在定义边结点时事实上是有默认方向的)

(给出一个例子)

int Find(int *parent, int f)
{
	while ( parent[f] > 0)//一直到找到端点为止 
	{
		f = parent[f];
	}
	return f;
}

完整代码: 

#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status;	

#define MAXEDGE 20
#define MAXVEX 20
#define INFINITY 65535

typedef struct
{
	int arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}MGraph;

typedef struct
{
	int begin;
	int end;
	int weight;
}Edge;   


void CreateMGraph(MGraph *G)
{
	int i, j;

	
	G->numEdges=15;
	G->numVertexes=9;

	for (i = 0; i < G->numVertexes; i++)
	{
		for ( j = 0; j < G->numVertexes; j++)
		{
			if (i==j)
				G->arc[i][j]=0;
			else
				G->arc[i][j] = G->arc[j][i] = INFINITY;
		}
	}

	G->arc[0][1]=10;
	G->arc[0][5]=11; 
	G->arc[1][2]=18; 
	G->arc[1][8]=12; 
	G->arc[1][6]=16; 
	G->arc[2][8]=8; 
	G->arc[2][3]=22; 
	G->arc[3][8]=21; 
	G->arc[3][6]=24; 
	G->arc[3][7]=16;
	G->arc[3][4]=20;
	G->arc[4][7]=7; 
	G->arc[4][5]=26; 
	G->arc[5][6]=17; 
	G->arc[6][7]=19; 

	for(i = 0; i < G->numVertexes; i++)
	{
		for(j = i; j < G->numVertexes; j++)
		{
			G->arc[j][i] =G->arc[i][j];
		}
	}

}


void Swapn(Edge *edges,int i, int j)
{
	int temp;
	temp = edges[i].begin;
	edges[i].begin = edges[j].begin;
	edges[j].begin = temp;
	temp = edges[i].end;
	edges[i].end = edges[j].end;
	edges[j].end = temp;
	temp = edges[i].weight;
	edges[i].weight = edges[j].weight;
	edges[j].weight = temp;
}


void sort(Edge edges[],MGraph *G)
{
	int i, j;
	for ( i = 0; i < G->numEdges; i++)
	{
		for ( j = i + 1; j < G->numEdges; j++)
		{
			if (edges[i].weight > edges[j].weight)
			{
				Swapn(edges, i, j);
			}
		}
	}
	printf("权排序之后的为:n");
	for (i = 0; i < G->numEdges; i++)
	{
		printf("(%d, %d) %dn", edges[i].begin, edges[i].end, edges[i].weight);
	}

}


int Find(int *parent, int f)
{
	while ( parent[f] > 0)//一直到找到端点为止 
	{
		f = parent[f];
	}
	return f;
}


void MiniSpanTree_Kruskal(MGraph G)
{
	int i, j, n, m;
	int k = 0;
	int parent[MAXVEX];
	
	Edge edges[MAXEDGE];

	
	for ( i = 0; i < G.numVertexes-1; i++)
	{
		for (j = i + 1; j < G.numVertexes; j++)
		{
			if (G.arc[i][j] 
最短路径 

在有权图和无权图之中,最短路径的含义不同。

无权图:经过边数最少的路径;

有权图: 两顶点经过边上权值和最小;

显然研究有权图更具有实用价值。(无权图可以转化为权值为1的有权图)

迪杰斯特拉(Dijkstra)算法 Dijkstra算法大致的思路:

1、准备工作

(1)设立两个数组保存结果 P[ ]  D[ ] 

P[v]的值是v的前驱顶底下标       

D[v]表示v0(可以改为其他节点)到v的最短路径长度

(2)设置一个辅助数组final[ ]

final[v]==0表示该点还未确定路径;==1表示已经确定路径;

(3)将他们全部初始化,D[ v ] 导入G.matirx[ v0 ][ v ], P[ v ] 全部设为0 ,final[ ]全部设为0;

2、主要实现

主循环,每次都求得v0到某个点v的最短路径,这就是为什么我们要执行v

主循环里面的第一个循环找到还未确定路径中的最短路径。(因为这一段是所剩最短的,是可以确定下来的)

一定要注意,由于上一句话我们是默认的,所以Dijkstra算法是不适用与权值为负的情况的。

主循环内第二个循环,是用新确定的最短路径去更新其他未确定的路径。

如何更新?

假设在第一个循环找到的最短路径长min,顶点为k,到m顶点的路径还未确定。

则我们要比较以k为跳板,即先从v0走目前的最小路径到k,再从k直接到m,与原本的路径相比是否会更小,若更小,则替换。(D[ ] ,P [ ]都要替换)

#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXEDGE 20
#define MAXVEX 20
#define INFINITY 65535

typedef int Status;	 


typedef struct
{
	int vexs[MAXVEX];
	int arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}MGraph;

typedef int Patharc[MAXVEX];    
typedef int ShortPathTable[MAXVEX];


void CreateMGraph(MGraph *G)
{
	int i, j;

	
	G->numEdges=16;
	G->numVertexes=9;

	for (i = 0; i < G->numVertexes; i++)
	{
		G->vexs[i]=i;
	}

	for (i = 0; i < G->numVertexes; i++)
	{
		for ( j = 0; j < G->numVertexes; j++)
		{
			if (i==j)
				G->arc[i][j]=0;
			else
				G->arc[i][j] = G->arc[j][i] = INFINITY;
		}
	}

	G->arc[0][1]=1;
	G->arc[0][2]=5; 
	G->arc[1][2]=3; 
	G->arc[1][3]=7; 
	G->arc[1][4]=5; 

	G->arc[2][4]=1; 
	G->arc[2][5]=7; 
	G->arc[3][4]=2; 
	G->arc[3][6]=3; 
	G->arc[4][5]=3;

	G->arc[4][6]=6;
	G->arc[4][7]=9; 
	G->arc[5][7]=5; 
	G->arc[6][7]=2; 
	G->arc[6][8]=7;

	G->arc[7][8]=4;


	for(i = 0; i < G->numVertexes; i++)
	{
		for(j = i; j < G->numVertexes; j++)
		{
			G->arc[j][i] =G->arc[i][j];
		}
	}

}

    
  
void ShortestPath_Dijkstra(MGraph G, int v0, Patharc *P, ShortPathTable *D)
{    
	int v,w,k,min;    
	int final[MAXVEX];
	for(v=0; v 
弗洛伊德(Floyd)算法 

先举一个简单 的例子:

初始化

三层循环

输出

时间复杂度

使用条件(权值有负值的情况)

#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXEDGE 20
#define MAXVEX 20
#define INFINITY 65535

typedef int Status;	

typedef struct
{
	int vexs[MAXVEX];
	int arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}MGraph;

typedef int Patharc[MAXVEX][MAXVEX];
typedef int ShortPathTable[MAXVEX][MAXVEX];


void CreateMGraph(MGraph *G)
{
	int i, j;

	
	G->numEdges=16;
	G->numVertexes=9;

	for (i = 0; i < G->numVertexes; i++)
	{
		G->vexs[i]=i;
	}

	for (i = 0; i < G->numVertexes; i++)
	{
		for ( j = 0; j < G->numVertexes; j++)
		{
			if (i==j)
				G->arc[i][j]=0;
			else
				G->arc[i][j] = G->arc[j][i] = INFINITY;
		}
	}

	G->arc[0][1]=1;
	G->arc[0][2]=5; 
	G->arc[1][2]=3; 
	G->arc[1][3]=7; 
	G->arc[1][4]=5; 

	G->arc[2][4]=1; 
	G->arc[2][5]=7; 
	G->arc[3][4]=2; 
	G->arc[3][6]=3; 
	G->arc[4][5]=3;

	G->arc[4][6]=6;
	G->arc[4][7]=9; 
	G->arc[5][7]=5; 
	G->arc[6][7]=2; 
	G->arc[6][8]=7;

	G->arc[7][8]=4;


	for(i = 0; i < G->numVertexes; i++)
	{
		for(j = i; j < G->numVertexes; j++)
		{
			G->arc[j][i] =G->arc[i][j];
		}
	}

}

    
void ShortestPath_Floyd(MGraph G, Patharc *P, ShortPathTable *D)
{    
	int v,w,k;    
	for(v=0; v(*D)[v][k]+(*D)[k][w])
				{
					(*D)[v][w]=(*D)[v][k]+(*D)[k][w];
					(*P)[v][w]=(*P)[v][k];
				}
			}
		}
	}
}

int main(void)
{    
	int v,w,k;  
	MGraph G;    
	
	Patharc P;    
	ShortPathTable D;    
	
	CreateMGraph(&G);
	
	ShortestPath_Floyd(G,&P,&D);  

	printf("各顶点间最短路径如下:n");    
	for(v=0; v %d",k);	
				k=P[k][w];			
			}
			printf(" -> %dn",w);	
		}
		printf("n");
	}

	printf("最短路径Dn");
	for(v=0; v 

未完待续。。。 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/665520.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号