图:图(Graph)是由定点的有穷非空集合和定点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中的顶点的集合,E是图G中边的集合。

图的两个重要的存储方式:

1、 邻接矩阵

/**************图数据结构***********************/

#define VERTEX_MAX 26   //图的最大顶点数  

#define MAXVALUE 32767 //最大值(可设为一个最大整数)

typedef struct

{

    char Vertex[VERTEX_MAX]; //保存顶点信息(序号或字母)                                                                                                 

    int Edges[VERTEX_MAX][VERTEX_MAX]; //保存边的权

    int isTrav[VERTEX_MAX]; //遍历标志

    int VertexNum; //顶点数量

    int EdgeNum;//边数量

    int GraphType; //图的类型(0:无向图,1:有向图)   

}MatrixGraph; //定义邻接矩阵图结构

 

void CreateMatrixGraph(MatrixGraph *G);//创建邻接矩阵图

void OutMatrix(MatrixGraph *G); //输出邻接矩阵

 

/***********创建邻接矩阵存储方式的图****************/

void CreateMatrixGraph(MatrixGraph *G)//创建邻接矩阵图

{

    int i,j,k,weight;

    char start,end; //边的起始顶点

    printf("输入各顶点信息\n");

    for(i=0;i<G->VertexNum;i++) //输入顶点

    {

        getchar();

        printf("第%d个顶点:",i+1);

        scanf("%c",&(G->Vertex[i])); //保存到各顶点数组元素中

    }

    printf("输入构成各边的两个顶点及权值(用逗号分隔):\n");

    for(k=0;k<G->EdgeNum;k++)  //输入边的信息

    {

        getchar(); //暂停输入

        printf("第%d条边:",k+1);

        scanf("%c,%c,%d",&start,&end,&weight);

        for(i=0;start!=G->Vertex[i];i++); //在已有顶点中查找始点

        for(j=0;end!=G->Vertex[j];j++); //在已有顶点中查找结终点

        G->Edges[i][j]=weight; //对应位置保存权值,表示有一条边

        if(G->GraphType==0)  //若是无向图

            G->Edges[j][i]=weight;//在对角位置保存权值 

    }

}

/***********输出邻接矩阵存储方式的图****************/

void OutMatrix(MatrixGraph *G)//输出邻接矩阵

{

    int i,j;

    for(j=0;j<G->VertexNum;j++)

        printf("\t%c",G->Vertex[j]);          //在第1行输出顶点信息

    printf("\n");

    for(i=0;i<G->VertexNum;i++)

    {

        printf("%c",G->Vertex[i]);

        for(j=0;j<G->VertexNum;j++)

        {

            if(G->Edges[i][j]==MAXVALUE) //若权值为最大值

                printf("\t∞");          //输出无穷大符号

            else

                printf("\t%d",G->Edges[i][j]); //输出边的权值

        }

        printf("\n");

    }            

}

 

/*******************测试代码*******************************/

int main()

{

    MatrixGraph G; //定义保存邻接矩阵结构的图

    int i,j;

    printf("输入生成图的类型(0:无向图,1:有向图):");

    scanf("%d",&G.GraphType); //图的种类

    printf("输入图的顶点数量和边数量:");

    scanf("%d,%d",&G.VertexNum,&G.EdgeNum); //输入图顶点数和边数

    for(i=0;i<G.VertexNum;i++)  //清空矩阵

        for(j=0;j<G.VertexNum;j++)

            G.Edges[i][j]=MAXVALUE; //设置矩阵中各元素的值为最大值        

    CreateMatrixGraph(&G); //创建用邻接表保存的图

    printf("邻接矩阵数据如下:\n");

    OutMatrix(&G);

    getch();

    return 0;

}

 

2、 邻接表存储方式:

/************************图邻接表存储结构****************/

#define VERTEX_MAX 20   //图的最大顶点数  

typedef struct edgeNode  

{

    int Vertex; //顶点信息(序号或字母)

    int weight; //权值

    struct edgeNode *next; //指向下一个顶点指针 (当前顶点和指向的下一顶点构成一条边)

}EdgeNode; //邻接表边结构

 

