GRAPH

图、广度优先算法与深度优先算法

图(Graph)

结构类型研究方向
线性结构研究数据元素之间的一对一关系。
树结构研究数据元素之间的一对多关系。
图结构研究数据元素之间的多对多关系。

线性结构:研究数据元素之间的一对一关系。在这种结构中,除第一个和最后一个元素外,任何一个元素都有唯一的一个直接前驱和直接后继。
树结构:研究数据元素之间的一对多关系。在这种结构中,每个元素对下(层)可以有0个或多个元素相联系,对上(层)只有唯一的一个元素相关,数据元素之间有明显的层次关系。
图结构:研究数据元素之间的多对多关系。在这种结构中,任意两个元素之间可能存在关系。即结点之间的关系可以是任意的,图中任意元素之间都可能相关。

基本概念

图的定义

定义:图定义为一个偶对(V,E) ,记为G=(V,E) 。
其中: V是顶点(Vertex)的非空有限集合,记为V(G);E是无序集V&V的一个子集,记为E(G) ,其元素是图的弧(Arc)。

形式化定义
G=(V ,E)
V={v|vdata object}
E={<v,w>| v,wV∧p(v,w)}
P(v,w)表示从顶点v到顶点w有一条直接通路。

图的相关术语

弧(Arc):表示两个顶点v和w之间存在一个关系,用顶点偶对<v,w>表示。通常根据图的顶点偶对将图分为有向图和无向图。

有向图: 若图G的关系集合E(G)中,顶点偶对<v,w>的v和w之间是有序的,称图G是有向图。
在有向图中,若 <v,w>E(G) ,表示从顶点v到顶点w有一条弧。 其中:v称为弧尾或始点,w称为弧头或终点。

无向图: 若图G的关系集合E(G)中,顶点偶对<v,w>的v和w之间是无序的,称图G是无向图。
在无向图中,若<v,w>E(G) ,有<w,v>E(G) ,即E(G)是对称,则用无序对(v,w) 表示v和w之间的一条边(Edge),因此(v,w) 和(w,v)代表的是同一条边。

注意:有序对和无序对所用的括号不一样,有序对使用尖括号,无序对使用圆括号。

入度出度:对于无向图G=(V,E), viV,图G中依附于vi的边的数目称为顶点vi的度,记为TD(vi)。
显然,在无向图中,所有顶点度的和是图中边的2倍。 即 ∑TD(vi)=2e i=1, 2, …, n ,e为图的边数。
对有向图G=(V,E),若vi V ,图G中以vi作为起点的有向边(弧)的数目称为顶点vi的出度,记为OD(vi) ;以vi作为终点的有向边(弧)的数目称为顶点vi的入度,记为ID(vi) 。顶点vi的出度与入度之和称为vi的度,记为TD(vi) 。即
TD(vi)=OD(vi)+ID(vi)

抽象数据定义

ADT Graph{
数据对象V:具有相同特性的数据元素的集合,称为顶点集。
数据关系R:R={VR}
//VR={<v,w>|<v,w>| v,wV∧p(v,w) ,<v,w>表示从v到w的弧,P(v,w)定义了弧<v,w>的信息 }
基本操作P:
Create_Graph() : 图的创建操作。
    初始条件:无。
    操作结果:生成一个没有顶点的空图G。
GetVex(G, v) : 求图中的顶点v的值。
    初始条件:图G存在,v是图中的一个顶点。
    操作结果:生成一个没有顶点的空图G.
… …
DFStraver(G,V):从v出发对图G深度优先遍历。
    初始条件:图G存在。
    操作结果:对图G深度优先遍历,每个顶点访问且只访问一次。
BFStraver(G,V):从v出发对图G广度优先遍历。
    初始条件:图G存在。
    操作结果:对图G广度优先遍历,每个顶点访问且只访问一次。
} ADT Graph

图的存储结构

图的存储结构相对复杂,其复杂性主要表现在:

  • 任意顶点之间可能存在联系,无法以数据元素在存储区中的物理位置来表示元素之间的关系。
  • 图中顶点的度不一样,有的可能相差很大,如果按照度数最大的顶点设计结点结构,则会浪费很多存储单元,反之按照每个顶点自己的度设计不同结构则会影响操作。

常用存储结构邻接矩阵、邻接链表、十字链表、临界多重表和边表。

邻接矩阵(Matrix)

基本思想:对于有n个顶点的图,用一维数组vexs[n]存储顶点信息(类似于线性表中的数据域),用二维数组A[n][n]存储顶点之间关系的信息。该二维数组称为邻接矩阵。在邻接矩阵中,以顶点在vexs数组中的下标代表顶点,邻接矩阵中的元素A[i][j]存放的是顶点i到顶点j之间关系的信息。

无向无权图G=(V,E)有n(n≧1)个顶点,其邻接矩阵是n阶对称方阵,如图7-5所示。其元素的定义如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F16cqmsG-1591419259863)(./G.png)]

建立图(Graph)类
#define MaxVnum 50//设置最大顶点数50
typedef double Matrix[MaxVnum][MaxVnum];//建立一个二位矩阵类型

class Graph
{
public:
    Graph();
    ~Graph();
    void printArcs();
    void printvexnum();
    void reset();
    void DFS(int v);
    void BFS();
private:
    int vexnum = 8;//顶点数
    int arcnum = 9;//孤数
    int vexs[8];//顶点集
    Matrix arcs;//邻接矩阵
    bool visited[8];//用于判断顶点是否被访问了
};
初始化Graph对象
Graph::Graph()
{
    for (int i = 0; i < vexnum; i++)
    {
        for (int j = 0; j < vexnum; j++)
        {
            arcs[i][j] = 0;
        }
    }

    arcs[0][1] = 1;
    arcs[0][2] = 1;
    arcs[1][0] = 1;
    arcs[1][3] = 1;
    arcs[1][4] = 1;
    arcs[2][0] = 1;
    arcs[2][5] = 1;
    arcs[2][6] = 1;
    arcs[3][1] = 1;

    arcs[3][7] = 1;
    arcs[4][1] = 1;
    arcs[4][7] = 1;
    arcs[5][2] = 1;
    arcs[5][6] = 1;
    arcs[6][2] = 1;
    arcs[6][5] = 1;
    arcs[7][3] = 1;
    arcs[7][4] = 1;

    for (int i = 0; i < vexnum; i++)
    {
        vexs[i] = i + 1;
    }
}

图的深度优先算法

void Graph::DFS(int v)
{
    visited[v] = true;
    cout << vexs[v] << "  ";//输出顶点中的数据
    for (int i = 0; i < vexnum; i++)
    {
        if (arcs[v][i]==1&&visited[i]==false)
        {
            DFS(i);
        }
    }
}

图的广度优先算法

#include "Queue.h"//循环队列
void Graph::BFS()
{
    CirQueue Q;
    for (int i = 0; i < vexnum; i++)
    {
        if (visited[i]==false)
        {
            Q.EnQueue(i);
            visited[i] = true;
            while (!Q.Empty())
            {
                int t = Q.DeQueue();
                cout << vexs[t] << "  ";
                for (int j = 0; j < vexnum; j++)
                {
                    if (arcs[t][j]==1&&visited[j]==false)
                    {
                        Q.EnQueue(j);
                        visited[j] = true;
                    }
                }
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值