图的概念和基于邻接矩阵的实现

这一篇简单介绍下一种更为复杂的数据结构------图,图是一种比线性表和树更为复杂的数据结构。图结构是研究数据与数据之间多对多的关系。

一、图的基本概念

1、一个图定义为一个偶对(V,E),记为G=(V,E);其中V是顶点的非空有限集合,记为V(G),E是无序集V&V的一个子集,记为E(G),其元素是图的弧。

2、弧:表示两个顶点之间存在一个关系,用顶点偶对<v,w>表示,通常根据顶点偶对将图分为有向图和无向图。

3、有向图:若图的关系集合E(G)中,顶点偶对<v,w>的v和w之间是有序的,称图G是有向图。在有向图中,若<v,w>属于E(G),表示从顶点v到顶点w有一条弧。

4、无向图:若图的关系集合E(G)中,顶点偶对<v,w>的v和w之间是无序的,称图G是无向图。在无向图中,E(G)是对称的,则用无序对(v,w)表示v到w的一条边,即(v,w)和(w,v)表示的是同一条边。

5、完全有向图:对于有向图,若图的顶点数是n,用e表示弧的数目,e=[0,n(n-1)],具有n(n-1)条弧的有向图称为完全有向图。

6、权:与图的边和弧相关的数。权可以表示从一个顶点到另一个顶点的距离或耗费。

7、子图和生成子图:设有两个图G1和G2,G1的顶点集是G2的顶点集的子集,G1的弧集是G2的弧集的子集,则称G1是G2的子图;若G1和G2的顶点集相等,G1的弧集是G2的弧集的子集,则称G1是G2的生成子图。

8、顶点的邻接:对于无向图G=(V,E),若v和w之间存在边,则称v和w互为邻接点。边依附于点v和w。对于有向图G=(V,E),若v和w之间存在有向弧,称顶点v邻接到w,称顶点w邻接自v,弧与顶点v和w相关联

9、度、出度、入度、路径(有向路径)、路径长度、回路(环)

10、连通图、非连通图、图的连通分量(非连通图的极大连通子图)-----无向图而言

11、强连通图、非强连通图、强连通分量-------有向图而言

12、生成树:一个连通图(无向图)的生成树是一个极小连通子图,包含全部n个顶点和构成树的n-1条边。生成森林:由若干棵有向树组成,含有图中全部顶点,有向树是只有一个顶点的入度为0,其他顶点的入度为1的有向图。

13、网:带权的连通图

二、图的存储结构

1、邻接矩阵(数组)表示法:包括图的创建、顶点定位、插入顶点、插入弧等

//图的邻接矩阵表示
#define INFINITY 1000
#define MAX_VEX 30 //最大顶点数目
using namespace std;
typedef string GraphKind;//有向,无向,带权有向,带权无向;(DG,AG,WDG,WAG)
//typedef ArcType AdjType;
typedef char VexType;
typedef int ArcValType;
typedef int ArcInfoType;
//弧或边的结构定义
typedef struct ArcType
{
    VexType vex1,vex2; //依附的两个顶点;
    ArcValType ArcVal;//权值
    ArcInfoType ArcInfo;// 其他信息
}ArcType;
typedef ArcType AdjType;
//图的定义
typedef struct MGraph
{
    GraphKind kind;
    int vexnum,arcnum; //图的当前顶点数和弧数
    VexType vexs[MAX_VEX];
    AdjType adj[MAX_VEX][MAX_VEX];//弧集
}MGraph;
//create graph
void Create_Graph(MGraph *G)
{
    cout<<"请输入图的种类标志:\n"<<endl;
    string s;
    cin>>s;
    G->kind=s;
    G->vexnum=0;
}
//图的顶点定位,即确定一个顶点在vexs数组中的下标
int Locate_Graph_Vex(MGraph *G,VexType *vex)
{
    for(int k=0;k<G->vexnum;++k)
        if(G->vexs[k]==*vex)
        return k;
    return -1;
}
//向图中增加顶点
int AddVex_Graph(MGraph *G,VexType *vex)
{
    int k;
    if(G->vexnum>=MAX_VEX){
        cout<<"graph is overflow!"<<endl;
        return -1;
    }
    if(Locate_Graph_Vex(G,vex)!=-1)
    {
        cout<<"the vex has existed!"<<endl;
        return -1;
    }
    k=G->vexnum;
    G->vexs[G->vexnum++]=*vex;
    if(G->kind=="DG" || G->kind=="AG") //无权值
    {
        for(int j=0;j<G->vexnum;j++)
        {
            G->adj[j][k].ArcVal=G->adj[k][j].ArcVal=0;
        }
    }
    else
    {
        for(int j=0;j<G->vexnum;j++)
        {
            G->adj[j][k].ArcVal=INFINITY;
            G->adj[k][j].ArcVal=INFINITY;
        }
    }
    return 1;
}
//
int AddArc_Graph(MGraph *G,ArcType *arc)
{
    int k,j;
    k=Locate_Graph_Vex(G,&arc->vex1);
    j=Locate_Graph_Vex(G,&arc->vex2);
    if(k==-1 || j==-1)
    {
        cout<<"the vexs has not existed!"<<endl;
        return -1;
    }
    if(G->kind=="DG" || G->kind=="WDG") //y有向图或者带权的有向图
    {
        G->adj[k][j].ArcVal=arc->ArcVal;
        G->adj[k][j].ArcInfo=arc->ArcInfo;
    }
    else //无向图或无权的无向图
    {
        G->adj[j][k].ArcVal=G->adj[k][j].ArcVal=arc->ArcVal;
        G->adj[j][k].ArcInfo=G->adj[k][j].ArcInfo=arc->ArcInfo;
    }
    return 1;
}

这一篇介绍了基本概念和图的邻接矩阵的实现,下边贴出来测试代码,下一篇介绍图的邻接链表的实现和图的两种基本遍历方式。


#include <iostream>
#include <malloc.h>
#include "SeqGraph.h"
using namespace std;

int main()
{
    cout << "Graph:" << endl;
    MGraph *G;
    VexType vexs[4]={'A','B','C','D'};
    ArcType arc[4];
   /*
    for(int i=0;i<4;i++)
    {
        arc[i].ArcInfo=0;
        arc[i].ArcVal=i+1;
        arc[i].vex1=vex[i];
        arc[i].vex2=vex[(i+1)%4];
    }
    */
    G=(MGraph *)malloc(sizeof(MGraph));
    Create_Graph(G);
    for(int i=0;i<4;i++)
    {
        AddVex_Graph(G,&vexs[i]);
    }
    for(int i=0;i<4;i++)
    {
        arc[i].ArcInfo=0;
        arc[i].ArcVal=i+1;
        arc[i].vex1=vexs[i];
        arc[i].vex2=vexs[(i+1)%4];
        AddArc_Graph(G,&arc[i]);
    }
    for(int i=0;i<4;i++)
    {
        cout<<G->vexs[i]<<" ";
    }
    cout<<endl;
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++){
            cout<<G->adj[i][j].ArcVal<<" ";
        }
        cout<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值