数据结构(图)——邻接矩阵

图的存储结构:

比较常见的两种图的存储结构:

  • 邻接矩阵表示法(数组表示法)
    若图G是一个具有n个顶点的无权图,G的邻接矩阵是具有以下性质的n×n矩阵A:
    A [ i , j ] = { 1 i f ( v i , v j ) o r &lt; v i , v j &gt; ∈ V 0 o t h e r s A[i,j]=\left\{\begin{matrix} 1 &amp;if (v_{i},v_{j})or&lt;v_{i},v_{j}&gt;\in V \\ 0 &amp; others \end{matrix}\right. A[i,j]={10if(vi,vj)or<vi,vj>Vothers
    若图G是一个具有n个顶点的网,则它的邻接矩阵是具有以下性质的n×n矩阵A:
    A [ i , j ] = { w i j i f ( v i , v j ) o r &lt; v i , v j &gt; ∈ V ∞ o t h e r s A[i,j]=\left\{\begin{matrix} w_{ij} &amp;if (v_{i},v_{j})or&lt;v_{i},v_{j}&gt;\in V \\ \infty &amp; others \end{matrix}\right. A[i,j]={wijif(vi,vj)or<vi,vj>Vothers
  • 邻接表
    邻接表存储方法时一种顺序分配与链式分配相结合的存储方法。邻接表中,对图中每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点 v i v_{i} vi的边。每个单链表上附设一个表头结点。表结点和表头结点的结构如下:
    表头结点:
datafirstarc
存储顶点的名称或其他信息指向链表中第一个结点

表结点:

adjvexnextarcinfo
指示与顶点邻接的点在图中的位置指示下一条边或弧的结点存储与边或弧相关的信息,如权值等

邻接矩阵

下面是邻接矩阵的结构定义

//邻接矩阵
typedef enum{DG, DN, UDG, UDN} GraphKind;   //有向图、有向网、无向图、无向网

typedef struct ArcCell{
    VRType adj;         //弧的类型,图为0,1
    InfoType *info;     //与弧相关的信息的指针
}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedef struct 
{
    VertexType vexs[MAX_VERTEX_NUM];        //顶点向量
    AdjMatrix arcs;                         //邻接矩阵
    int vexnum, arcnum;                     //顶点数和边数
    GraphKind kind;                         //图类型
}MGraph;

下面是利用邻接矩阵实现的基本功能:
创建图
两种方法,第一种是文本读入,第二种是键盘输入。
文本里,第一行是结点个数,第二行是结点名称,第三行及其往下是结点与结点之间的信息(权值),如果两个结点之前没有联系就是0

void createGraph_txt(MGraph &G)
{
   ifstream fin("city.txt");	//文本名称
    fin>>G.vexnum;
    for(int i=0;i<G.vexnum;i++){
        fin>>G.vexs[i];
    }
    int edge = 0;
    for(int i =0;i<G.vexnum;i++){
        for(int j=0;j<G.vexnum;j++){
            double info;
            fin>>info;
            if(info>0){
                G.arcs[i][j].adj = info;
                edge++;
            }
            else{
                G.arcs[i][j].adj = 0;
            }
        }
    }
    G.arcnum = edge;
}

void createGraph_cin(MGraph &G)
{
    cout<<"请输入结点数量:";
    int city_num;
    cin>>city_num;
    G.vexnum = city_num;
    cout<<"请输入结点名称:";
    for(int i=0;i<G.vexnum;i++) cin>>G.vexs[i];
    
    int edge = 0;
    cout<<"请依次输入结点之间的权值,如果结点之间无联系,请输入0"<<endl;
    for(int i=0;i<G.vexnum;i++){
        for(int j=0;j<G.vexnum;j++){
            double info;
            cin>>info;
            if(info>0){
                G.arcs[i][j].adj = info;
                edge ++;
            }
            else{
                G.arcs[i][j].adj = 0;
            }
        }
    }
    G.arcnum = edge;
}

获取当前图的结点个数、有向边个数

int getNumVertices(MGraph &G)
{
    return G.vexnum;
}

int getNumEdges(MGraph &G)
{
    return G.arcnum;
}

判断某个顶点是否存在

bool validVertex(MGraph &G, string v)
{
    int has = 0;
    for(int i=0;i<G.vexnum;i++){
        if(!v.compare(G.vexs[i])){
            has = 1;
            cout<<v<<"顶点存在"<<endl;
            break;
        }
    }
    if(has==1) return true;
    else {
        cout<<v<<"顶点不存在"<<endl;
        return false;
    }
}

判断两个顶点之间是否有边
分别获取两个顶点在图里的位置,再看对应的 &lt; v i , v j &gt; &lt;v_{i},v_{j}&gt; <vi,vj>的信息,如果是0,那就不存在有向边。
这里uv用于判断输入的两个顶点是否都存在,当有一个存在的时候就+1,这样两个都存在就加了2.

bool hasEdge(MGraph &G, string u, string v)
{
    int u_index = -1, v_index = -1;
    int uv = 0;
    for(int i=0;i<G.vexnum;i++){
        if(!u.compare(G.vexs[i])){
            u_index = i;
            uv ++;
            if(uv==2) break;
        }
        else if(!v.compare(G.vexs[i])){
            v_index = i;
            uv ++;
            if(uv==2) break;
        }
    }
    if(G.arcs[u_index][v_index].adj==0||uv!=2){
        cout<<"不存在"<<u<<"到"<<v<<"的有向边"<<endl;
        return false;
    }
    else{
        cout<<"存在"<<u<<"到"<<v<<"的有向边"<<endl;
        cout<<"权值为:"<<G.arcs[u_index][v_index].adj<<endl;
        return true;
    }
}

添加顶点
还是先判断是否存在该顶点,如果存在就退出,如果不存在的话就加进去,加完后其余顶点和它之间的联系默认为0

void addVertex(MGraph &G, string u)
{
    if(validVertex(G, u)){
        cout<<"该顶点已存在,无需添加"<<endl;
        return ;
    }
    else{
        G.vexnum++;
        G.vexs[G.vexnum-1] = u;
        for(int i=0;i<G.vexnum-1;i++) G.arcs[i][G.vexnum].adj = 0;
        for(int i=0;i<G.vexnum;i++) G.arcs[G.vexnum-1][i].adj = 0;
    }
}

添加有向边


void addEdge(MGraph &G, string u, string v, int w)
{
    if(hasEdge(G, u, v)){
        cout<<"该有向边已存在,无需添加"<<endl;
        return ;
    }
    else{
        int u_index = -1, v_index = -1;
        for(int i=0;i<G.vexnum;i++){
            if(!u.compare(G.vexs[i])){
                u_index = i;
                uv ++;
                if(uv==2) break;
            }
            else if(!v.compare(G.vexs[i])){
                v_index = i;
                uv ++;
                if(uv==2) break;
            }
        }
        G.arcs[u_index][v_index].adj = w;
    }
}

删除一条边
把对应的边信息置0

void removeEdge(MGraph &G, string u, string v)
{
    int u_index = -1, v_index = -1;
    int uv = 0;
    for(int i=0;i<G.vexnum;i++){
        if(!u.compare(G.vexs[i])){
            u_index = i;
            uv ++;
            if(uv==2) break;
        }
        else if(!v.compare(G.vexs[i])){
            v_index = i;
            uv ++;
            if(uv==2) break;
        }
    }
    if(uv!=2||G.arcs[u_index][v_index].adj==0){
        return ;
    }
    else{
        G.arcs[u_index][v_index].adj = 0;
    }
}

显示出边信息

void drawGraph(MGraph &G)
{
    for(int i=0;i<G.vexnum;i++){
        cout<<G.vexs[i]<<" ";
    }
    cout<<endl;
    for(int i=0;i<G.vexnum;i++){
        for(int j=0;j<G.vexnum;j++){
            cout<<G.arcs[i][j].adj<<" ";
        }
        cout<<endl;
    }
    cout<<endl;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值