[图论] 邻接链表 前向星||向前星

[图论] 邻接链表 前向星||向前星

往常我们常常会用邻接矩阵来储存一张图,但往往会浪费放大量的空间。
noip2016的一道题博主因为当时水平有限,用了邻接矩阵,毕竟当时只会深搜。
然而今天,Sim同学给大家科普一下这个神奇的存法。
适用范围 图较为疏密。
以下是 邻接表与邻接矩阵的优缺点比较;

                  邻接矩阵  

优点
可以在常数时间判断两者之间是否有边
实现简单
缺点
空间花费很高,需要|V|²的空间,如果是稀疏图,空间被大量浪费
若有重边,则无法保存所有边的信息

                   邻接表

优点
有多少边就占用多少空间,空间利用效率高,且能存下所有边的信息
稀疏图时,遍历复杂度低,O(|V|+|E|)
缺点
不可以在常数时间判断两者之间是否有边

实现稍复杂

C++实现代码


const int MAXN=1005;
struct edge{
    int to,next;
    int w;
}g[MAXN];
int ne,h[MAXN];
void add(int u,int v,int dis)//u--v的边; 
{
    ne++;
    g[ne].to=v;
    g[ne].w=dis;
    g[ne].next=h[u];
    h[u]=ne;
}

过去的代码太Naive了。好吧,就几个月前。
贴上新写法

#define MAXN 100005

int head[MAXN], ne;

class edge  {
public:
    int to, pre, w;
    edge(int to = 0, int pre = 0, int w = 0) : to(to), pre(pre), w(w)  { }
} g[MAXN << 1];

inline bool adde(int u, int v, int w)  {
    g[++ne] = edge(v, head[u], w), head[u] = ne;
    return true;
}

关于遍历:

#define edges(u) for(register int i = head[u]; i; i = g[i].pre)

void dfs(int u, int f)  {
    edges(u)  {
        int v = g[i].to;
        dfs(v, u);
    }
}

大家都很强, 可与之共勉。

Update : 2017.10.20

更新现在的写法,使用指针。
递归调用实现加双向边。
可以使用构造函数,但为了减少代码量,所以省去。
注意这种写法只在g++系列编译器是有效的。

# include 

const int N = 123456 ;

struct edge  {
    int to, w ;  edge* nxt ;
} g [N << 1], *NewEdge, *head [N] ;

inline void add_edge ( int u, int v, int w, bool db ) {
    *( ++ NewEdge ) = ( edge ) {  v, w, head [u]  } ;  head [u] = NewEdge ;
    if ( db )  add_edge ( v, u, w, ! db ) ;
}

关于初始化:

void Init ( )  {
    NewEdge = g ;
}

当然可以直接在声明NewEdge的时候把它指向指针池。

关于遍历:

for ( edge* it = head [u] ; it ; it = it -> nxt )  {
/*
    some huaji things...
*/
}

Update : 2017.11.3

封装 + 重载运算符

struct edge  {
    int to ; edge* nxt ;
} ;

# define N 500050
# define M 500050

struct Graph  {
    edge g [M], *head [N] ;
    Graph ( )  {  memset ( head, 0, sizeof head ) ;  }
    inline void add_edge ( int u, int v )  {
        static edge* NewEdge ( g ) ;
        *( ++ NewEdge ) = ( edge ) {  v, head [u]  } ; head [u] = NewEdge ;
    }
    inline edge*& operator [] ( const int& u )  {  return head [u] ;  }
} g1, g2 ;

再也不用担心重建图的时候不方便啦!!!

关于遍历:

for ( edge* it = g1 [u] ; it ; it = it -> nxt )  {
/*
do sth
*/
}

你可能感兴趣的:(伊始,C++/OI)