zoukankan      html  css  js  c++  java
  • 邻接表

    邻接表:所谓邻接表(adjacency list),就是把从同一个顶点发出的边链接在同一个称为边链表的单链表中。边链表的每个结点代表一条边,称为边结点。每个边结点有2 个域:该边终点的序号,以及指向下一个边结点的指针。在邻接表中,还需要一个用于存储顶点信息的顶点数组。例如,图1.19(a)所示的有向图对应的邻接表如图(b)所示。在顶点数组中,每个元素有两个成员:一个成员用来存储顶点信息;另一个成员为该顶点的边链表的表头指针,指向该顶点的边链表。如果没有从某个顶点发出的边,则该顶点没有边链表,因此表头指针为空,如图1.19(b)中的顶点G。在该图中,如果指针为空,则用符号“∧”表示。


    图1.19有向图的邻接表

    在邻接表每个顶点的边链表中,各边结点所表示的边都是从该顶点发出的边,因此这种邻接表也称为出边表。采用邻接表存储图时,求顶点的出度很方便,只需要统计每个顶点的边链表中边结点的个数即可,但在求顶点的入度时就比较麻烦。在图1.19(b)中,顶点B 的边链表有3 个边结点,分别表示边<B, F>、<B, E>和<B, C>,因此顶点B 的出度为3;顶点C 的边链表中只有1 个边结点,表示边<C, E>,因此顶点C 的出度为1。如果需要统计各顶点的入度,可以采用逆邻接表存储表示图。所谓逆邻接表,也称为入边表,就是把进入同一个顶点的边链接在同一个边链表中。


    图1.20有向图的逆邻接表

    例如,图1.20(a)所示的有向图对应的逆邻接表如图(b)所示。在图1.20(b)中,顶点B 的边链表有2 个边结点,分别表示边<E, B>和<A, B>,因此顶点B 的入度为2;顶点C 的边链表中也有2个边结点,分别表示边<D, C>和<B, C>,因此顶点C 的入度也为2。

    接下来以有向图为例介绍邻接表的实现方法。为了方便求解顶点的出度和入度,在实现时,把出边表和入边表同时包含在图的邻接表结构中。有向图的邻接表用一个结构体LGraph 存储表示,其中包含3 个成员:顶点数组vertexs,顶点数vexnum 和边的数目arcnum,其中顶点数组vertexs 中每个元素都是VNode 结构体变量。VNode 结构体变量存储图中每个顶点,它包含3 个成员:顶点信息、出边表的表头指针和入边表的表头指针,其中后面两个成员都是ArcNode 结构体类型的指针。ArcNode 结构体存储边链表中的边结点,它包含2 个成员:边的另一个邻接点的序号,以及指向下一个边结点的指针。

    例题:

    问题描述:用邻接表存储有向图,并输出各顶点的出度和入度。

    输入描述输入文件中包含多个测试数据,每个测试数据描述了一个无权有向图。每个测试数据的第一行为两个正整数n 和m,1≤ n ≤ 100,1≤ m ≤ 500,分别表示该有向图的顶点数目和边数,顶点的序号从1 开始计起。接下来有m 行,每行为两个正整数,用空格隔开,分别表示一条边的起点和终点。每条边出现一次且仅一次,图中不存在自身环和重边。输入文件最后一行为0 0,表示输入数据结束。

    输出描述:

    对输入文件中的每个有向图,输出两行:第1 行为n 个正整数,表示每个顶点的出度;第2行也为n 个正整数,表示每个顶点的入度。每两个正整数之间用一个空格隔开,每行的最后一个正整数之后没有空格。

    样例输入:

    4 7
    1 4
    2 1
    2 2
    2 3
    2 3
    4 2
    4 3

    0 0

    样例输出:

    1 4 0 2

    1 2 3 1

    代码实现:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <set>
    #include <map>
    #define INF 99999999
    using namespace std;
    const int maxn=105;
    struct ArcNode{//边结点
        int adjvex;//有向边的另一个邻接点的序号
        ArcNode *nextarc;//指向下一个边结点的指针
    };
    struct VNode{//顶点
        int data;//顶点信息
        ArcNode *head1;//出边表的表头指针
        ArcNode *head2;//入边表的表头指针
    };
    struct LGraph{//图的邻接表存储结构
        VNode vertexs[maxn];//顶点数组
        int vexnum,arcnum;//顶点数和边数
    }LG;
    void CreateLG(){
        ArcNode *p;//用来构造边链表的边结点指针
        int v1,v2;
    
        //LG.vexnum=LG.arcnum=0;
        //scanf("%d %d",&LG.vexnum,&LG.arcnum);
    
        for(int i=0;i<LG.vexnum;i++){//初始化表头指针为空
            LG.vertexs[i].head1=LG.vertexs[i].head2=NULL;
        }
        for(int i=0;i<LG.arcnum;i++){
            scanf("%d %d",&v1,&v2);
            v1--,v2--;
            p = new ArcNode;//假定有足够空间
            p->adjvex = v2;
            p->nextarc = LG.vertexs[v1].head1;//插入链表
            LG.vertexs[v1].head1=p;
            p = new ArcNode;
            p->adjvex = v1;
            p->nextarc = LG.vertexs[v2].head2;
            LG.vertexs[v2].head2=p;
        }
    }
    void DeleteLG(){
        ArcNode *p;//用来指向边链表中各边结点的指针
        for(int i=0;i<LG.vexnum;i++){
            p=LG.vertexs[i].head1;//释放第i个顶点出边表各边节点所占的存储空间
            while(p!=NULL){
                LG.vertexs[i].head1=p->nextarc;
                delete p;
                p=LG.vertexs[i].head1;
            }
            p=LG.vertexs[i].head2;//释放第i个顶点入边表各边节点所占的存储空间
            while(p!=NULL){
                LG.vertexs[i].head2=p->nextarc;
                delete p;
                p=LG.vertexs[i].head2;
            }
        }
    }
    int main()
    {
        int id,od;//顶点的入度跟出度
        ArcNode *p;//用来遍历边链表的边结点指针
        while(scanf("%d %d",&LG.vexnum,&LG.arcnum)){
            if(LG.arcnum+LG.vexnum==0)
                break;
            CreateLG();
            for(int i=0;i<LG.vexnum;i++){//统计各顶点出度并输出
                od=0;
                p=LG.vertexs[i].head1;
                while(p!=NULL){
                    od++;
                    p=p->nextarc;
                }
                if(i==0) printf("%d",od)
                    ;
                else printf(" %d",od);
            }
            printf("
    ");
            for(int i=0;i<LG.vexnum;i++){//统计各顶点入度并输出
                id=0;
                p=LG.vertexs[i].head2;
                while(p!=NULL){
                    id++;
                    p=p->nextarc;
                }
                if(i==0) printf("%d",id);
                else printf(" %d",id);
            }
            printf("
    ");
            DeleteLG();//释放
        }
        return 0;
    }

    • 邻接表的简单实现
    typedef struct  
    {  
        int to;  
        int w;  
        int next;  
    }Edge;  
    Edge e[MAX];  
    int pre[MAX];  
    //初始化  
    memset(pre,-1,sizeof(pre));  
    //输入  
    scanf("%d %d %d",&from,&to,&w1);  
    e[i].to = to; 
    e[i].w = w1; 
    e[i].next = pre[from]; 
    pre[from] = i++;  
    上面这段代码中,边的结构体Edge由三个元素组成:弧头结点序号,边权值,下一条边的序号。e[i]指的是第i条边。pre[i]记录的是从当前输入的情况来看,序号为i的弧尾结点发出的第一条边的序号是pre[i]。


  • 相关阅读:
    深入理解Android(1)——理解Android中的JNI(上)
    我的2014——北京梦的起点和终点
    Phalcon的MVC框架解析
    jquery方法操作iframe元素
    Phalcon学习-model
    Phalcon Framework的Mvc结构及启动流程(部分源码分析)
    使用 OAuth2-Server-php 在 Yii 框架上搭建 OAuth2 Server
    Yii CDbCriteria 常用方法
    Yii-模型- criteria查找数据库方法
    Yii CDbCriteria常用用法
  • 原文地址:https://www.cnblogs.com/kzbin/p/9205225.html
Copyright © 2011-2022 走看看