vector动态数组邻接表--功能更强大的邻接表

来源:互联网 发布:收款收据打印软件 编辑:程序博客网 时间:2024/06/04 22:33

某些时候邻接表可能有局限性。
有一种Vector动态数组+结构体的有效替代法。

它的边遍历顺序可以自己定义:
若正序遍历,遍历顺序与邻接表相反;
若反序遍历,遍历顺序与邻接表相同。
还可以对每个vector进行排序后遍历。
在某些需要遍历某个特殊点编号时,可以sort()后二分查找与这个点最接近的点编号,优先遍历,从而达到增大遍历几率,减少时间的作用。
对于这个点是n号节点,则可以sort()后直接从后往前遍历,某些时候可以卡过毒瘤出题人的数据。。。
这些都是邻接表所没有的功能。

例如:保存有向图:
给定n个点m条边,用三个数表示从a点到b点有一条距离为c的边。

struct data{    vector <int> to;    vector <int> dis;    int m;          //m用于存储边数,方便遍历    /*data()//用于提速,但保留的空间也算入总空间    {        to.reserve(70);//对于大部分图已经够用了        dis.reserve(70);    }*/}num[10000]; //num[i]表示编号为i的点for (a=1;a<=n;a++){    num[a].to.push_back(0);    num[a].dis.push_back(0);}//由于个人比较习惯从1号开始,所以填掉了0号位for (a=1;a<=m;a++){    scanf("%d%d%d",&b,&c,&d);//表示从b到c有一条长为d的边    num[b].to.push_back(c);    num[b].dis.push_back(d);    num[b].m++;//计数    /*    num[c].to.push_back(b);//无向图    num[c].dis.push_back(d);    num[c].m++;    */}

这种方法中,注意to与dis是一一对应关系。
比如说,遍历全图,时间复杂度为O(n+m):

void dfs(int x){    vis[x]=1;    int i;    for (i=1;i<=num[x].m;++i)        if (!vis[ num[x].to[a] ])            dfs(num[x].to[a]);}

若是初学,看得晕,可以将点取出来,便于理解:

v=num[a].to[b];//到达的点u=num[a].dis[b];//边长

下面发两个代码来验证使用方法:
SPFA-Vector:

#include<iostream>#include<cstdio>#include<queue>#include<vector>using namespace std;int l,m,n,s,q,k;int v,u;int dis[1001],team[1001];bool exist[2010];struct sr{    vector <int> to;    vector <int> length;    int mem;}num[1001];int head,tail;int main(){    int a,b,c,d,e;    cin>>n>>m;    for (a=1;a<=m;a++)    {        dis[a]=999999;        num[a].to.push_back(999999);        num[a].length.push_back(999999);    }    for (a=1;a<=m;a++)    {        scanf("%d%d%d",&b,&c,&d);        num[b].to.push_back(c);        num[b].mem++;        num[b].length.push_back(d);        num[c].to.push_back(b);        num[c].mem++;        num[c].length.push_back(d);    }    team[1]=1;    head=0;    tail=1;    exist[1]=true;    dis[1]=0;    do    {        head++;        k=team[head];        exist[k]=0;        for (a=1;a<=num[k].mem;a++)        {            v=num[k].to[a];            if (dis[v] > dis[k] + num[k].length[a] )            {                dis[v] = dis[k] + num[k].length[a];                if (! exist[v] )                {                    tail++;                    team[tail]=num[k].to[a];                    exist[ num[k].to[a] ]=1;                }            }        }    }while (head<tail);    cout<<dis[n];    return 0;}

Dijkstra堆优化-Vector:

#include<iostream>#include<cstdio>#include<queue>#include<vector>#include<cstring>using namespace std;int dis[10010];bool exist[10010];struct cmp{    bool operator()(int a,int b)    {        return dis[a]>dis[b];    }};struct data{    vector <int> to;    vector <int> dis;    int m;}num[10010];int l,m,n,s,q,u,v;priority_queue<int,vector<int>,cmp> Q;int main(){    int a,b,c,d,e;    cin>>n>>m;    for (a=1;a<=n;a++)    {        num[a].to.push_back(0);        num[a].dis.push_back(0);        dis[a]=9999999;        exist[a]=0;    }    for (a=1;a<=m;a++)    {        scanf("%d%d%d",&b,&c,&d);        num[b].to.push_back(c);        num[b].dis.push_back(d);        num[b].m++;        num[c].to.push_back(b);        num[c].dis.push_back(d);        num[c].m++;    }    dis[1]=0;    exist[1]=1;    Q.push(1);    while (!Q.empty())    {        u=Q.top();        Q.pop();        exist[u]=1;             l=num[u].m;        for (a=1;a<=l;a++)        {            v=num[u].to[a];            if (!exist[v] && dis[u]+num[u].dis[a]<dis[v])            {                dis[v]=dis[u]+num[u].dis[a];                Q.push(v);            }        }    }    cout<<dis[n];    return 0;}

有时候会出现多组数据,那么可以写一个初始化函数:

void clr(){    int a;    for (a=1;a<=n;a++)    {        num[a].to.clear();        num[a].dis.clear();        num[a].m=0;    }}        

时间复杂度为O(n)。

动态数组邻接表法建表容易,理解简单,比普通邻接表略省空间,由于vector的局限性导会耗费更多时间,但可以通过reserve()函数得到有效解决。