1.邻接矩阵
无向带权图的创建(邻接矩阵)
typedef char VertexType
typedef int EdgeType;
#define MAXVEX 100;
#define INFINITY 65535;//表示无限大
typedef struct{
VertexType vexs[MAXVEX];
EdgeType arc[MAXVEX][MAXVEX];
int numVertexes,numEdges;
}MGraph;
void CreatMGraph(MGraph *Graph){
int i,j,k,w;
cout<<"请输入顶点数和边数:"<<endl;
cin>>Graph->numVertexes;
cin>>Graph->numEdges;
for(i=0;i<Graph->numVertexes;i++){
cin>>Graph->vexs[i];//建立点集合
}
for(i=0;i<Graph->numVertexes;i++){//边表初始化
for ( j = 0; i < Graph->numVertexes; i++)
{
Graph->arc[i][j]=INFINITY;
}
}
for(k=0;k<Graph->numEdges;k++){
cout>>"请输入边的首位字母下标和权值:"<<endl;
cin>>i>>j>>w;
Graph->arc[i][j]=w;
Graph->arc[j][i]=w;//无向边的对称性
}
}
2.邻接链表
无向图的建立(邻接表)
typedef char VertexType
typedef int EdgeType;
#define MAXVEX 100;
typedef struct EdgeNude{
int adjvex;//边的指向下标
EdgeType weight;
struct EdgeNude *next;
}EdgeNude;
typedef struct VertexNude{
VertexType data;
EdgeNude *firstedge;
}VertexNude Adjlist[MAXVEX];
typedef struct{
Adjlist adjlist;
int numVertexes,numEdges;
}GraphAdjlist;
void CreatAdjlistGraph(GraphAdjlist *Graph){
int i,j,k;
EdgeNude *e;
cout<<"输入顶点数和边数:"<<endl;
cin>>Graph->numVertexes>>Graph->numEdges;
for(i=0;i<Graph->numVertexes;i++){//顶点表建立和头指针初始化
cout<<"输入顶点名:"<<endl;
cin>>Graph->adjlist[i];
Graph->adjlist[i].firstedge=NULL;
}
for(k=0;k<Graph->numEdges;K++){//头插法建立链表
cout<<"请输入边字母两个下标:"<<endl;
cin>>i>>j;
e=(EdgeNude *)malloc(sizeof(EdgeNude));
e->adjvex=j;
e->next= Graph->adjlist[i].fistedge;
Graph->adjlist[i].firstedge=e;
//无向图的对称性
e->adjvex=i;
e->next= Graph->adjlist[j].fistedge;
Graph->adjlist[j].firstedge=e;
}
}
3.十字链表
对于有向图来说,邻接表是有缺陷的。关心了出度问题,想了解入度就必须要遍历整个图才能知道。反之,逆邻接表解决了入度
我们重新定义顶点表结点结构为:
data firstin firstout
其中firstin表示入边表头指针,指向该顶点的入边表中第一个结点,firstout表示出边表头指针,指向该顶点的出边表中的第一个结点。
重新定义的边表结点结构如下:
tailvex headvex headlink taillink
其中tailvex是指弧起点在顶点表的下标,headvex是指弧终点在顶点表中的下标,headlink是指入边表指针域,指向终点(弧头)相同的
下一条边,taillink是指出边表指针域,指向起点(弧尾)相同的下一条边。如果是网,还可以再增加一个weight域来存储权值。
如下图表示的十字链表:
4.邻接多重表
十字链表主要是针对有向图的存储结构进行了优化,那么对于无向图的邻接表,有没有问题呢?
如果我们在无向图的应用中,关注的重点是顶点,那么邻接表是不错的选择,但如果我们更关注边的操作,比如对已访问过的边做标记,删除某一条边等操作,那就意味着需要找到这条边的两个边表结点进行操作。如下图,若要删除(v0,v2)这条边,需要对邻接表结构中右边表的两个结点进行删除,显然这是比较繁琐的。
项目 | Value
- ivex | ilink | jvex | jlink |
其中ivex和jvex是指某条边依附的两个顶点在顶点表中的下标。ilink指向依附顶点ivex的下一条边,jlink指向依附顶点jvex的下一条边。
这就是邻接多重表结构。如上图有4个顶点和5条边,先将边表结点画出来。由于是无向图,所以ivex,jvex正反过来都可以,为了绘图方便,都将ivex值设置的与一旁的顶点下标相同。
下面开始连线,首先连线的(1)(2)(3)(4)是将顶点的firstedge指向一条边,顶点下标要与ivex的值相同。接着,由于顶点v0的(v0,v1)边的
邻边有(v0,v3)和(v0,v2)。因此(5)(6)的连线就是满足指向下一条依附于顶点v0的边的目标,注意ilink指向的结点的jvex(ivex)一定要与它本身
的ivex的值相同。同理,连线(7)就是指(v1,v0)这条边,它是相当于顶点v1指向(v1,v2)边后的下一条。v2有三条边依附,所以(3)之后就有
了(8)(9)。连线(10)就是顶点v3在连线(4)之后的下一条边。左图一共有5条边,所以右图有10条连线,完全符合预期。
5.边集数组
边集数组是由两个一维数组构成。
一个是存储顶点的信息;另一个是存储边的信息,这个边数组每个数据元素由一条边的起点下标(begin)、终点下标(end)和权(weight)组成。
边集数组关注的是边的集合,在边集数组中要查找一个顶点的度需要扫描整个边数组,效率并不高。因此它更适合对边依次进行处理的操作,而不适合对顶点相关的操作。