定义:
图是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中的顶点的集合,E是图G中边的集合
各种图的定义
1.无向边:若顶点vi到vj之间没有方向,则称这条边为无向边,有无序偶对(vi,vj)来表示。
2.无向图:如果图中任意两个顶点之间的边都是无向边,则称该图为无向图
3.有向边:若从顶点vi到vj的边有方向为有向边,也称为弧,用 有序偶< vi, vj> 来表示,vi称为弧尾,vj 称为弧头。
4.有向图:如果图中任意两个顶点之间的边都是有向边,则称该图为有向图。
5.简单图:在图中,如果不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图。
6.无向完全图:在无向图,如果任意两个顶点之间都有存在边,则称该图为无向完全图。
7.有向完全图:在有向图中,如果任意两个顶点之间都存在互为相反的弧,则称该图为有向完全图
8.稀疏图&稠密图:有很少的边或弧的图称为稀疏图,反之称为稠密图
9.权:有些图的边或者弧具有与他相关的数字,这个相关的数称为权
10.网:这种带权的图通常称为网
图的顶点与边间的关系
1.对于无向图G=(V,{E}),如果边(v1,v2)∈E , 则称顶点v1和v2互为邻接,即v1,v2相邻接。边(v1,v2)依附于顶点v1和v2,或者说(v1,v2)于顶点v1,v2相关联。顶点v的度为是和v相关联的边的数目,记做TD(v)
2.对于有向图G=(V,{E}),如果弧< v1,v2>∈E,则称顶点v1邻接到顶点v2,顶点v2邻接自顶点v1.弧< v1,v2>和顶点v1,v2相关联,自顶点v1为头的弧的数目为v1的入度,记为ID(v),以v1为弧尾的弧的数目称为v1的出度,记为OD(v),顶点v的度TD(v)=ID(v)+OD(v).
3.路径:无向图G(V,{E})中从顶点v1到顶点v2的路径是从v1到v2途经顶点的序列
路径的长度:路径上的边或者弧的数目
4.回路(环):第一个顶点到最后一个顶点相同的路径称为回路或者环
5.简单路径:序列中顶点不重复出现的路径称为简单路径
6.简单回路(环):除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路,称为简单回路或者简单环
连通图相关的术语
1.连通: 在无向图G中,如果从顶点v1到顶点v2有路径,则称v1和v2是连通的
2.连通图:如果对于无向图中任意两个顶点vi,vj,vi和vj都是连通的,则称该图是连通图
3.连通分量:无向图中的极大连通子图称为连通分量。
4.强连通图:在有向图中,任如果意两个顶点vi,vj,vi和vj都是连通的,则称该图是强连通图
5.强连通分量:有向图中的极大强连通子图称作有向图的强连通分量
图的储存结构
**1.**邻接矩阵
图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息。
实现代码
#define MAX 10
typedef struct _Vertex{
int num;//顶点编号
int info;//顶点的其他附加信息,可以不要
}Vertex;
//图的结构信息
typedef struct _Graph{
int vertex_num; //图中顶点数目
int edge_num; //图中边或弧的数目
Vertex vertex[MAX]; //顶点数组
int edges[MAX][MAX]; //邻接矩阵,存储图中边或或弧的信息
}Graph;
**2.**邻接表
邻接矩阵是不错的一种图存储结构,但是,对于边数相对顶点较少的图,这种结构存在对存储空间的极大浪费。因此,找到一种数组与链表相结合的存储方法称为邻接表。
邻接表的处理方法:
1.图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过,数组可以较容易的读取顶点的信息,更加方便。
2.图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以,用单链表存储,无向图称为顶点vi的边表,有向图则称为顶点vi作为弧尾的出边表。
实现代码
typedef struct Node
{
int dest; //邻接边的弧头结点序号
int weight; //权值信息
struct Node *next; //指向下一条邻接边
}Edge; //单链表结点的结构体
typedef struct
{
DataType data; //结点的一些数据,比如名字
int sorce; //邻接边的弧尾结点序号
Edge *adj; //邻接边头指针
}AdjHeight; //数组的数据元素类型的结构体
typedef struct
{
AdjHeight a[MaxVertices]; //邻接表数组
int numOfVerts; //结点个数
int numOfEdges; //边个数
}AdjGraph; //邻接表结构体
无向图的邻接表
void GreateMGraph(MGraph * G)
{
int i,j,k,w;
scanf("%d%d",&G->numVertexes,&G->numEdge);
for(i=0;i<G->numVertexes;i++) /*读入顶点信息,建立顶点表*/
{
scanf(" %c",&G->vexs[i]);
}
for(i=0;i<G->numVertexes;i++)
for(j=0;j<G->numVertexes;j++)
G->arc[i][j]=INFINITY; /*邻接矩阵初始化*/
for(k=0;k<G->numEdge;k++) /*读入numEdges条边,建立邻接矩阵*/
{
scanf("%d,%d,%d",&i,&j,&w);
G->arc[i][j]=w;
G->arc[j][i]=G->arc[i][j];
}
}
图的遍历
俩种方法
一.深度优先遍历(又称为深度优先搜索)
思想
1.从图中某个顶点vi出发,访问vi;然后找到vi的一个邻接顶点vi1
2.从vi1出发,深度优先搜索访问和vi1相邻接且未被访问的所有顶点
3.转⑴ ,直到和vi相邻接的所有顶点都被访问为止
4.继续选取图中未被访问顶点vj作为起始顶点,转到1 直到图中所有顶点都被访问为止。
实现代码
void DFS1 (MGraph MG, int i)
{ int j;
visited[i]=1;
printf("%3c",MG.vexs[i]);
for(j=1; j<=MG.vex_num; j++)
if(!visited[j]&&MG.arcs[i][j]==1)
DFS1 (MG, j);
}
void DFS2(AdjList G,int i)
{ int j;
EdgeLinklist *p;
visited[i]=1;
printf("%3c",G.vertices[i].Elem);
for(p=G.vertices[i].firstedge;p;p=p->next)
{j=p->adjvex;
if(!visited[j])
DFS2(G, j); }
}
二.广度优先搜索:
思想
1.从图中某个顶点vi出发,访问vi;
2.访问vi的所有相邻接且未被访问的所有顶点vi1,vi2,…,vim;
3.以vi1,vi2, …,vim的次序,以vij(1≦j≦m)依此作为vi ,转⑴;
4.继续选取图中未被访问顶点vk作为起始顶点,转 1,直到图中所有顶点都被访问为止。
实现代码
void BFS1(Mgraph G ,int k)
{ int i,j;
int visited[Vex_num];
SqQueue q;
initqueue(&q);
printf("visit vertex: V%d\n", G->vexs[k]);
visited[k]=1;
Enqueue(&q,k);
while(!QueueEmpty(&q))
{
i=Dequeue(&q);
for(j=0; j<G->n; j++)
{
printf("visit vertex :V%d \n",G->vexs[j]);
visited[j]=1;
Enqueue(&q,j);
}
}
}
最小生成树
定义:我们把构造连通网的最小代价生成树称为最小生成树
找连通网的最小生成树的俩种经典算法
1.普里姆算法
2.克鲁斯卡尔算法
最短路径
详见
https://blog.csdn.net/sheep_princess/article/details/104418671
拓扑排序
详见
https://blog.csdn.net/sheep_princess/article/details/104419051