浅析数据结构-图的基本概念

线性表和树两类数据结构,线性表中的元素是“一对一”的关系,树中的元素是“一对多”的关系,本章所述的图结构中的元素则是“多对多”的关系。图(Graph)是一种复杂的非线性结构,在图结构中,每个元素都可以有零个或多个前驱,也可以有零个或多个后继,也就是说,元素之间的关系是任意的。

一、图的定义与术语

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

1、图的分类

图是按照无方向和有方向分为无向图和有向图。

左图为无向图是由顶点和边构成,右图为有向图是由顶点和弧(有向边构成)。弧有弧头和弧尾区别。

按照边分为稀疏图和稠密图,这是个模糊的概念,同样是相对的概念。

如果任意两个顶点之间都存在边叫完全图,有向的边叫有向完全图。如果无重复的边或者顶点到自身的边叫简单图。在用数学方式表示时,无向边用()表示,有向边用<>表示。现在我们讲解的图全是简单图。

左图没有重复的边或者到自身的边(简单图),右图则有。

这种边带权值的图叫网

2.图的顶点和边间关系

顶点的度:顶点关联边的数目。有向图图中有,入度:方向指向顶点的边;出度:方向背向顶点的边。在有向图中顶点的度就是两者之和。

路径长度:路径上边或者弧的数目。

左图中,从B到D的路径度为2,在右图中就是3了(粗线的边)。

右图中A的入度是2,出度是1;B的入度为0,出度是2.

连通

在无向图G中,任意两个顶点是相通的就是连通图。

左图不是连通图,AE之间没有连通。

二、图的存储结构

图的结构比价复杂,任意两个顶点之间都可能存在关系,不能用简单的顺序存储结构来表示。如果运用多重链表,即一个数据域多个指针域组成的结点表示图中一个结点,则造成大量存储单元浪费。

1、邻接矩阵

邻接矩阵用两个数组保存数据。一个一维数组存储图中顶点信息,一个二维数组存储图中边或弧的信息。

无向图中二维数组是个对称矩阵。

