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

图的存储结构:

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

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

表结点:

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

邻接矩阵

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

//邻接矩阵
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;
    }
}

判断两个顶点之间是否有边
分别获取两个顶点在图里的位置,再看对应的 < v i , v j > <v_{i},v_{j}> <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;
}

你可能感兴趣的:(数据结构)