typedef struct  

{

    EdgeNode* AdjList[VERTEX_MAX]; //指向每个顶点的指针

    int VextexNum,EdgeNum; //图的顶点的数量和边的数量                                                                                                                 

    int GraphType; //图的类型(0:无向图,1:有向图)

}ListGraph;  //图的结构

 

void CreateGraph(ListGraph *G); //生成图的邻接表  

void OutList(ListGraph *G); //输出邻接表

 

/************************创建图邻接表存储结构****************/

void CreateGraph(ListGraph *G)  //构造邻接表结构图

{

    int i,weight;

    int start,end;

    EdgeNode *s;

    for(i=1;i<=G->VextexNum;i++)//将图中各顶点指针清空

        G->AdjList[i]=NULL;

    for(i=1;i<=G->EdgeNum;i++) //输入各边的两个顶点

    {

        getchar();

        printf("第%d条边:",i);

        scanf("%d,%d,%d",&start,&end,&weight); //输入边的起点和终点

        s=(EdgeNode *)malloc(sizeof(EdgeNode)); //申请保存一个顶点的内存

        s->next=G->AdjList[start]; //插入到邻接表中

        s->Vertex=end; //保存终点编号

        s->weight=weight; //保存权值

        G->AdjList[start]=s; //邻接表对应顶点指向该点

        if(G->GraphType==0) //若是无向图,再插入到终点的边链中

        {

            s=(EdgeNode *)malloc(sizeof(EdgeNode)); //申请保存一个顶点的内存

            s->next=G->AdjList[end];

            s->Vertex=start;

            s->weight=weight;

            G->AdjList[end]=s;

        }

    }  

}

/************************输出图邻接表存储结构****************/

void OutList(ListGraph *G)

{

    int i;

    EdgeNode *s;

    for(i=1;i<=G->VextexNum;i++)

    {

        printf("顶点%d",i);

        s=G->AdjList[i];

        while(s)

        {

            printf("->%d(%d)",s->Vertex,s->weight);

            s=s->next;

        }

        printf("\n");

    }

}

 

/*****************测试代码**************************/

int main()

{

    ListGraph G; //定义保存邻接表结构的图

    printf("输入生成图的类型(0:无向图,1:有向图):");

    scanf("%d",&G.GraphType); //图的种类

    printf("输入图的顶点数量和边数量:");

    scanf("%d,%d",&G.VextexNum,&G.EdgeNum); //输入图顶点数和边数

    printf("输入构成各边的两个顶点及权值(用逗号分隔):\n");

    CreateGraph(&G); //生成邻接表结构的图

    printf("输出图的邻接表:\n");

    OutList(&G);

    getch();

    return 0;

}

 

深度优先遍历

 深度优先遍历方法类似于树的先序遍历,具体过程如下:

(1)从isTrav数组中选择一个未被访的顶点Vi,将其标记为已访问。

(2)接着从Vi的一个未被访问过的邻接点出发进行深度优先遍历。

(3)重复步骤(2),直至图中所有和Vi有路径相通的顶点都被访问过。

(4)重复步骤(1)至步骤(3)的操作,直至所有顶点都被访问过。

广度优先遍历

                  广度优先遍历类似于树的按层次遍历,具体过程如下:

(1)从isTrav数组中选择一个未被访问的顶点Vi,将其标记为已访问。

(2)接着依次访问Vi的所有未被访问的邻接点,并标记为已被访问过。

(3)从这些邻接点出发进行广度优先遍历,直至图中所有和Vi有路径相通的顶点都被访问过。

(4)重复步骤(1)至步骤(3)的操作,直至所有顶点都被访问过。

 

/*****************本程序是以邻接矩阵存储方式的图的*********************/

#include <stdio.h>

#include "3-6 AdjMatrixGraph.c"

#define QUEUE_MAXSIZE 30 //队列的最大容量

typedef struct

{

    int Data[QUEUE_MAXSIZE]; //数据域

    int head; //队头指针

    int tail; //队尾指针

}SeqQueue; //队列结构