特点:

  • 1、0表示无边,1表示有边

    2、顶点的度是行内数组之和。

    3、求取顶点邻接点,将行内元素遍历下。

    有向图的邻接矩阵:有向图中讲究入度和出度,各行之和是出度,各列之和是入度。

    带权的图叫网,用邻接矩阵表示为:

    邻接矩阵对于边数相对顶点较少的图,就是对存储空间极大的浪费。

    2、邻接表

    邻接表:数组和链表相结合的存储方法为邻接表。

  • 图中顶点用一个一维数组存储。
  • 图中每个顶点Vi的所有邻接点构成一个线性表。

    从图中得知,顶点表的各个结点由data和Firstedge两个域表示,data是数据域,存储顶点信息,firstedge是指针域,指向边表的第一个结点,即顶点的第一个邻接点。边表结点由adjvex和next两个域组成。adjvex是邻接点域,存储某顶点的邻接点在顶点表中坐标,next存储边表中下一个结点指针。比如v1顶点与v2、v0互为邻接点,则在v1边表中,adjvex分别为0和2。

    有向图也可以用邻接表,出度表叫邻接表,入度表尾逆邻接表。

    3、十字链表

    在邻接表中针对有向图,分为邻接表和逆邻接表,导致无法从一个表中获取图的入读和出度的情况,有人提出了十字链表。

    定点表:

    其中firstin:入边表头指针,指向顶点入边表的第一个结点。

    firstout:出边表头指针,指向顶点出边表第一个结点。

    边表:

    其中tailvex是指弧起点在顶点表的下标,headvex弧终点在顶点表的下标,headlink入边表指针域,指向终点相同的下一条边,taillink是指边表指针域,指向起点相同的下一条边。

    4、邻接多重表

    邻接多重表结构如图:

    ivex和jvex是与某条边依附的两个顶点在顶点表中的下标。ilink指向依附项点ivex的下一条边,jlink指向依附顶点jvex的下一条边。

    三 、代码实现

    #include <iostream>
    
    #define  MAXVEX 100      //最大顶点数
    #define INFINITY 65535   //最大权值
    
    typedef int EdgeType;    //权值类型自己定义
    typedef char VertexType;  //顶点类型自己定义
    #pragma once
    
    #pragma region 邻接矩阵结构体
    typedef struct
    {
        VertexType vex[MAXVEX];   //顶点表
        EdgeType arg[MAXVEX][MAXVEX];  ///权值表-邻接矩阵
        int numVertexes,numEdges;  //图中的边数和顶点数
    }GraphArray;
    
    #pragma endregion
    
    #pragma region 邻接表结构体
    //边表结点
    typedef struct EdgeNode
    {
        int nNodevex;     //邻接点的点表中结点的坐标
        EdgeType nNodeWeight;   //用于网图中边的权值
        EdgeNode* next;       //链域,指向下一个邻接点
    }EdgeNode,*pEdgeNode;
    //顶点表结点
    typedef struct VertexNode
    {
        VertexType nNodeData;   //顶点表中存储的数据
        pEdgeNode pFirstNode;   //顶点表和边表中关联指针,指向边表头指针
    
    }VertexNode,pVertexNode,VertexList[MAXVEX];
    //图结构
    typedef struct
    {
        VertexList vertexList;
        int numVertess,numEdges;
    }GraphList;
    
    #pragma endregion
    
    class GraphData
    {
    public:
        GraphData(void);
        ~GraphData(void);
        #pragma region 创建邻接矩阵
        void CreateGraphArray(GraphArray* pGraphArray,int numVer,int numEdegs);
        int GetGraphLocation(GraphArray* pGraphArrray,char chpoint);
        #pragma endregion
    
        #pragma region 创建邻接表
        void CreateGraphList(GraphList* pList,int numVer,int numEdegs);
        int GetGraphListLocation(GraphList* pList,char chpoint);
        #pragma endregion
    
    };

    Graphdata.h

  • #include "GraphData.h"
    
    GraphData::GraphData(void)
    {
    }
    
    GraphData::~GraphData(void)
    {
    }
    
    int GraphData::GetGraphLocation(GraphArray* pGraphArrray,char chpoint)
    {
        int i = 0;
        for (i = 0;i< pGraphArrray->numVertexes;i++)
        {
            if (pGraphArrray->vex[i] == chpoint)
            {
                break;;
            }
        }
        if (i >= pGraphArrray->numVertexes)
        {
            return -1;
        }
        return i;
    }
    /// <summary>
    /// 创建邻接矩阵
    /// </summary>
    void GraphData::CreateGraphArray(GraphArray* pGraphArray,int numVer,int numEdegs)
    {
        int weight = 0;
        pGraphArray->numVertexes = numVer;
        pGraphArray->numEdges = numEdegs;
    
        //创建顶点表
        for (int i= 0; i < numVer;i++)
        {
            pGraphArray->vex[i] = getchar();
            while(pGraphArray->vex[i] == ‘\n‘)
            {
                pGraphArray->vex[i] = getchar();
            }
        }
    
        //创建邻接表的边矩阵
        for (int i = 0; i < numEdegs; i++)
        {
            for (int j = 0;j < numEdegs ; j++)
            {
                pGraphArray->arg[i][j] = INFINITY;
            }
        }
        for(int k = 0; k < pGraphArray->numEdges; k++)
        {
            char p, q;
            printf("输入边(vi,vj)上的下标i,下标j和权值:\n");
    
            p = getchar();
            while(p == ‘\n‘)
            {
                p = getchar();
            }
            q = getchar();
            while(q == ‘\n‘)
            {
                q = getchar();
            }
            scanf("%d", &weight);    
    
            int m = -1;
            int n = -1;
            m = GetGraphLocation(pGraphArray, p);
            n = GetGraphLocation(pGraphArray, q);
            if(n == -1 || m == -1)
            {
                fprintf(stderr, "there is no this vertex.\n");
                return;
            }
            //getchar();
            pGraphArray->arg[m][n] = weight;
            pGraphArray->arg[n][m] = weight;  //因为是无向图,矩阵对称
        }
    
    }
    
    #pragma region
    void GraphData::CreateGraphList(GraphList* pList,int numVer,int numEdegs)
    {
        int weight = 0;
        GraphList *pGraphList = pList;
        pGraphList->numVertess = numVer;
        pGraphList->numEdges = numEdegs;
        EdgeNode* firstNode,*secondNode;
        //创建顶点表
        for (int i= 0; i < numVer;i++)
        {
            pGraphList->vertexList[i].nNodeData = getchar();
            pGraphList->vertexList[i].pFirstNode = NULL;
            while(pGraphList->vertexList[i].nNodeData == ‘\n‘)
            {
                pGraphList->vertexList[i].nNodeData = getchar();
            }
        }
    
        //创建边表
        for(int k = 0; k < pGraphList->numEdges; k++)
        {
            char p, q;
            printf("输入边(vi,vj)上的下标i,下标j和权值:\n");
    
            p = getchar();
            while(p == ‘\n‘)
            {
                p = getchar();
            }
            q = getchar();
            while(q == ‘\n‘)
            {
                q = getchar();
            }
            scanf("%d", &weight);    
    
            int m = -1;
            int n = -1;
            m = GetGraphListLocation(pGraphList, p);
            n = GetGraphListLocation(pGraphList, q);
            if(n == -1 || m == -1)
            {
                fprintf(stderr, "there is no this vertex.\n");
                return;
            }
            //getchar();
            //字符p在顶点表的坐标为m,与坐标n的结点建立联系权重为weight
            firstNode = new EdgeNode();
            firstNode->nNodevex = n;
            firstNode->next = pGraphList->vertexList[m].pFirstNode;
            firstNode->nNodeWeight = weight;
            pGraphList->vertexList[m].pFirstNode = firstNode;
    
            //第二个字符second
            secondNode = new EdgeNode();
            secondNode->nNodevex = m;
            secondNode->next = pGraphList->vertexList[n].pFirstNode;
            secondNode->nNodeWeight = weight;
            pGraphList->vertexList[n].pFirstNode = secondNode;
    
        }
    }
    
    int GraphData::GetGraphListLocation(GraphList* pList,char chpoint)
    {
        GraphList *pGraphList = pList;
        int i = 0;
        for (i = 0;i< pGraphList->numVertess;i++)
        {
            if (pGraphList->vertexList[i].nNodeData == chpoint)
            {
                break;;
            }
        }
        if (i >= pGraphList->numVertess)
        {
            return -1;
        }
        return i;
    }
    
    #pragma endregion

    GraphData.cpp

    #include <iostream>
    #include "GraphData.h"
    using namespace std;
    //
    
    void PrintGrgph(GraphList *pGraphList)
    {
        int i =0;
        while(pGraphList->vertexList[i].pFirstNode != NULL && i<MAXVEX)
        {
            printf("顶点:%c  ",pGraphList->vertexList[i].nNodeData);
            EdgeNode *e = NULL;
            e = pGraphList->vertexList[i].pFirstNode;
            while(e != NULL)
            {
                printf("%d  ", e->nNodevex);
                e = e->next;
            }
            i++;
            printf("\n");
        }
    
    }
    int main()
    {
        int numVexs,numEdges;
        GraphData* pTestGraph = new GraphData();
        GraphArray graphArray;
        GraphArray* pGraphArray = &graphArray;
        GraphList* pGgraphList = new GraphList();
    
        cout<<"输入顶点数和边数"<<endl;
        cin>>numVexs>>numEdges;
        cout<<"顶点数和边数为:"<<numVexs<<numEdges<<endl;
    
        /*pTestGraph->CreateGraphArray(pGraphArray,numVexs,numEdges);
        for(int i = 0; i< numEdges;i++)
        {
            for (int j = 0;j< numEdges;j++)
            {
                cout<<pGraphArray->arg[i][j];
            }
            cout<<endl;
        }*/
        pTestGraph->CreateGraphList(pGgraphList,numVexs,numEdges);
        PrintGrgph(pGgraphList);
        system("pause");
    }

    TestGraph

