图的存储方式
1.邻接矩阵
2.邻接表
3.链式前向星
4.边集数组
常见的图的存储结构有以上四种。
一.邻接矩阵(顺序存储)
邻接矩阵的优点:
①便于找任意顶点的邻接点。
②便于计算任意顶点的度
邻接矩阵的局限性 时间复杂度O(n2),空间复杂度(n2);
①浪费空间;对于稠密图还合算,对于稀疏图就有大量无效元素。且元素定为int时,顶点多了容易爆内存
②浪费时间;时间复杂度O(n2);
无向图邻接矩阵是对称的,有向图不对称,且行为该顶点出度,列为该顶点入度。
struct node{
int no;//顶点编号
char data;//顶点信息
}
struct Graph{
int n;//顶点数
int e;//顶点边数
int Edges[MAX][MAX];//邻接矩阵
node vertex[MAX];//顶点表
}
Graph G;
void Create(){
cin>>G.n>>G.e;
for(int i=1;i<=G.e;i++){
cin>>u>>v>>w;
G.Edges[u][v]=w;
G.Edges[v][u]=w;
}
//还有顶点信息可根据需要输入。
}
领接表(链式存储)
包括顶点表和边表
定点表数据包括顶点的信息和这个顶点所连的边链表的头指针
边表数据包括顶点的邻接点的下标,边的权值,连接下一条边的指针
在邻接表中,每个顶点建立一个单链表,每个单链表附设表头结点。
特点如下:
①领接表不唯一。与各个顶点的邻接边输入次序有关。
②对于n个顶点,e条边的无向图,领接表有2e个边节点。比邻接矩阵省空间。
③对于有向图,顶点对应的链表边表节点数表示出度,入度往往要遍历整个邻接表,这也是其局限性。
//边表结构
struct ANode{
int adjvex;//顶点下标
int weight;
ANode* next;
ANode(int tmpAdjvex,int tmpWeight,ANode* tmpnode=NULL){
adjvex=tmpAdjvex;
weight=tmpWeight;
next=tmpnode;
}
}
//顶点表
struct Vnode{
char data;//顶点信息
ANode* head;//头指针
Vnode(char data,ANode* tmphead=NULL){
data=data;
head=tmphead;
}
Vnode(ANode* tmphead=NULL){
head=tmphead;
}
}
Vnode AdjList[MAX];
//一般为节省时间下面代码可不写
struct Graph{
int n,e;
Vnode AdjList[MAX];
}
//初始化
ANode* nodes[MAX];
void Init(){
ANode* p;
cin>>n>>e;
for(int i=1;i<=n;i++){
cin>>AdjList[i].data;
AdjList[i].head=NULL;
}
//创建边
for(int j=1;j<=e;j++){
cin>>u>>v>>w;
ANode node=new ANode(v,w);
p=AdjList[u].head;
if(p==NULL){
p=node;
}else{
while(p->next!=NULL){
p=p->next;
}
p->next=node;
}
}
}
链式前向星
1.结构
struct Edge{
int to;//这条边的终点
int w;//权值
int next;//同一个起点的下一条边
}Edges[100];
2.增边
int num=0;
void add(int u,int v,int w){
++num;
Edges[num].to=v;
Edges[num].w=w;
Edges[num].next=head[u];
head[u]=num;
}
3.遍历一个顶点的边
for(int i=head[u];i!=0;i=Edges[i].next)
边集数组
struct Edge{
int u;//起点
int v;//终点
int w;//权值
}Edges[100];
适合对边进行相关操作。