//队列操作函数

void QueueInit(SeqQueue *q); //初始化一个队列  

int QueueIsEmpty(SeqQueue q); //判断队列是否空  

int QueueIn(SeqQueue *q,int n); //将一个元素入队列  

int QueueOut(SeqQueue *q,int *ch); //将一个元素出队列                                                                                                         

 

//图操作函数

void DFSTraverse(MatrixGraph *G); //深度优先遍历

void BFSTraverse(MatrixGraph *G); //广度优先遍历

void DFSM(MatrixGraph *G,int i);

void BFSM(MatrixGraph *G,int i);

 

void QueueInit(SeqQueue *Q)    //队列初始化 

{

    Q->head=Q->tail=0;

}

int QueueIsEmpty(SeqQueue Q)   //判断队列是否已空,若空返回1,否则返回0

{

    return Q.head==Q.tail;

}

int QueueIn(SeqQueue *Q,int ch)   //入队列,成功返回1,失败返回0  

{

    if((Q->tail+1) % QUEUE_MAXSIZE ==Q->head) //若队列已满

        return 0;  //返回错误;

    Q->Data[Q->tail]=ch; //将数据ch入队列

    Q->tail=(Q->tail+1) % QUEUE_MAXSIZE; //调整队尾指针

    return 1; //成功,返回1

}

int QueueOut(SeqQueue *Q,int *ch)   //出队列,成功返回1,并用ch返回该元素值,失败返回0 

{

    if(Q->head==Q->tail) //若队列为空

        return 0; //返回错误

    *ch=Q->Data[Q->head]; //返回队首元素

    Q->head=(Q->head+1) % QUEUE_MAXSIZE; //调整队首指针

    return 1; //成功出队列,返回1  

}  

 

/*********************深度优先遍历**************************/

void DFSTraverse(MatrixGraph *G) //深度优先遍历

{

    int i;

    for(i=0;i<G->VertexNum;i++) //清除各顶点遍历标志

        G->isTrav[i]=0;

    printf("深度优先遍历结点:");

    for(i=0;i<G->VertexNum;i++)

        if(!G->isTrav[i]) //若该点未遍历

            DFSM(G,i); //调用函数遍历

    printf("\n");

 

}

void DFSM(MatrixGraph *G,int i) //从第i个结点开始,深度遍历图

{

    int j;

    G->isTrav[i]=1; //标记该顶点已处理过

    printf("->%c",G->Vertex[i]);//输出结点数据

//    printf("%d->",i); //输出结点序号

 

    //添加处理节点的操作

    for(j=0;j<G->VertexNum;j++)

        if(G->Edges[i][j]!=MAXVALUE && !G->isTrav[i])

            DFSM(G,j); //递归进行遍历

}

 

/*********************广度优先遍历**************************/

void BFSTraverse(MatrixGraph *G) //广度优先

{

    int i;

    for (i=0;i<G->VertexNum;i++) //清除各顶点遍历标志

        G->isTrav[i]=0;

    printf("广度优先遍历结点:");

    for (i=0;i<G->VertexNum;i++)

        if (!G->isTrav[i])

            BFSM(G,i);

    printf("\n");

}

void BFSM(MatrixGraph *G,int k) //广度优先遍历

{

    int i,j;

    SeqQueue Q; //创建循环队列

    QueueInit(&Q); //初始化循环队列

 

    G->isTrav[k]=1; //标记该顶点

    printf("->%c",G->Vertex[k]);  //输出第一个顶点

 

    //添加处理节点的操作

    QueueIn(&Q,k); //入队列

    while (!QueueIsEmpty(Q)) //队列不为空

    {

        QueueOut(&Q,&i); //出队列

        for (j=0;j<G->VertexNum;j++)

            if(G->Edges[i][j]!=MAXVALUE && !G->isTrav[j])

            {

                printf("->%c",G->Vertex[j]);

                G->isTrav[j]=1;  //标记该顶点

                //处理顶点

                QueueIn(&Q,j); //出队列

            }

    }

}

 

/*********************测试代码**************************/

int main()

