图的储存结构

来源:互联网 发布:美国宝宝的好处知乎 编辑:程序博客网 时间:2024/05/17 23:48

        

        要将图的信息存到计算机中,需要使用专门设计的数据结构,比较常见的是邻接矩阵,向前星,邻接表,链式向前星这四种方式。另外还有十字链表的方式,由于其建立比较复杂,故在ACM/ICPC竞赛中很少用到,这里不再赘述。下文只需要考虑输入的信息为有向边的信息,如果输入为无向边请读者自行拆成两条有向边处理

                                                                                    

一  邻接矩阵 

       逻辑结构分为两部分:V和E集合。因此,用一个一维数组存放图中所有顶点数据;用一个二维数组存放顶点间关系(边或弧)的数据,这个二维数组

称为邻接矩阵。邻接矩阵又分为有向图邻接矩阵和无向图邻接矩阵。(下面三张图片转自点击打开链接)

        1.无向图。

                            


         2.有向图 




           3.有向网图

                         

优点:实现简单直观。

           可以直接查询点Vi与Vj间是否有边,如果有,边的权值是多少。

缺点:遍历效率低,并且不能储存重边。

           大图的空间开销大,特别当n比较大的时候,建一个n*n的数组是不现实的。

           对于稀疏图邻接矩阵的空间利用效率也不高

 

二 向前星

       向前星是一种通过储存边信息的方式储存图的数据结构。它的构造方式非常简单,读入每条边的信息,将边存放在数组中,把数组中的边按照起点顺序排序,向前星就构造完了,为了查询方便,经常会有一个数组储存七点为Vi的第一条边的位置。

数据结构如下

int head[maxsize];   //储存起点为Vi的第一条边的位置struct node{    int from;    //起点    int to;    //终点    int w;    //权值}edge[maxsize];


        将所有边的信息读入,按照边的起点排序,如果起点相同,对于相同起点的边按终点排序,如果依然相同,按权值排序。在下面的样例中,使用的C++STL的排序函数

比较函数

bool cmp(node x,node y){    if(x.from!=y.from)        return x.from<y.from;    if(x.to!=y.to)        return x.to<y.to;    return x.w<y.w;}

读入数据

         cin>>n>>m        for(int i=1;i<=m;i++)            cin>>edge[i].from>>edge[i].to>>edge[i].w;        sort(edge+1,edge+1+m,cmp);   //排序        memset(head,-1,sizeof(head));        head[edge[0].from]=0;        for(int i=2;i<=m;i++)        {            if(edge[i].from!=edge[i-1].from)                head[edge[i].from]=i;  //确实起点为Vi的第一条边的位置        }

遍历代码

for(int i=1;i<=n;i++)        {            for(int j=head[i];edge[j].from==i&&j<=m;j++)            {                cout<<edge[j].from<<" "<<edge[j].to<<" "<<edge[j].w<<endl;            }        }


完整代码

#include<iostream>#include<algorithm>#include<string.h>const int maxsize=1000;using namespace std;int n,m;int head[maxsize];struct node{    int from;    int to;    int w;}edge[maxsize];bool cmp(node x,node y){    if(x.from!=y.from)        return x.from<y.from;    if(x.to!=y.to)        return x.to<y.to;    return x.w<y.w;}int main(){    while(cin>>n>>m)    {        for(int i=1;i<=m;i++)            cin>>edge[i].from>>edge[i].to>>edge[i].w;        sort(edge+1,edge+1+m,cmp);        memset(head,-1,sizeof(head));        head[edge[1].from]=1;        for(int i=2;i<=m;i++)        {            if(edge[i].from!=edge[i-1].from)                head[edge[i].from]=i;        }        for(int i=1;i<=n;i++)        {            for(int j=head[i];edge[j].from==i&&j<=m;j++)            {                cout<<edge[j].from<<" "<<edge[j].to<<" "<<edge[j].w<<endl;            }        }    }    return 0;}


样例测试

测试数据8 121 2 48 7 71 6 96 1 123 1 224 3 175 8 296 5 97 4 256 7 48 3 113 2 19输出1 2 41 6 93 1 223 2 194 3 175 8 296 1 126 5 96 7 47 4 258 3 118 7 7head数组的值1 -1 3 5 6 7 10 11


优点:可以对应点非常多的情况,可以储存重边。

缺点 :但是不能直接判断任意两个顶点之间是否具有边,而且排序需要浪费一些时间


三 邻接表

邻接表的是图的一种链式储存结构。对于图G中每个顶点Vi,把所有邻接于Vi的顶点Vj链成一个单链表,这个单链表称为顶点Vi的邻接表。

邻接表有三种实现方法,分别为动态建表实现,使用STL中的vector模拟链表实现和静态建表实现。

                                 

1动态建表

动态建表的数据结构:

struct EdgeNode   //邻接表节点{    int to;     //终点    int w;      //权值    EdgeNode *next;      //指向下一条边的指针};struct VNode      //起点表节点{    int from;       //起点    EdgeNode *first;    //邻接表头指针}; VNode Adjlist[maxsize];   //整个图的邻接表

信息储存的主要代码

cin>>i>>j>>w;EdgeNode *p=new EdgeNode();p->to=j;p->w=w;p->next=Adjlist[i].first;Adjlist[i].first=p;//将新节点指向起点表节点,并且将起点表节点更新为该新节点

遍历代码

for(int i=1;i<=n;i++){    for(EdgeNode *k=Adjlist[i].first;k!=NULL;k=k->next)    {        cout<<i<<" "<<k->to>>" "<<k->w<<endl;    }}

2 STL 中的vector模拟链表实现

所需的数据结构

struct node   //表边节点的类型{    int to;   //节点序号    int w;     //权值};vector<node> map[maxsize];   

信息储存的主要代码

node e;cin>>i>>j>>w;e.to=j;e.w=w;map[i].push_back(e);

遍历代码

for(int i=1;i<=n;i++){    for(vector<node>::iterator k=map[i].begin();k!=map[i].end();k++)    {        node t=*p;        cout<<i<<" "<<t.to<<" "<<t.w<<endl;        /*或者写成         cout<<i<<" "<<k->to<<" "<<k->w<<endl;*/    }}

3静态建表

静态建表也就是采用数组模拟链表的方式实现邻接表的功能。

我以前的博客有将过,附上链接点击打开链接,在此不再赘述。


优点:效率高,所在空间小

缺点 :  不能迅速找到任意两点的关系

原创粉丝点击