时间: 2024-08-04 08:03:44

浅析数据结构-图的基本概念的相关文章

浅析数据结构-图的遍历

上一篇了解图的基本概念,包括图的分类.术语以及存储结构.本篇就是应用图的存储结构,将图进行数据抽象化,应用遍历方法,对数据进行遍历.由于图复杂的数据结构,一定保证图中所有顶点被遍历.如果只访问图的顶点而不关注边的信息,那么图的遍历十分简单,使用一个foreach语句遍历存放顶点信息的数组即可.但是,如果为了实现特定算法,就必须要根据边的信息按照一定的顺序进行遍历.图的遍历算法是求解图的连通性问题.拓扑排序和求解关键路径等算法的基础. 一.图的遍历   图的数据结构相对树复杂,图的任一顶点都可能和

数据结构-图之基本概念

在图中的数据元素称为顶点(Vertex).顶点之间的关系称为边(Edge).图G是由顶点的有穷集合V,以及边的集合E组成. 由有序对构成的图为有向图(Digraph).在有向图中,两个顶点之间的由弧(Arc)连接,起始点(Initial node)为弧尾(Tail),终止点(terminal node)为弧首(Head). 由无序对构成的图是无向图(Undigraph).无向图的一条边相当于有向图的中两条边,即如果无向图的顶点v1和v2之间有一条边,那么既有从v1连接到v2的边,也有从v2连接到