{

    MatrixGraph G; //定义保存邻接表结构的图

    int path[VERTEX_MAX];

    int i,j,s,t;

    char select;

    do

    {

        printf("输入生成图的类型(0:无向图,1:有向图):");

        scanf("%d",&G.GraphType); //图的种类

        printf("输入图的顶点数量和边数量:");

        scanf("%d,%d",&G.VertexNum,&G.EdgeNum); //输入图顶点数和边数

        for(i=0;i<G.VertexNum;i++)  //清空矩阵

            for(j=0;j<G.VertexNum;j++)

                G.Edges[i][j]=MAXVALUE; //设置矩阵中各元素的值为0        

        CreateMatrixGraph(&G); //生成邻接表结构的图

        printf("邻接矩阵数据如下:\n");

        OutMatrix(&G); //输出邻接矩阵            

        DFSTraverse(&G); //深度优先搜索遍历图

        BFSTraverse(&G); //广度优先搜索遍历图

        printf("图遍历完毕,继续进行吗?(Y/N)");

        scanf(" %c",&select);

    }while(select!='N' && select!='n');   

    getch();

    return 0;

}

 

求最小生成树:

1、Prim算法

#define USED 0    //已使用,加入U集合

#define NOADJ -1  //非邻接顶点

void Prim(MatrixGraph G)//最小生成树

{

    int i,j,k,min,sum=0;

    int weight[VERTEX_MAX];//权值

    char tmpvertex[VERTEX_MAX];//临时顶点信息

   

    for(i=1;i<G.VertexNum;i++) //保存邻接矩阵中的一行数据                                                                                                      

    {

        weight[i]=G.Edges[0][i]; //权值

        if(weight[i]==MAXVALUE)

            tmpvertex[i]=NOADJ; //非邻接顶点

        else

            tmpvertex[i]=G.Vertex[0]; //邻接顶点

    }

    tmpvertex[0]=USED; //将0号顶点并入U集

    weight[0]=MAXVALUE; //设已使用顶点权值为最大值

    for(i=1;i<G.VertexNum;i++)

    {

        min=weight[0]; //最小权值

        k=i;

        for(j=1;j<G.VertexNum;j++) //查找权值最小的一个邻接边

            if(weight[j]<min && tmpvertex[j]>0) //找到具有更小权值的未使用边

            {

                min=weight[j]; //保存权值

                k=j; //保存邻接点序号

            }

        sum+=min;//累加权值

        printf("(%c,%c),",tmpvertex[k],G.Vertex[k]); //输出生成树一条边

        tmpvertex[k]=USED; //将编号为k的顶点并入U集

        weight[k]=MAXVALUE; //已使用顶点的权值为最大值

        for(j=0;j<G.VertexNum;j++) //重新选择最小边

            if(G.Edges[k][j]<weight[j] && tmpvertex[j]!=0)

            {

                weight[j]=G.Edges[k][j]; //权值

                tmpvertex[j]=G.Vertex[k]; //上一个顶点信息

            }

    }

    printf("\n最小生成树的总权值为:%d\n",sum);

}

 

/********************测试代码************************/

#include "3-6 AdjMatrixGraph.c"

#include "3-12 Prim.c"

int main()

{

    MatrixGraph G; //定义保存邻接表结构的图

    int path[VERTEX_MAX];

    int i,j,s,t;

    char select;

    do

    {

        printf("输入生成图的类型(0:无向图,1:有向图):");

        scanf("%d",&G.GraphType); //图的种类

        printf("输入图的顶点数量和边数量:");

        scanf("%d,%d",&G.VertexNum,&G.EdgeNum); //输入图顶点数和边数

 

        for(i=0;i<G.VertexNum;i++)  //清空矩阵

            for(j=0;j<G.VertexNum;j++)

                G.Edges[i][j]=MAXVALUE; //设置矩阵中各元素的值为0        

        CreateMatrixGraph(&G); //生成邻接表结构的图

        printf("邻接矩阵数据如下:\n");

        OutMatrix(&G);       

 

        printf("最小生成树的边为:\n");

        Prim(G);

 

        printf("继续进行吗?(Y/N)");

        scanf(" %c",&select);

        getchar();

    }while(select!='N' && select!='n');

    getch();

    return 0;

}

 

