用邻接链表存储无向图和有向图

来源:互联网 发布:淘宝聊天记录 编辑:程序博客网 时间:2024/06/05 09:29
上一篇文章我们说到用邻接矩阵存储有向图和无向图,这种方法的有点是很直观的知道点与点之间的关系,查找的复杂度是为O(1)。但是这种存储方式同时存在着占用较多存储空间的问题,

邻接矩阵存储很好理解,但是,有时候太浪费空间了,特别是对于顶点数多,但是关联关系少的图。

举个极端的例子。

下图中,5个顶点都是孤立的,然而为了存储边的信息,要分配一个5X5的矩阵。本来一条边都没有,没必要用存储空间来存储边,但还要分配额外的空间。

            

用邻接表则可以避免这种浪费。邻接表用动态表结构存储边,更加灵活:有一个边就分配一个空间去存储,没有就不分配。

我们仍然用邻接矩阵中那个图的例子来说明邻接表的构建思想。

邻接表只需要一个数组,但是这个数组有点复杂,需要解剖一下。如下图。

 

 

 可以发现,用邻接表存储时,图中的每一个节点 不仅要存储本顶点的数据data,还要存储一个表,这个表存储了此顶点的所有临接点的索引。2点确定一线,那么就能存储此节点相关的所有的边了。

下面我们用到C++库中的vector来实现indexlist。

代码如下:

#include<stdio.h>#include<vector>#define MAX_VERTEX 4using std::vector;        //使用C++标准库中的vector来作为list,它实质就是一个顺序表 typedef char DataType;typedef struct node{    DataType data;            //顶点数据     vector<int> indexList;    //存储顶点邻接点索引的 表 }Node;typedef Node* UListGraph;/********************************/void UListGraph_init(UListGraph*pGraph);void UListGraph_create(UListGraph graph);void UListGraph_show(UListGraph graph);void UListGraph_destroy(UListGraph*pGraph);int main(void){    UListGraph g;    UListGraph_init(&g);    UListGraph_create(g);    UListGraph_show(g);    UListGraph_destroy(&g);    return 0;}void UListGraph_init(UListGraph*pGraph){    (*pGraph) = new Node[MAX_VERTEX];}void UListGraph_create(UListGraph  graph){            for (int i = 0; i < MAX_VERTEX; ++i)  //填充顶点数组    {        printf("输入第%d个顶点值\n",i+1);                scanf(" %c",  &(graph[i].data));     }    for(int i=0;i<MAX_VERTEX;++i)        for(int j=i+1;j<MAX_VERTEX;++j)        {            printf("如果元素%c和%c之间有边,请输入1,否则输入0",graph[i].data,graph[j].data);            int opt;            scanf("%d",&opt);            if(opt==1)            {                graph[i].indexList.push_back(j);                graph[j].indexList.push_back(i);            }        }}void UListGraph_show(UListGraph graph){        printf("顶点元素如下:\n\n");     for(int i=0;i<MAX_VERTEX;i++)    {        printf("%c\t",graph[i].data);    }    printf("\n\n");    for(int i=0;i<MAX_VERTEX;i++)    {        printf("元素%c的邻接点 :",graph[i].data);        Node tnode = graph[i];        for(int k=0;k<tnode.indexList.size();++k)        {            printf("%c\t",graph[tnode.indexList[k]].data);        }        putchar('\n');    }}void UListGraph_destroy(UListGraph*pGraph){    delete (*pGraph);    *pGraph = NULL;               }
2、有向网用邻接链表存储

邻接表对于无向图来说很适用,但是对于有向图来说就不适用了,因为邻接表中,每一个节点的IndexList只能存储一种状态的弧,出弧或者入弧(逆邻接表),那怎么将一个顶点的出入弧都存储起来呢?

那就是将邻接表和逆邻接表都用起来,也就是一个节点需要存储:①data,②inArcList,入弧记录表,③outArcList,出弧记录表


实现代码如下:

#include<stdio.h>#include<vector>using std::vector;#define MAX_VERTEX 4 typedef char DataType;typedef struct arc{     int headVertex;         //此条弧的头尾结点的index    int tailVertex;         //此条弧的头尾结点的index    //WeightType weight;    //此弧的附加信息,比如权重,这里是有向图,不是网,所以不需要weight}Arc;typedef struct node{    DataType data;   //顶点数据域    vector<Arc> outArc;     //此顶点的所有 出度 弧 表    vector<Arc> inArc;      //此顶点的所有 入度 弧 表 }Node;typedef Node* Graph;void Graph_init(Graph* pG);void Graph_create(Graph g);void Graph_show(Graph g);void Graph_destroy(Graph*pg);int main(void){    Graph g;    Graph_init(&g);    Graph_create(g);    Graph_show(g);    return 0;}void Graph_init(Graph* pG){    (*pG) = new Node[MAX_VERTEX];    if(*pG == NULL)    {        //exit(-1);    }}void Graph_create(Graph g){    int opt;        for (int i = 0; i < MAX_VERTEX; ++i)  //填充顶点数组    {        printf("输入第%d个顶点值\n",i+1);                scanf(" %c",  &(g[i].data));     }    for(int j=0;j<MAX_VERTEX;++j)        for(int i=j+1;i<MAX_VERTEX;++i)        {            printf("若元素%c有指向%c的弧,则输入1,否则输入0\t",g[j].data,g[i].data);                       scanf("%d",&opt);            if(opt==1)            {                Arc* parc = new Arc;                parc->headVertex = i;                parc->tailVertex = j;                                g[j].outArc.push_back(*parc);                g[i].inArc.push_back(*parc);            }                        printf("若元素%c有指向%c的弧,则输入1,否则输入0\t",g[i].data,g[j].data);                       scanf("%d",&opt);            if(opt==1)            {                                Arc* parc = new Arc;                parc->headVertex = j;                parc->tailVertex = i;                g[i].outArc.push_back(*parc);                g[j].inArc.push_back(*parc);                                 }        }}void Graph_show(Graph g){    for (int j = 0; j <MAX_VERTEX; ++j)    {        printf("顶点数据%c\n",g[j].data);               printf("发射:");                for(int i=0;i<g[j].outArc.size();++i)        {            printf("%c\t",g[g[j].outArc[i].headVertex].data);        }        putchar('\n');        printf("接收:");        for(int i=0;i<g[j].inArc.size();++i)        {            printf("%c\t",g[g[j].inArc[i].tailVertex].data);        }        printf("\n\n");    }    }void Graph_destroy(Graph*pg){  delete (*pg);    *pg = NULL;               }


0 0
原创粉丝点击