数据结构(图)

定义——

    1、图是由顶点的有穷非空集合和顶点之间的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图中顶点的集合,E是图G中边的集合。

    2、线性表中的数据元素叫元素,树中的数据元素叫结点,在图中的数据元素称之为顶点。

        线性表中可以没有数据元素,称为空表。树中可以没有结点,叫空树。而在图结构中不允许没有顶点

        线性表中,相邻的元素之间具有线性关系,树结构中,相邻两层的结点具有层次关系,而图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。

    3、无向边:若顶点vi到vj之间的边没有方向,则称这条边为无向边,用无序偶对(vi,vj)来表示。如果图中任意两个顶点之间的边都是无向边,则称该图为无向图。

        有向边:若从顶点vi到vj的边有方向,则称这条边为有向边,也称为弧。用有序偶<vi,vj>来便是,vi称为弧尾,vj称为弧头。如果图中任意两个顶点之间的边都是有向边,则成为该图为有向图。

        *无向边用小括号“()”表示,而有向边则用尖括号“<>”表示。

    4、在图中,若不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图。

    5、在无向图中,如果任意两个顶点之间都存在边,则称该图为无向完全图。含有n个顶点的无向完全图有n*(n-1)/2条边。

         在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧,则称该图为有向完全图。含有n个顶点的有向完全图有n*(n-1)条边。

        对于具有n个顶点和e条边的图,无向图0<=e<=n*(n-1)/2,有向图0<=e<=n*(n-1)

    6、有很少条边或者弧的图称为稀疏图,反之称为稠密图。

    7、与图的边或弧相关的数叫权。这种带权的图通常称为网。

    8、假设有两个图G=(V,{E})和G'=(V'{E'}),如果V'属于V且E'属于E,则称G'为G的子图。

    9、对于无向图G(V,{E}),如果边(v,v')属于E,则称v和v'互为邻接点,即v和v'相邻接。

         顶点v的度是和v相关联的边的数目,记为TD(v),边数是各顶点度数和的一半

         对于有向图G(V,{E}),如果弧<v,v'>属于E,则称顶点v邻接到顶点v’,顶点v邻接自顶点v。弧<v,v'>和顶点v和v'相关联。

        以顶点v为头的弧的数目称为v的入度,记为ID(v),以v为尾的弧的数目称为称为v的出度,记为OD(v);顶点v的度为TD(v)=ID(v)+OD(v)。

        无向图从顶点v到v'的路径是一个顶点序列。

    10、树中根节点到任意结点的路径是唯一的,但是图中顶点与顶点之间的路径却是不唯一的。

         路径的长度是路径上的边或者弧的数目。

         第一个顶点到最后一个顶点相同的路径称为回路或者环。序列中顶点不重复出现的路径称为简单路径。除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路称为简单回路或者简单环。

    11、连通图:在无向图中,如果从顶点v到v'有路径,则称v和v'是连通的。如果对于图中任意两个顶点vi,vj属于V,vi和vj都是连通的,则称G为连通图。

    12、无向图中的极大连通子图称为连通分量,注意:

            1】要是子图

            2】子图要是连通的

            3】连通子图含有极大顶点数

            4】具有极大顶点数的连通子图包含依附于这些顶点的所有边。

    13、在有向图中,如果对于每一对vi,vj,从vi到vj和从vj到vi都存在路径,则称G是强连通图。有向图中的极大强连通子图称作有向图的强连通分量。

    14、连通图的生成树:一个连通图的生成树是一个极小的连通子图,它含有图中全部的n个顶点,但只有足以构成一棵树的n-1条边。

    15、如果一个图有n个顶点和小于n-1条边,则是非连通图,如果他多于n-1条边,必定构成一个环。不过有n-1条边不一定是生成树。

    16、如果一个有向图恰有一个顶点的入度为0,其余顶点的入度均为1,则是一棵有向树。

    17、一个有向图的生成森林由若干棵有向树组成,含有图中全部顶点,但只有足以构成若干棵不想交的有向树的弧

术语总结——

    1、图按照有无方向分为无向图和有向图。无向图由顶点和边构成,有向图由顶点和弧构成。弧有弧尾和弧头之分。

    2、图按照边或弧的多少分为稀疏图和稠密图。如果任意两个顶点之间都存在边交完全图,有向的叫有向完全图。若无重复的边或顶点到自身的边叫简单图。

    3、图中顶点之间有邻接点、依附概念。无向图顶点的边数叫度,有向图的顶点分为入度和出度

    4、图上的边或弧上带权则称为网。

    5、图中点点间存在路径,两顶点间存在路径则说明是连通的,如果路径最终回到起始点则称为环,当中不重复叫简单路径。若任意两顶点间都是连通的,则图就是连通图,有向则称为强连通图。图中有子图,若子图极大连通就是连通分量,有向则称为强连通分量。

    6、无向图中连通且n个顶点n-1条边叫生成树,有向图中一顶点入度为0,其余顶点入度为1的叫有向树。一个有向图由若干棵有向树构成生成森林。

图的存储结构——

    1、由于图的结构比较复杂,任意两个顶点之间都可能存在联系,因此无法以数据元素在内存中的物理位置来表示元素之间的关系,也就是说,图不可能用简单的顺序存储结构来表示。而是用多重链表的形式,即一个数据域和多个指针域组成的结点表示图中一个顶点。但是每个顶点的度有差别,因此按照度最大的顶点设计存在物理空间的浪费。

    2、图的存储结构——

        1】邻接矩阵。用两个数组来表示图,一个一维数组存储图中的顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息。

        对称矩阵就是n阶矩阵的元满足aij=aji。即从矩阵的左上角到右下角的主对角线为轴,右上角的元与左下角对应的元全都是相等的(即是无向图)

            要判定任意两定点之间是否有边无边就非常容易了。        

            要知道某个顶点的度,其实就是这个顶点vi在邻接矩阵中第i行(或第i列)的元素之和

            求顶点vi的所有邻接点就是矩阵中第i行元素扫描一遍,arc[i][j]为1就是邻接点

        判断有向图顶点vi到vj是否存在弧,只需要查找矩阵中arc[i][j]为1的顶点

        图的邻接矩阵存储结构代码:

        typedef char VertexType;//顶点类型,用户定义,可能是v0,v1,v2,,,也可能是1,2,3...

        typedef int EdgeType;//边上的权值类型应由用户定义

        typedef struct{

            VertexType vexs[MAXVEX];//顶点表示

            EdgeType arc[MAXVEX][MAXVEX];//邻接矩阵,可做边表

            int  numVertexes,numEdges;//图中当前顶点数和边数

        }MGraph

        无向图创建代码:

        void CreateMGraph(MGraph *G)

        {

            int i,j,k,w;

            printf("输入顶点数和边数:\n");

            scanf("%d,%d",&G->numVextexes,&G->numEdges);//输入顶点数和边数

            for(i=0;i<G->numVertexes;i++){//读入顶点信息,建立定点表

                scanf(&G-vexs[i]);

            }

            for(i=0;i<G->numVertexes;i++){

                for(j=0;j<G->numVertexes;j++){

                    G->arc[i][j]=INFINITY;//邻接矩阵初始化

                }

            }

            for(k=0;k<G->numEdges;k++){

                printf("输入边(vi,vj)上的下标i,下标j和权w:\n");

                scanf("%d,%d,%d",&i,&j,&w);//输入边(vi,vj)上的权w

                G->arc[i][j]=w;

                G->arc[j][i]=G->arc[i][j];//因为图是无向图,矩阵对称

            }

        }

        对于边数相对于顶点较少的图,这中结构是存在对存储空间的极大浪费的。

        2】邻接表

            1)图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过数组能比较容易的读取顶点信息,更加方便。另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息。

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

        顶点表的各个结点由data和first edge两个域表示,data是数据域,存储顶点的信息,firstedge是指针域,指向边表的第一个结点,即此顶点的第一个邻接点。边表结点由adjvex和next两个域组成。adjvex是邻接点域,存储某顶点的邻接点的顶点信顶点中的下标,next则存储指向表边表中下一个结点的指针。

        对于带权值的网图,可以在边表结点定义中再增加一个weight的数据域,存储权值信息即可。

        对于有向图,为了便于算出每个结点的入度或者出度是多少,以及判断两定点之间是否存在弧可以建立一个有向图的逆邻接表,即对每个顶点vi都建立一个链接为vi为弧头的表。

        结点定义代码:

        typedef char VertexType;//顶点类型应由用户定义

        typedef int EdgeType;//边上的权值类型应由用户定义

        typedef struct EdgeNode{//边表结点

            int adjvex;//邻接点域,存储该顶点对应下标

            EdgeType weight;//用于存储权值,对于非网图可以不需要

            struct EdgeNode *next;//链域,指向下一个邻接点

        }

        typedef struct VertexNode{//顶点表结点

            VertexType data;//顶点域,存储顶点信息

            EdgeNode *firstedge;//边表头指针

        }VertexNode,AdjList[MAXVEX];

        typedef struct{

            AdjList adjList;

            int numVertexes,numEdges;//图中当前顶点数和边数

        }GraphAdjList;

    建立图的邻接表结构——

    void CreateALGraph(GraphAdjList *G){

        int i,j,k;

        EdgeNode *e;

        printf("输入顶点数和边数:\n");

        scanf("%d,%d",&G->numVertexes,&G->numEdges);

        for(i=0;i<G->numVertexes;i++){

            scanf(&G->adjList[i].data);

            G->adjList[i].firstedge=null;

        }

        for(k=0;k<G->numEdges;k++){

            printf("输入边(vi,vj)上的顶点序号:\n");

            scanf("%d,%d",&i,&j);

            e=(EdgeNode*)malloc(sizeof(EdgeNode));

            e->adjvex=j;

            e->next=G->adjList[i].firstedge;

            G->adjList[i].firstedge=e;


            e=(EdgeNode*)malloc(sizeof(EdgeNode));

            e->adjvex=i;

            e->next=G-adjList[j].firstedge;

            G->adjList[j].firstedge=e;

        }

    }

    (有向图)十字链表——

    将邻接表与逆邻接表结合起来,

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

    边表结点结构:tailvex | headvex | headlink | taillink,tailvex是指弧起点在顶点表的下标,headvex是指弧终点在顶点表中的下标,headlink是指入边表指针域,指向终点相同的下一条边,taillink是指边表指针域,指向起点相同的下一条边。如果是玩还可以增加weight域来存储权值。

    十字链表的好处是将邻接表和逆邻接表整合在了一起,这样既容易找到某顶点为尾的弧,也容易找到该结点为头的弧,因而容易求得顶点的出度和入度。而且他除了结构复杂一点,其实创建图算法的时间复杂度是和邻接表相同的。

    (无向图)邻接多重表——

    顶点表结构:data | firstedge

    边表结点结构:ivex | ilink | jvex | jlink,ivex和jvex是与某条边依附的两个顶点在顶点表中的下标,ilink指向依附顶点ivex的下一条边,jlink指向依附顶点jvex的下一条边。

    邻接多重表和邻接表的差别仅仅是在于同一条边在邻接表中用两个结点表示,而在邻接多重表中只有一个结点。这样对于边的操作比较方便,若要删除(v0,v2)这条边只需要将6、9的链接指向改为^即可。

    编辑数组:

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

    边表数组结构:begin | end | weight

    

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值