图论:图的概念与图的储存方式
转载自http://acm.uestc.edu.cn/bbs/read.php?tid=5670
下载ppt帐号:qscqesze
密码:123456
-------------------------------------------------------------------
1.图的基本概念
图:二元组(V, E) 。V 为顶点集。E为V 中结点之间的边的集合。
自环:一条边的两个端点是相同的。
多重边:两个端点之间有两条以上的边,称他们是多重边。
简单图:没有自环和多重边的图
无向边:边是双向的
有向边:单向边,有箭头
无向图:只有无向边的图
有向图:只有有向边的图
顶点的度:
无向图中,一个顶点相连的边数称为该顶点的度。
有向图中,从一个顶点出发的边数称为该顶点得出度;到达该顶点的边数称为它的入度。
权和网:
在图的边给出相关的数,成为权。权可以表示一个顶点到另一个顶点的距离,耗费等。带权图一般成为网。
完全图、稠密图和稀疏图:
任何两个顶点之间都有边(弧)相连称为完全图
边(弧)很少的图称为稀疏图反之为稠密图
2.图的存储
邻接矩阵:
int g[max_v+1][max_v+1]; void init()//初始化 { for(int i=1;i<=max_v;i++) for(int j=1;j<=max_v;j++) { if(i==j) g[i][j]=0; else g[i][j]=inf; } } void add_edge(int a,int b,int c) { g[a][b]=g[b][a]=c;//双向边 //g[a][b]=c;单向边情况 }
空间复杂度:O(V^2)
优点:直观,容易理解,可以直接查看任意两点的关系。
缺点:对于稀疏图,会有很多空间根本没有利用。对于带权图,不能处理重边。要查询某一个顶点的所有边,要枚举V次。
在邻接矩阵表示中,除了存放顶点本身信息外,还用一个矩阵表示各个顶点之间的关系。若(i,j)∈E(G)或〈i,j〉∈E(G),则矩阵中第i行 第j列元素值为1,否则为0 。
图的邻接矩阵定义为:
1 ,若(i,j)∈E(G)或〈i,j〉∈E(G)
A[i][j]=
0 ,其它情形
例如, 下面为两个无向图和有向图对应的邻接矩阵:
类似地可以定义网的邻接矩阵为:
wij 若(i,j)∈E(G)或〈i,j〉∈E(G)
A[i][j]= 0 若i=j
∞ 其它情形
图的存储-邻接表
struct Edge { int u,v;//边权 } vector<Edge> e[max_v+1]; void init()//初始化 { for(int i=1;i<=max_v;i++) e[i].clear(); } void add_edge(int a,int b,int c) { e[a].push_back((Edge){b,c}); e[b].push_back((Edge){a,c});//双向边情况 }
空间复杂度:有向图O(V+E)无向图O(V+2*E)
优点:节省空间,能快速找到某个顶点所有相连的顶点,而无需访问无关顶点。
对图的每个顶点建立一个单链表(n个顶点建立n个单链表),第i个单链表中的结点包含顶点Vi的所有邻接顶点。
图的储存——前向星
nt first[MAXN]; //first[x]表示顶点x连出去的第一条边的存储位置 int next[MAXM]; //next[i]表示第i条边的下一条边的位置 int v[MAXM]; //v[i]表示第i条边的终点 int w[MAXM]; //w[i]表示第i条边的权值 int cnt; //表示当前一共加入多少条边 初始化:memset(first,0,sizeof(first)); memset(next,0,sizeof(next)); 加入一条权值为q的边 x->y : cnt++; next[cnt]=first[x]; first[x]=cnt; v[cnt]=y; w[cnt]=q; 使用:for (int i=first[x];i;i=next[i]) {……} //v[i]即为x发出的点,w[i]为相应边的权值
前向星与邻接表相似,不再过多赘述