数据结构与算法(十二)图&存储结构

图:G=(V,E)

        V:顶点(数据元素)的有穷非空集合        E:边的有穷集合

        无向图:每条边都是无方向的

        有向图:每条边都是有方向的

         完全图:任意两个点之间都有一条边

        稀疏图:有很少边或弧的图(e < n logn)

        稠密图:有较多边或弧的图

        网:边/弧带权的图

        邻接:有边/弧相连的两个顶点的关系

                存在(vi,vj),称vi和vj互为相接点(无向图)

                存在<vi,vj>,称vi邻接到vj,vj邻接于vj(有向图)

        关联(依附):边.弧与顶点之间的关系

         顶点的度:与该顶点相关联的边的数目,记作TD(v)

                有向图中分为入度ID(v)出度OD(v) 

图的逻辑结构:多对多

        图没有顺序结构,但是可以用二维数组来表示元素之间的关系,称为数组表示法(邻接矩阵)

        链式存储结构:邻接表、邻接多重表、十字链表

邻接矩阵法:

        建立顶点表和一个邻接矩阵

                设图A = (V,E)有n个顶点,则:顶点表Vexs[n]

i012...n-1
Vex[i]V1V2V3...Vn

                图的邻接矩阵是一个二维数组A.arcs[n][n]定义为:

                A.arcs[i][j] = 1,如果 <i,j> 或 (i,j) 存在        

                                 =0,如果不存在

                         无向图的邻接矩阵是对称的

                         顶点i的度=第 i 行(列)中 1 的个数

                         完全图的邻接矩阵中,对角线元素为0,其余1

                         有向图的邻接矩阵可能不对称

                          顶点的出度=第 i 行元素之和

                          顶点的入度=第 i 列元素之和

                有向网的邻接矩阵表示(将权值表现在矩阵中,无连接使用∞表示)

         邻接矩阵(无向网)的建立

#define MVNum 100    //最大顶点数
typedef char VerTexType;    //设顶点的数据类型为字符型
typedef int ArcType;    //假设边的权值为整形

typedef struct{
    VerTexType vex[MVNum];    //顶点表
    ArcType arc[MVNum][MVNum];    //邻接矩阵
    int vexnum,arcnum;//图当前的点数和边数
}AMGraph;

                算法思路:

                        1.输入总顶点数总边数

                        2.依次输入点的信息存入顶点表

                        3.初始化邻接矩阵,使每个权值初始化为极大值

                        4.构造邻接矩阵

Status CreateUDN(AMGraph &G){
    cin>>G.vexnuym>>G.arcnum;    //输入总顶点数,总边数
    for(i=0;i<G.vexnum;++i)
        cin>>G.vexs[i];    //依次输入点信息
    for(i=0;i<G.vexnum;++i)
        for(j=0;j<G.vexnum;++j)
            G.arc[i][j] = MaxInt;    //边的权值均置为极大值

    for(k=0;k<G.arcnum;++k){
        cin>>v1>>v2>>w;    //输入一条边所依附的顶点和边的权值
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);    //确定v1和v2在G中的位置
        G.arcs[i][j]=w;        //设定权值
        G.arcs[j][i]=G.arcs[i][j];    //置对称边的权值为w
    }
    return OK;
}

                在图中查找顶点

int LocateVex(AMGraph G,VertexType u){
    int i;
    for(i=0;i<G.vexnum;++i)
        if(u==G.vexs[i])    return i;
    return -1;
}

        邻接表(链式)

                顶点:按编号顺序将顶点数据存储在一维数组中

                关联统一顶点的边:用线性链表存储

                无向图表示

                 特点:邻接表不唯一

                        若无向图中有n个顶点、e调边,则需要n个表头和2e个表结点,适宜存储稀疏图

                        无向图中顶点Vi的度为第 i 个单链表中的结点个数

                有向图表示(存储出度边 / 也可以存储入度边<逆邻接表>)

                特点:顶点Vi的出度为第 i 个单链表中的结点个数

                           顶点Vi的入度为整个单链表中邻接借点域值是 i-1的结点个数

                            容易找出度,难以找入度 

                建立:        1.输入总顶点数和总边数

                                   2.建立顶点表        依次输入点的信息存入顶点表中

                                                                使每个表头节点的指针域初始化为NULL

                                   3.创建邻接表        依次输入每条边依附的两个顶点

                                                                确定两个顶点的序号 i 和 j ,建立边结点

                                                                将此边结点分别插入到Vi和Vj对应的两个边链表的头部

Status CreateUDN(AMGraph &G){
    cin>>G.vexnuym>>G.arcnum;    //输入总顶点数,总边数
    for(i=0;i<G.vexnum;++i){
        cin>>G.vertices[i].data;    //依次输入点信息
        G.vertices[i].firstarc=NULL;    //顶点置空
    }

    for(k=0;k<G.arcnum;++k){
        cin>>v1>>v2;    //输入一条边所依附的顶点
        i=LocateVex(G,v1);
        j=LocateVex(G,v2);    //确定v1和v2在G中的位置

        //*****出度表*******//
        p1 = new ArcNode();    //生成新的边结点*p1
        p1->adjvex = j;   //邻接点序号为j
        p1->nextarc = G.vertices[i].fristarc = p1;  
        G.vertices[i].fristarc = p1;    //将新结点*p1插入到顶点Vi的边表头部

        //*****入度表*******//
        p2 = new ArcNode();    //生成新的边结点*p2
        p2->adjvex = j;   //邻接点序号为j
        p2->nextarc = G.vertices[i].fristarc = p2;  
        G.vertices[i].fristarc = p2;    //将新结点*p2插入到顶点Vi的边表头部        
    }
    return OK;
}

                特点:方便找到任意顶点的所有邻接点

                           节约稀疏图的空间(需要N个头指针+2E个结点<每个结点2个域>)

                            方便找到有向图的度,但对于无向图需要邻接表和逆邻接表

        邻接矩阵和邻接表的关系

                1.邻接表中每个链表对应于邻接矩阵中的一行,链表中结点个数等于一行中非零元素的个数

                2.对任意图,邻接矩阵是唯一的,但是邻接表不唯一

                3.邻接矩阵的空间复杂度为O(n^2),邻接表的空间复杂度为O(n+e)

        用途:邻接矩阵用于稠密图;邻接表用于稀疏图

        十字链表(用于有向图)

                结合邻接表和逆邻接表;有向图中每一条弧对应十字链表中的一个弧结点,每个结点对应一个顶点结点

                顶点结点

datafirstinfirstout

                弧结点

tailvexheadvexhlinktlink
(弧尾)(弧头)(下一个弧头相同的弧)(下一个弧尾相同的弧)

        邻接多重表(针对无向图、可以解决每条边存储两遍的问题)

                特点:容易得出顶点和边的信息

                           不方便操作(删除一条边需要找到两个结点)

                 顶点结点

Datafirstedge
顶点数据指向第一条依附该顶点的边

                 边结点

markivexilinkjvexjlinkinfo

标志域

标记此边是否被搜索过

该边依附的两个顶点在表头数组的位置指向依附于ivex的下一条边该边依附的两个顶点在表头数组的位置指向依附于jvex的下一条边

                

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值