2、Dijkstra算法

void Dijkstra(MatrixGraph G)

{

    int weight[VERTEX_MAX];//某源点到各顶点的最短路径长度

    int path[VERTEX_MAX];//某源点到终点经过的顶点集合的数组

    int tmpvertex[VERTEX_MAX];//最短路径的终点集合

    int i,j,k,v0,min;

    printf("\n请输入源点的编号:");

    scanf("%d",&v0);

    v0--; //编号自减1(因数组是从0开始)

    for(i=0;i<G.VertexNum;i++) //初始辅助数组

    {

        weight[i]=G.Edges[v0][i]; //保存最小权值

        if(weight[i]<MAXVALUE && weight[i]>0) //有效权值

            path[i]=v0; //保存边

        tmpvertex[i]=0; //初始化顶点集合为空

    }

    tmpvertex[v0]=1; //将顶点v0添加到集合U中

    weight[v0]=0; //将源顶点的权值设为0

    for(i=0;i<G.VertexNum;i++)

    {

        min=MAXVALUE; //将min中保存一个最大值

        k=v0; //源顶点序号

        for(j=0;j<G.VertexNum;j++) //在U集合中查找未用顶点的最小权值                                                                             

            if(tmpvertex[j]==0 && weight[j]<min)

            {

                min=weight[j];

                k=j;

            }

        tmpvertex[k]=1;   //将顶点k加入集合U

        for(j=0;j<G.VertexNum;j++) //以顶点k为中间点,重新计算权值

            if(tmpvertex[j]==0 && weight[k]+G.Edges[k][j]<weight[j]) //有更小权值的路径

            {

                weight[j]=weight[k]+G.Edges[k][j]; //更新权值

                path[j]=k;

            }

    }

    printf("\n顶点%c到各顶点的最短路径为(终点 < 源点):\n",G.Vertex[v0]);

    for(i=0;i<G.VertexNum;i++)//输出结果

    {

        if(tmpvertex[i]==1)

        {

            k=i;           

            while(k!=v0)

            {

                j=k;

                printf("%c < ",G.Vertex[k]);

                k=path[k];

            }

            printf("%c\n",G.Vertex[k]);

        }else

            printf("%c<-%c:无路径\n",G.Vertex[i],G.Vertex[v0]);

    }

}

 

/********************测试代码**********************/

#include <stdio.h>

#include "3-6 AdjMatrixGraph.c"

#include "3-14 Dijkstra.c"

int main()

{

    MatrixGraph G; //定义保存邻接表结构的图

    int path[VERTEX_MAX];

    int i,j,s,t;

    char select;

    do

    {

        printf("输入生成图的类型(0:无向图,1:有向图):");

        scanf("%d",&G.GraphType); //图的种类

        printf("输入图的顶点数量和边数量:");

        scanf("%d,%d",&G.VertexNum,&G.EdgeNum); //输入图顶点数和边数

 

        for(i=0;i<G.VertexNum;i++)  //清空矩阵

            for(j=0;j<G.VertexNum;j++)

                G.Edges[i][j]=MAXVALUE; //设置矩阵中各元素的值为0        

        CreateMatrixGraph(&G); //生成邻接表结构的图

        printf("邻接矩阵数据如下:\n");

        OutMatrix(&G);       

 

        printf("最短路径:\n");

        Dijkstra(G);

 

        printf("继续进行吗?(Y/N)");

        scanf(" %c",&select);

        getchar();

    }while(select!='N' && select!='n');

    getch();

    return 0;

}


/*****************************************Java实现图******************************/

Java实现连接矩阵存储结构的图

package com.jtlyuan.graph;

