码迷,mamicode.com
首页 > 其他好文 > 详细

图的存储形式——邻接矩阵(数组)

时间:2014-06-24 15:48:29      阅读:300      评论:0      收藏:0      [点我收藏+]

标签:des   style   class   blog   code   http   

邻接矩阵:用两个数组分别存储数据元素(顶点)的信息和数据元素之间的关系(边或弧)的信息。
比如考虑下面这个有向图:
bubuko.com,布布扣
如果用邻接矩阵存储可以表示为:
1.顶点数组:
bubuko.com,布布扣
2.邻接矩阵:
bubuko.com,布布扣
图的遍历:
深度优先(DFS):
深度优先搜索遍历类似于树的先根遍历,是树的先根遍历的推广。假设初始状态是图中所有顶点未曾访问过,则深度优先搜索可从图中的某个顶点v出发,访问此顶点,然后依次从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到;若此时图中还有顶点未访问,则另选图中未访问的顶点作为起始点,重复上述过程,直至所有顶点被访问。
上图深度优先遍历结果:abcdfeghi
广度优先(BFS):
广度优先搜索类似于树的层次遍历。假设从图中某顶点v出发,在访问了v之后,依次访问v的各个未曾访问的邻接点,然后分别从这些邻接点触发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。若此时仍有顶点没访问,另选图中未访问的顶点作为起始点,重复上述过程,直至所有顶点被访问。
上图广度优先遍历结果:abgcehidf

具体实现:
/************************************
图的邻接矩阵(数组)表示
by Rowandjj
2014/6/22
************************************/

#include<iostream>
using namespace std;

#define INFINTY_INT_MAX  0x7fffffff    //代表正无穷
#define MAX_VERTIEX_NUM 20    //最大顶点个数
#define MAX_INFO 20

typedef enum{DG,DN,AG,AN}GraphKind;//有向图、有向网、无向图、无向网

typedef struct
{
    int adj;//顶点关系类型
    char *info;//该弧的相关信息
}ArcCell,AdjMatrix[MAX_VERTIEX_NUM][MAX_VERTIEX_NUM];


typedef struct 
{
    char vexs[MAX_VERTIEX_NUM];//顶点向量
    AdjMatrix arcs;//邻接矩阵
    int vexnum,arcnum;//顶点数、弧数
    GraphKind kind;//种类
}MGraph,*pMGraph;


bool visited[MAX_VERTIEX_NUM];//访问标志数组(全局)
bool (*VisitFunc)(char);

bool Visit(char v)
{
    cout<<v;    
    return true;
}
//----------------操作-------------------------------
int LocateVex(MGraph G,char u);//若G中存在顶点u,则返回该顶点在图中位置;否则返回-1
bool CreateDG(pMGraph G);//创建有向图
bool CreateDN(pMGraph G);//创建有向网
bool CreateAG(pMGraph G);//创建无向图
bool CreateAN(pMGraph G);//创建无向网

bool CreateGraph(pMGraph G);//构造图
void DestroyGraph(pMGraph G);//销毁图G
char GetVex(MGraph G,int v);//初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值
bool PutVex(pMGraph G,char v,char iValue);//初始条件: 图G存在,v是G中某个顶点。操作结果: 对v赋新值value
int FirstAdjVex(MGraph G,char v);//返回v的第一个邻接顶点的序号
int NextAdjVex(MGraph G,char v,char w);//返回v的(相对于w的)下一个邻接顶点的序号,否则返回-1
void InsertVex(pMGraph G,char v);//在图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做)
bool DeleteVex(pMGraph G,char v);//删除G中顶点v及其相关的弧
bool InsertArc(pMGraph G,char v,char w);//在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v>
bool DeleteArc(pMGraph G,char v,char w);//在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v>

void DFSTravel(MGraph G,bool (*Visit)(char));//深度优先
void DFS(MGraph G,int v);
void BFSTravel(MGraph G,bool (*Visit)(char));//广度优先
void Display(MGraph G);

//----------------辅助队列--------------------------

typedef struct _QUEUENODE_
{
    int data;
    struct _QUEUENODE_ *next;
}QueueNode,*pQueueNode;

typedef struct _QUEUE_
{
    int size;
    pQueueNode pHead;
    pQueueNode pTail;
}Queue,*pQueue;

