图存储结构复习

来源:互联网 发布:亚马逊阅读kindle软件 编辑:程序博客网 时间:2024/04/29 17:41

图的存储主要有5种结构

        1、邻接矩阵

        顶点不分大小,主次,用一个一维数组来存储,边或弧用一个二维数组在存储。

typedef char VertexType;   //顶点类型应由用户定义;typedef int EdgeType;      //边上的权值类型应由用户定义;const int MaxVex=100;      //最大顶点数应由用户定义;const int Infinity=65536;   //用Infinity来代表∞;struct MGraph{VertexType Vertex[MaxVex];  //顶点数组;EdgeType arc[MaxVex][MaxVex];//边二维数组;int numVertex,numEdge;//当前的顶点数和边数;};//建立无向图的邻接矩阵;void CreateGragh(MGraph *G){int i,j,k,w;cout<<"输入顶点数和边数:\n";cin>>G->numVertex>>G->numEdge;//输入顶点信息,建立顶点一维数组;for (i=0;i<G->numVertex;i++)cin>>G->Vertex[i];//输入边的信息,建立邻接矩阵;for (i=0;i<G->numEdge;i++)for (j=0;j<G->numEdge;j++){G->arc[i][j]=Infinity;//初始化邻接矩阵;}for(k=0;k<G->numEdge;k++){cout<<"输入边的下标(i,j)和权值w";cin>>i>>j>>w;G->arc[i][j]=G->arc[j][i]=w;//因为是无向图所以对称;}}

        2、邻接表

        邻接矩阵是一种不错的存储结构,但是对于边数相对顶点较少的图,邻接矩阵是队存储空间的极大浪费。这里我们就可以采用另一种邻接表来存储。

             邻接表处理办法:

        1、图中顶点用一个一维数组存储,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便查找该顶点边的信息。

        2、图中每个顶点V的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点V的边表,有向图则称为顶点V的出边表。

        对于有向图的邻接表,我们所说的邻接表存储中可以直观的得到每个顶点的出度;但有时为了便于确定顶点的入度,我们还可以建立一个有向图的逆邻接表;即对每个顶点V都建立一个连接为V为弧头的表。

       此外,对于带权值的网,需要在边表结点中在增加一个weight的数据域,存储权值的信息。

        

typedef char VertexType;   //顶点类型应由用户定义;typedef int EdgeType;      //边上的权值类型应由用户定义;const int MaxVex=100;      //最大顶点数应由用户定义;//首先定义边表节点;struct EdgeNode {int adjvex;//邻接域,存放顶点在一维数组中的下标;EdgeType weight;//用于存储权值,对于非网图可以不需要;EdgeNode* next;//指向下一个邻接点;};struct VertexNode//顶点表结点;{VertexType data; //顶点域存放顶点信息;EdgeNode* firstedge;//指向顶点的边表;};struct GraphAdjList{VertexNode Nodelist[MaxVex];//顶点一维数组;int numVertex,numEdges;//图中顶点数和边数;};void CreateAdjGraph(GraphAdjList *G){int i,j,k;cout<<"输入顶点数和边数;\n";cin>>G->numVertex>>G->numEdges;for (i=0;i<G->numVertex;i++){cin>>G->Nodelist[i].data;//输入顶点信息;G->Nodelist[i].firstedge=NULL;//将边表置为空表;}//建立边表;for (k=0;k<G->numEdges;k++){cout<<"请输入边(i,j)的顶点序号:\n";cin>>i>>j;//头插法,建立边表;EdgeNode *e1=new EdgeNode;e1->adjvex=j;e1->next=G->Nodelist[i].firstedge;G->Nodelist[i].firstedge=e1;//无向图;EdgeNode *e2=new EdgeNode;  //想内存中申请空间,生成e2->adjvex=i;e2->next=G->Nodelist[j].firstedge;G->Nodelist[j].firstedge=e2;}}
        3、十字链表

        对于有向图,邻接表是有缺陷的。关心了出度,却没有关心入度的问题,除非加入逆邻接表。这里的十字链表就是讲邻接表和逆邻接表组合起来。

         重新定义顶点表结点的结构:data-firstin-firstout;

        firstin表示入边表头指针,指向该顶点的入边表中的第一个顶点,firstout表示出边表头指针,指向该顶点的出边表中的第一个结点。

        重新定义的边表结点结构:tailvex-headvex-headlink-taillink;

        tailvex是指弧起点在顶点表的下标,headvex是表示弧终点在顶点表的下标,headlink是指入边表指针域,指向终点相同的下一个顶点;taillink是指出边表指针域,指向起点相同的下一条边。如果是网,还可以在增加一个权值域。

        十字链表的好处是把邻接表和逆邻接表整合在一起,很容易找出顶点V的出度和入度。同时,其除了结构复杂一点外,其创建图的算法时间复杂度和邻接表相同。在有向图中,十字链表是非常好的数据结构。

        4、多重邻接表

        十字链表说到底对有向图的优化存储,对于无向图中,如果关注的重点是边,那么可以采用多重邻接表在存储图。

        重新定义边表结点;ivex-ilink-jvex-jlink

        ivex和jvex是与某条边依附的两个顶点在顶点表中的下标,ilink指向依附顶点ivex的下一条边,jlink指向依附于顶点jvex的下一条边。这就是邻接多重表的结构。

        邻接多重表与邻接表的差别,仅仅是在于同一条边在邻接表中用两个结点表示,而在多重邻接表中只有一个结点。这样对边的操作就方便多了。

        5、边集数组

        边集数组是由两个一维数组构成,一个是存储顶点的信息;另一个是存储边的信息,这个边数组每个数据元素由一条边的起点下标(begin)、终点下标(end)和权值组成(weight);

       个人感觉,图的邻接矩阵、邻接表和边集数组用的还是比较多的。

0 0