publicclass MGraph {

    publicstaticintVERTEX_MAX = 25;

    char[] Vertex = newchar[VERTEX_MAX]; // 保存顶点信息(序号或字母)

    int[][] Edges = newint[VERTEX_MAX][VERTEX_MAX]; // 保存边的权                                                                              

    boolean[] isTrav = newboolean[VERTEX_MAX]; // 遍历标志

    intVertexNum; // 顶点数量

    intEdgeNum;// 边数量

    publicchar[] getVertex() {

       returnVertex;

    }

    publicvoid setVertex(char[] vertex) {

       Vertex = vertex;

    }

    publicint[][] getEdges() {

       returnEdges;

    }

    publicvoid setEdges(int[][] edges) {

       Edges = edges;

    }

    publicint getVertexNum() {

       returnVertexNum;

    }

    publicvoid setVertexNum(int vertexNum) {

       VertexNum = vertexNum;

    }

    publicint getEdgeNum() {

       returnEdgeNum;

    }

    publicvoid setEdgeNum(int edgeNum) {

       EdgeNum = edgeNum;

    }

}

 

深度优先遍历和广度优先遍历

package com.jtlyuan.graph;

 

import java.util.LinkedList;

import java.util.Queue;

 

publicclass GraphTraDemo {

    /****深度优先遍历******/

    publicvoid DFSTra(MGraph g){

       for(int i=0;i<g.VertexNum;i++){

           g.isTrav[i]=false;

       }

       for(int i =0 ;i<g.VertexNum;i++){                                                                                                                

           if(!g.isTrav[i]){

              DFS(g,i);

           }

       }

    }

    privatevoid DFS(MGraph g, int i) {

       g.isTrav[i]=true;

       System.out.print(g.Vertex[i]+ " --> ");

       for(int j = 0; j<g.VertexNum;j++){

           if(g.Edges[i][j]!=0&&!g.isTrav[j]){

              DFS(g,j);

           }

       }

    }

    /******广度优先遍历*********/

    publicvoid BFSTra(MGraph g){

       for(int i=0;i<g.VertexNum;i++){

           g.isTrav[i]=false;

       }

       for(int i =0 ;i<g.VertexNum;i++){

           if(!g.isTrav[i]){

              BFS(g,i);

           }

       }

    }

    privatevoid BFS(MGraph g, int i) {

       Queue<Integer> q = new LinkedList<Integer>();

       q.add(i);

       g.isTrav[i]=true;

       System.out.print(g.Vertex[i]+"-->");

 

       while(!q.isEmpty()){

           q.poll();

           for(int j = 0 ;j<g.VertexNum;j++){

              if(g.Edges[i][j]!=0&&!g.isTrav[j]){

                  System.out.print(g.Vertex[j]+"-->");

                  g.isTrav[j]=true;

                  q.add(j);

              }

           }

       }

    }

    publicstaticvoid main(String[] args) {

       MGraph g = new MGraph();

       g.setVertexNum(5);

       g.setEdgeNum(6);

       g.Vertex[0]='A';

       g.Vertex[1]='B';

       g.Vertex[2]='C';

       g.Vertex[3]='D';

       g.Vertex[4]='E';

       g.Edges[0][1]=3;

       g.Edges[0][3]=2;

       g.Edges[1][2]=9;

       g.Edges[2][4]=7;

       g.Edges[3][4]=6;

       g.Edges[4][1]=3;

       System.out.println("深度遍历");

       new GraphTraDemo().DFSTra(g);

       System.out.println("\n广度遍历");

       new GraphTraDemo().BFSTra(g);

    }

}

/*打印了

深度优先遍历

A --> B --> C --> E --> D -->

广度优先遍历

A-->B-->D-->C-->E-->

*/

 


阅读更多
个人分类: 数据结构与算法
想对作者说点什么? 我来说一句

MH5.0MH5.0MH5.0MH5.0MH5.0

2010年05月12日 228KB 下载

网站图网站图网站图网站图

2010年03月04日 6KB 下载

erp系统er图,自己做的请指教

2009年03月25日 218KB 下载

可牛影像 专门做图工具

2009年02月09日 4.16MB 下载

设计图片非常好1111111

2011年04月20日 545KB 下载

画ER图工具

2011年09月21日 1.27MB 下载

没有更多推荐了,返回首页

不良信息举报

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