bool InitQueue(pQueue Q);
bool DestroyQueue(pQueue Q);
bool DeQueue(pQueue Q,int* e);
bool EnQueue(pQueue Q, int e);
bool QueueEmpty(Queue Q);
//------------------------------------------
bool InitQueue(pQueue Q)
{
    Q->pHead = Q->pTail = (pQueueNode)malloc(sizeof(QueueNode));
    if(!Q->pHead)
    {
        return false;
    }
    Q->pHead->next = NULL;
    Q->size = 0;
    return true;
}

bool DestroyQueue(pQueue Q)
{
    pQueueNode pTemp = Q->pHead->next;
    while(pTemp != NULL)
    {
        Q->pHead->next = pTemp->next;
        free(pTemp);
        pTemp = Q->pHead->next;
    }
    free(Q->pHead);
    Q->size = 0;
    return true;
}
bool QueueEmpty(Queue Q)
{
    return Q.size == 0;
}

bool DeQueue(pQueue Q,int* e)
{
    pQueueNode pDel = Q->pHead->next;
    if(pDel != NULL)
    {
        *e = pDel->data;
        Q->pHead->next = pDel->next;
        if(Q->pTail == pDel)
        {
            Q->pTail = Q->pHead;
        }
        free(pDel);
        Q->size--;
    }
    return true;
}
bool EnQueue(pQueue Q, int e)
{
    pQueueNode pNew = (pQueueNode)malloc(sizeof(QueueNode));
    if(!pNew)
    {
        return false;
    }
    pNew->next = NULL;
    pNew->data = e;

    Q->pTail->next = pNew;
    Q->pTail = pNew;
    Q->size++;

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

bool CreateDG(pMGraph G)
{
    int incInfo = 0;
    int i,j,k,l;
    char va,vb;
    char *info;
    char s[MAX_INFO] = {0};//存放弧信息
    cout<<"请输入有向图G的顶点数,弧数,弧是否含其它信息(是:1,否:0)"<<endl;
    cin>>G->vexnum;
    cin>>G->arcnum;
    cin>>incInfo;
    cout<<"请输入顶点值"<<endl;

    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->arcs[i][j].adj = 0;
            G->arcs[i][j].info = NULL;
        }
    }
    
    cout<<"请输入每条弧的弧头和弧尾"<<endl;

    for(k = 0; k < G->arcnum; k++)
    {
        cin>>va;
        cin>>vb;

        i = LocateVex(*G,va);
        j = LocateVex(*G,vb);

        G->arcs[i][j].adj = 1;
        if(incInfo)
        {
            cout<<"输入该弧的信息"<<endl;
            cin>>s;
            l = strlen(s);
            if(l)
            {
                info = (char *)malloc(sizeof(char) * (l+1));
                strcpy(info,s);
                G->arcs[i][j].info = info;
            }
        }
    }
    G->kind = DG;
    return true;
}

bool CreateDN(pMGraph G)
{
    int incInfo;
    int i,j,k,l,w;
    char s[MAX_INFO];
    cout<<"请输入有向网G的顶点数,弧数,弧是否含其它信息(是:1,否:0)"<<endl;
    cin>>G->vexnum;
    cin>>G->arcnum;
    cin>>incInfo;
    char va,vb;//分别代表弧头、弧尾
    char *pInfo;

    cout<<"请输入顶点值"<<endl;
    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->arcs[i][j].adj = INFINTY_INT_MAX;//网
            G->arcs[i][j].info = NULL;
        }
    }

    cout<<"请输入弧的头、尾、权值"<<endl;
    for(k = 0; k < G->arcnum; k++)
    {
        cout<<"弧头"<<endl;
        cin>>va;
        cout<<"弧尾"<<endl;
        cin>>vb;
        cout<<"权值"<<endl;
        cin>>w;
        i = LocateVex(*G,va);
        j = LocateVex(*G,vb);
        
        G->arcs[i][j].adj = w;
        if(incInfo)
        {
            cout<<"请输入该弧的信息"<<endl;
            cin>>s;
            l = strlen(s);
            if(l)
            {
                pInfo = (char *)malloc(sizeof(char)*(l+1));
                strcpy(pInfo,s);
                G->arcs[i][j].info = pInfo;
            }
        }

    }


    G->kind = DN;
    return true;
}

