邻接表

 

  对于一个无向图,有邻接矩阵和邻接表等存储方式,而其中邻接表的实现方式无疑让人很纠结。

  邻接表的优点在于,对于节点为n的稀疏无向图,邻接矩阵需要耗费的空间为n2,而邻接表仅需耗费2n的空间。使用邻接表存储图,无疑大大降低了存储所必须的空间。

  这里主要讲解邻接表的数组实现。

  对于邻接表,一般包含两个部分:第一部分用于存储无向边的信息,第二部分拥有存储节点的起始边编号,如下:

  在这里我们使用结构体数组来存储无向边的信息,代码如下:

  struct LINE{
      int p;  //被连接的节点号
      int next;  //边表中下一条边的ID
  };
  LINE l[MAX * 2];   //无向图,边的数量*2

 

  使用一个一维数组来存储节点的起始边编号,如下:

 int h[MAX];

  举这样一个例子,对于以下无向图:

  

起始点 1 2 3 4 2
结束点 2 4 2 4 5

 

  我们可以将其存储为如下形式:

  对于一维数组h部分有:

 

h[1] h[2] h[3] h[4] h[5]
1 5 3 4 0

  

  对于结构体数组l部分有:

            

l[1] l[2] l[3] l[4] l[5]
p next p next p next p next p next
2 0 4 0 2 0 3 0 5 2

 

  值得注意的是,对于每一个新加入链表的边节点,我们都将其插入到链表头部,而不是将其插入到链表尾部。

  具体的存储过程实现代码如下:

void add(int n)  //无向图中节点个数
{
    int a, b;
    for(int i = 1; i <= n; i++)
    {
        cin>>a>>b;
        l[i].p = b;
        l[i].next = h[a];
        h[a] = i;
    }
}

  

当我们需要对第i号节点进行遍历时,只需如下操作:

void search(int i)  //需要遍历的节点编号
{
       int  k = h[i];

        while(k != 0)
        {
            cout<<l[k].p<<' ';
            k = l[k].next;
        }
}

 --------------------------------------------------------------------------------------------------------------------------------------------

  2018.8.1补充:

  当我们需要对整个无向图进行遍历时,也可以如下操作:

  

void search(int f, int i)
{
       int  k = h[i];
       int p;
        while(k)
        {
            p = l[k].p;
            if(p != f)
            {
                  search(i, p);
             }
            k = l[k].next;
        }
}

 

圆满完成。

 

posted @ 2018-07-22 11:11  potato226  阅读(423)  评论(0编辑  收藏  举报