数据结构之图的基本概念

一 图的定义 定义:图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合. 在图中需要注意的是: (1)线性表中我们把数据元素叫元素,树中将数据元素叫结点,在图中数据元素,我们则称之为顶点(Vertex). (2)线性表可以没有元素,称为空表:树中可以没有节点,称为空树:但是,在图中不允许没有顶点(有穷非空性). (3)线性表中的各元素是线性关系,树中的各元素是层次关系,而图中各顶点的关系是用边来表示

?数据结构-图之强连通

数据结构-图之强连通 在一个无向图G中,若从顶点v_i到顶点v_j有路径相连(当然从v_j到v_i也一定有路径),则称v_i和v_j是连通的.如果G是有向图,那么连接v_i和v_j的路径中所有的边都必须同向.如果图中任意两点都是连通的,那么图被称作连通图.图的连通性是图的基本性质. 连通分量:无向图G的一个极大连通子图称为G的一个连通分量(或连通分支).连通图只有一个连通分量,即其自身:非连通的无向图有多个连通分量. 初级通路:通路中所有的顶点互不相同.初级通路必为简单通路,但反之不真. 强连通

考研数据结构复习随笔-基本概念(一)

数据结构是对于计算机专业的一门非常重要的专业课.今天我们首先了解一些数据结构的一些基本概念. 1.数据:数据是对于一切客观事物的符号表示,能够输入到计算机中,并且能被计算机识别并处理的符号的总称. 2 数据元素:是数据的基本单位,在计算机中通常作为一个整体进行处理和考虑. 3 数据项: 数据的不可分割的最小单位. 4数据对象:性质相同的数据元素的集合.它是数据的一个子集. 5数据结构: 是相互之间存在一种或者多种特定关系的数据元素的集合. 6结构:数据元素之间存在的关系称为结构.主要包括4种(1

C#与数据结构--图的遍历

C#与数据结构--图的遍历 8.2 图的存储结构 图 的存储结构除了要存储图中各个顶点的本身的信息外,同时还要存储顶点与顶点之间的所有关系(边的信息),因此,图的结构比较复杂,很难以数据元素在存储区 中的物理位置来表示元素之间的关系,但也正是由于其任意的特性,故物理表示方法很多.常用的图的存储结构有邻接矩阵.邻接表.十字链表和邻接多重表. 8.2.1  邻接矩阵表示法 对于一个具有n个顶点的图,可以使用n*n的矩阵(二维数组)来表示它们间的邻接关系.图8.10和图8.11中,矩阵A(i,j)=1

数据结构--图 的JAVA实现(上)

1,摘要: 本系列文章主要学习如何使用JAVA语言以邻接表的方式实现了数据结构---图(Graph),这是第一篇文章,学习如何用JAVA来表示图的顶点.从数据的表示方法来说,有二种表示图的方式:一种是邻接矩阵,其实是一个二维数组:一种是邻接表,其实是一个顶点表,每个顶点又拥有一个边列表.下图是图的邻接表表示. 从图中可以看出,图的实现需要能够表示顶点表,能够表示边表.邻接表指是的哪部分呢?每个顶点都有一个邻接表,一个指定顶点的邻接表中,起始顶点表示边的起点,其他顶点表示边的终点.这样,就可以用邻

数据结构:图(1)

一.图的基本概念 1.有向图 若图G中的每条边都是有方向的,则称G为有向图(Digraph). 2.无向图 若图G中的每条边都是没有方向的,则称G为无向图(Undigraph). 3.连通图的生成树 一个极小的连通子图,它含有图中全部的n个顶点,但只有足以构成一棵树的n-1条边. 二.图的存储结构 1.数组表示法 用两个数组分别存储数据元素(顶点)的信息和数据元素之间的关系(边或弧)的信息. 2.邻接表表示法 对于图G中的每个顶点vi,该方法把所有邻接于vi的顶点vj链成一个带头结点的单链表,这

数据结构-图

1.图的定义 图:是一种灵活的数据结构,一般作为一种模型用来定义对象之间的关系或者联系.对象由顶点表示,而对象之间的关系或关联则通过顶点之间的边来表示. 2.图的应用 图算法.统计网络跳数.拓扑排序.图着色.哈密顿圈问题.分团问题.可序列化冲突 3.图的代码实现 /*graph.h*/ #ifndef GRAPH_H #define GRAPH_H #include <stdlib.h> #include "list.h" #include "set.h"