bool CreateAG(pMGraph G)//创建无向图
{
    int incInfo;
    int i,j,k,l;
    char va,vb;
    cout<<"请输入无向图G的顶点数,边数,边是否含其它信息(是:1,否:0):"<<endl;
    
    cin>>G->vexnum;
    cin>>G->arcnum;
    cin>>incInfo;
    char s[MAX_INFO];
    char *info;
    //初始化顶点
    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->arcs[i][j].adj = 0;//图
            G->arcs[i][j].info = NULL;
        }
    }
    cout<<"请输入每条边的两个顶点"<<endl;
    for(k = 0; k < G->arcnum; k++)
    {
        cin>>va;
        cin>>vb;

        i = LocateVex(*G,va);
        j = LocateVex(*G,vb);

        G->arcs[i][j].adj = G->arcs[j][i].adj = 1;
        if(incInfo)
        {
            cin>>s;
            l = strlen(s);
            if(l)
            {
                info = (char *)malloc(sizeof(char)*(l+1));
                strcpy(info,s);
                G->arcs[i][j].info = G->arcs[j][i].info = info;
            }
        }
    }
    G->kind = AG;
    return true;
}
bool CreateAN(pMGraph G)
{
    int incInfo;
    int i,j,k;
    char va,vb;
    int w;
    char s[MAX_INFO];
    char *info;

    cout<<"请输入无向网G的顶点数,边数,边是否含其它信息(是:1,否:0):";
    cin>>G->vexnum;
    cin>>G->arcnum;
    cin>>incInfo;

    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->arcs[i][j].adj = INFINTY_INT_MAX;
            G->arcs[i][j].info = NULL;
        }
    }
    cout<<"请输入每条边的两个顶点以及权值"<<endl;
    for(k = 0; k < G->vexnum; k++)
    {
        cin>>va;
        cin>>vb;
        cin>>w;

        i = LocateVex(*G,va);
        j = LocateVex(*G,vb);
        G->arcs[i][j].adj = G->arcs[j][i].adj = w;
        
        if(incInfo)
        {
            cout<<"请输入该边的相关信息"<<endl;
            cin>>s;
            w = strlen(s);
            if(w)
            {
                info = (char *)malloc(sizeof(char)*(w+1));
                strcpy(info,s);
                G->arcs[i][j].info = G->arcs[j][i].info = info;
            }
        }
    }
    
    G->kind = AN;
    return true;
}
bool CreateGraph(pMGraph G)
{
    cout<<"请输入图G的类型(有向图:0,有向网:1,无向图:2,无向网:3):";
    scanf("%d",&(*G).kind);
    switch((*G).kind)
    {
    case DG: return CreateDG(G); /* 构造有向图 */
    case DN: return CreateDN(G); /* 构造有向网 */
    case AG: return CreateAG(G); /* 构造无向图 */
    case AN: return CreateAN(G); /* 构造无向网 */
    default: return false;
   }
}
void DestroyGraph(pMGraph G)
{
    int i,j;
    if(G->kind < 2)//有向tu
    {
        for(i = 0; i < G->vexnum; i++)
        {
            for(j = 0; j < G->vexnum; j++)
            {
                if(G->kind == 0 && G->arcs[i][j].adj == 1 || G->kind == 1 && G->arcs[i][j].adj != INFINTY_INT_MAX)
                {
                    free(G->arcs[i][j].info);
                    G->arcs[i][j].info = NULL;
                }
            }
        }
    }else
    {
        for(i = 0; i < G->vexnum; i++)
        {
            for(j = i+1; j < G->vexnum; j++)
            {
                if(G->kind == 2 && G->arcs[i][j].adj == 1 || G->kind == 3 && G->arcs[i][j].adj != INFINTY_INT_MAX)
                {
                    free(G->arcs[i][j].info);
                    G->arcs[i][j].info = G->arcs[j][i].info =NULL;
                }
            }
        }
    }
}
char GetVex(MGraph G,int v)
{
    if(v > G.vexnum || v < 0)
    {
        exit(0);
    }
    return G.vexs[v];
}
bool PutVex(pMGraph G,char v,char iValue)
{
    int k = 0;
    k = LocateVex(*G,v);
    if( k < 0)
    {
        return false;
    }
    G->vexs[k] = iValue;
    return true;
}
int FirstAdjVex(MGraph G,char v)
{    
    int i,j = 0,k;
    k = LocateVex(G,v);
    if(G.kind == AN || G.kind == DN)
    {
        j = INFINTY_INT_MAX;
    }
    for(i = 0; i < G.vexnum; i++)
    {
        if(G.arcs[k][i].adj != j)
        {
            return i;
        }
    }
    return -1;
}
int NextAdjVex(MGraph G,char v,char w)//返回v的(相对于w的)下一个邻接顶点的序号,若w是v的最后一个邻接顶点,则返回-1
{
    int k1,k2;
    int i,j = 0;
    k1 = LocateVex(G,v);
    k2 = LocateVex(G,w);
    
    if(G.kind == AN || G.kind == DN)
    {
        j = INFINTY_INT_MAX;
    }

    for(i = k2+1; i < G.vexnum ; i++)
    {
        if(G.arcs[k1][i].adj != j)
        {
            return i;
        }
    }
    return -1;
}

void Display(MGraph G)
{
    int i,j;
    cout<<"顶点:";
    for(i = 0; i < G.vexnum; i++)
    {
        cout<<G.vexs[i]<<" ";
    }
    cout<<endl;
    cout<<"边"<<endl;
    for(i = 0; i < G.vexnum; i++)
    {
        for(j = 0; j < G.vexnum; j++)
        {
            cout<<G.arcs[i][j].adj<<" ";
        }
        cout<<endl;
    }
}
void InsertVex(pMGraph G,char v)
{
    int index = G->vexnum;
    G->vexnum+=1;
    G->vexs[index] = v;
    for(int i = 0; i <= index; i++)
    {    
        if(G->kind % 2)//网
        {
            G->arcs[i][index].adj = G->arcs[index][i].adj = INFINTY_INT_MAX;
        }else
        {
            G->arcs[i][index].adj = G->arcs[index][i].adj = 0;
        }
        G->arcs[index][i].info = NULL;
        G->arcs[i][index].info = NULL;
    }

}
bool DeleteVex(pMGraph G,char v)
{
    int k,m = 0;
    int i,j;
    //1.找到顶点v的序号
    k = LocateVex(*G,v);
    if(k < 0)
    {
        return false;
    }
    if(G->kind == DN || G->kind == AN)//网
    {
        m = INFINTY_INT_MAX;
    }
    //2.更改弧数(分有向图和无向图)
    for(i = 0; i < G->vexnum; i++)
    {
        if(G->arcs[i][k].adj != m)
        {
            if(G->arcs[i][k].info)//释放相关信息
            {
                free(G->arcs[i][k].info);
            }
            G->arcnum--;
        }
    }
    if(G->kind == DG || G->kind == AG)//有向图
    {
        for(i = 0; i < G->vexnum; i++)
        {
            if(G->arcs[k][i].adj != m)
            {
                if(G->arcs[k][i].info)//释放相关信息
                {
                    free(G->arcs[k][i].info);
                }
                G->arcnum--;
            }
        }
    }
    //3.更改顶点数组内容及大小
    for(i = k+1; i < G->vexnum; i++)
    {
        G->vexs[i-1] = G->vexs[i];
    }
    //4.更改邻接矩阵
    for(i = 0; i < G->vexnum; i++)
    {
        for(j = k+1;j < G->vexnum; j++)
        {
            G->arcs[i][j-1] = G->arcs[i][j];
        }
    }
    for(i = 0; i < G->vexnum; i++)
    {
        for(j = k+1;j < G->vexnum; j++)
        {
            G->arcs[j-1][i] = G->arcs[j][i]; 
        }
    }

    G->vexnum--;
    return true;
}
bool InsertArc(pMGraph G,char v,char w)
{
    int i,j,k,l;
    char s[MAX_INFO];
    char *pinfo;
    //1.找到v、w的序号
    i = LocateVex(*G,v);
    j = LocateVex(*G,w);
    if(i < 0 || j < 0)
    {
        return false;
    }
    //2.如果是网,需输入权值.是图则更改邻接矩阵相应值
    if(G->kind == DN || G->kind == AN)
    {
        cout<<"输入权值:";
        cin>>G->arcs[i][j].adj;
    }else
    {
        G->arcs[i][j].adj = 1;
    }
    //3.如果有相关信息,输入之
    cout<<"该弧是否有相关信息(0:否 1:是):"<<endl;
    cin>>k;
    if(k)
    {
        cout<<"输入相关信息:";
        cin>>s;
        l = strlen(s);
        if(l)
        {
            pinfo = (char *)malloc(sizeof(char)*(l+1));
            strcpy(pinfo,s);
            G->arcs[i][j].info = pinfo;
        }
    }
    //4.如果是无向的,添加对称弧
    if(G->kind == AG || G->kind == AN)
    {
        G->arcs[j][i].adj = G->arcs[i][j].adj;
        G->arcs[j][i].info = G->arcs[i][j].info;
    }
    G->arcnum++;
    return true;
}
bool DeleteArc(pMGraph G,char v,char w)
{
    int i,j;
    //1.找到v、w的位置
    i = LocateVex(*G,v);
    j = LocateVex(*G,w);
    if(i < 0 || j < 0)
    {
        return false;
    }
    //2.如果是图则将邻接矩阵对应位置的值改为0,否则改为INT_MAX
    if(G->kind == DG || G->kind == AG)
    {
        G->arcs[i][j].adj = 0;
    }else
    {
        G->arcs[i][j].adj = INFINTY_INT_MAX;
    }    
    
    if(G->arcs[i][j].info)
    {
        free(G->arcs[i][j].info);
        G->arcs[i][j].info = NULL;
    }
    //3.如果是无向的,需删除对称弧
    if(G->kind == AG || G->kind == AN)
    {
        G->arcs[j][i].adj = G->arcs[i][j].adj;
        G->arcs[j][i].info = NULL;
    }
    G->arcnum--;
    return true;
}
void DFSTravel(MGraph G,bool (*Visit)(char))
{
    int v;
    VisitFunc = Visit;
    for(v = 0; v < G.vexnum; v++)
    {
        visited[v] = false;
    }
    for(v = 0; v < G.vexnum; v++)
    {
        if(!visited[v])
        {
            DFS(G,v);
        }
    }
    cout<<endl;
}
void DFS(MGraph G,int v)
{
    char w1,v1;
    int w;

    visited[v] = true;
    VisitFunc(G.vexs[v]);
    v1 = GetVex(G,v);
    
    for(w = FirstAdjVex(G,v1);w>=0;w = NextAdjVex(G,v1,w1=GetVex(G,w)))
    {
        if(!visited[w])
        {
            DFS(G,w);
        }
    }
}
void BFSTravel(MGraph G,bool (*Visit)(char))
{
    Queue q;
    InitQueue(&q);
    char w1,u1;
    int i,u,w;
    for(i = 0; i < G.vexnum; i++)
    {
        visited[i] = false;
    }

    for(i = 0; i < G.vexnum; i++)
    {
        if(!visited[i])
        {
            visited[i] = true;
            Visit(G.vexs[i]);
            EnQueue(&q,i);
    
            while(!QueueEmpty(q))
            {
                DeQueue(&q,&u);
                u1 = GetVex(G,u);
                for(w = FirstAdjVex(G,u1);w>=0;w = NextAdjVex(G,u1,w1=GetVex(G,w)))
                {
                    if(!visited[w])
                    {
                        visited[w] = true;
                        Visit(G.vexs[w]);
                        EnQueue(&q,w);
                    }
                    
                }
            }
        }
    }
    DestroyQueue(&q);
    cout<<endl;
}
int main()
{
    MGraph G;
    CreateDG(&G);
    Display(G);
    cout<<"深度优先遍历"<<endl;
    DFSTravel(G,Visit);
    cout<<"广度优先遍历"<<endl;
    BFSTravel(G,Visit);
    return 0;
}

测试:
bubuko.com,布布扣







图的存储形式——邻接矩阵(数组),布布扣,bubuko.com

图的存储形式——邻接矩阵(数组)

标签:des   style   class   blog   code   http   

原文地址:http://blog.csdn.net/chdjj/article/details/34099147

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!