1

图是一种比线性表和树更复杂的数据结构,在图中,结点之间的关系是任意的,任意两个数据元素之间都可能相关。图是一种多对多的数据结构。

基本概念

图是由顶点的有穷非空集合以及顶点的边的集合组成,通常表示为G(V,E); V是顶点的集合、E是边的集合;

线性表中可以没有元素,称为空表。树中可以没有结点,叫做空树。但是在图中不允许没有顶点,可以没有边。

基本术语

  • 无向边:若顶点Vi和Vj之间的边没有方向,称这条边为无向边(Edge),用(Vi,Vj)来表示。
  • 无向图(Undirected graphs):图中任意两个顶点的边都是无向边。
  • 有向边:若从顶点Vi到Vj的边有方向,称这条边为有向边,也称为弧(Arc),用 <Vi, Vj> 来表示,其中Vi称为弧尾(Tail),Vj称为弧头(Head)。
  • 有向图(Directed graphs):图中任意两个顶点的边都是有向边。
  • 简单图:不存在自环(顶点到其自身的边)和重边(完全相同的边)的图
  • 无向完全图:无向图中,任意两个顶点之间都存在边。
  • 有向完全图:有向图中,任意两个顶点之间都存在方向相反的两条弧。
  • 稀疏图;有很少条边或弧的图称为稀疏图,反之称为稠密图。
  • (Weight):表示从图中一个顶点到另一个顶点的距离或耗费。
  • :带有权重的图
  • 度:与特定顶点相连接的边数;
  • 出度、入度:有向图中的概念,出度表示以此顶点为起点的边的数目,入度表示以此顶点为终点的边的数目;
  • :第一个顶点和最后一个顶点相同的路径;
  • 简单环:除去第一个顶点和最后一个顶点后没有重复顶点的环;
  • 连通图:任意两个顶点都相互连通的图;
  • 极大连通子图:包含尽可能多的顶点(必须是连通的),即找不到另外一个顶点,使得此顶点能够连接到此极大连通子图的任意一个顶点;
  • 连通分量:极大连通子图的数量;
  • 强连通图:此为有向图的概念,表示任意两个顶点a,b,使得a能够连接到b,b也能连接到a 的图;
  • 生成树:n个顶点,n-1条边,并且保证n个顶点相互连通(不存在环);
  • 最小生成树:此生成树的边的权重之和是所有生成树中最小的;
  • AOV网(Activity On Vertex Network ):在有向图中若以顶点表示活动,有向边表示活动之间的先后关系
  • AOE网(Activity On Edge Network):在带权有向图中若以顶点表示事件,有向边表示活动,边上的权值表示该活动持续的时间

图的存储结构

1、邻接矩阵

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

  • 无向图


无向图由于不分方向,所以是一个对称矩阵。主对角线上全是0表示途中没有自环。

  • 有向图

带有权值的有向图中,数字表示权重,无穷表示弧不存在。这是因为0页有可能是权值,所以不存在使用无穷大表示的。

优缺点:

  • 优点:

    1. 便于判断两点是否有边
    2. 便于计算一个点的度,对于无向图,该点所在的那一行,就表示它的度。对于有向图,对应的那一行的个数是他的出度,那一列的个数是入读。
  • 缺点:

    1. 不便于增加和删除点
    2. 不便于计算边的数目
    3. 对于稀疏图,这种实现方式将浪费大量的空间。
代码实现
// 实现
#include <stdio.h>
#include <iostream>
using namespace std;
typedef char VertexType; 
typedef int EdegeType;

#define MAXSIZE 100
#define IUNFINITY 65535

typedef struct {
    VertexType vexs[MAXSIZE]; // 顶点信息 
    EdegeType arc[MAXSIZE][MAXSIZE]; // 边或者弧
    int vnum,edgenum;  // 定义点个边的个数 
}MGraphy;

void createGraphy(MGraphy *q) {
    cout<<"请输入点的个数和边数"<<endl; 
    cin>> q->vnum >> q->edgenum;
    // 初始化顶点数组 
    
    for(int i = 0; i < q->vnum; i++) {
        cout<<"请输入第"<<i+1<<"个顶点的信息"<<endl;
        cin >> q->vexs[i];
    }
    
    // 初始化边/弧
    for(int i = 0; i < q->vnum; i++) {
        for(int j = 0; j < q->vnum; j++) {
            q->arc[i][j] = IUNFINITY;
        }
    }
    
    // 更改边的信息 
    for(int j = 0; j <q->edgenum; j++) {
        cout<<"请输入第"<<j+1<<"个边的相关信息,例如: 1 1 2,表示(1,1)位置上权重为2"<<endl;
        int a , b , c;
        cin>>a>>b>>c;

        // 有向图
        q->arc[a][b] = c;
        q->arc[b][a] = c; 

        // 无向图
        // q->arc[a][b] = c;
    } 
    
} 

void display(MGraphy *q) {
    for(int i = 0 ; i < q->vnum; i++) {
        for(int j = 0 ; j < q->vnum; j++) {
            cout<< q->arc[i][j] <<"\t";
        }
        cout<<"\n";
    }
} 

int main() {
    MGraphy q;
    createGraphy(&q);
    display(&q);
    return 0;
}


// 结果

图片描述

// 来一个更全的

#include<iostream>
using namespace std;


enum Graphkind{ DG, DN, UDG, UDN }; //{有向图,无向图,有向网,无向网}
typedef struct  Node
{
    int * vex;  //顶点数组
    int vexnum; //顶点个数
    int edge;   //图的边数
    int ** adjMatrix; //图的邻接矩阵
    enum Graphkind kind;
}MGraph;
void createGraph(MGraph & G,enum Graphkind kind)
{
    cout << "输入顶点的个数" << endl;
    cin >> G.vexnum;
    cout << "输入边的个数" << endl;
    cin >> G.edge;
    //输入种类

    //cout << "输入图的种类:DG:有向图 DN:无向图,UDG:有向网,UDN:无向网" << endl;
    G.kind = kind;
    //为两个数组开辟空间
    G.vex = new int[G.vexnum];
    G.adjMatrix = new int*[G.vexnum];
    cout << G.vexnum << endl;
    int i;
    for (i = 0; i < G.vexnum; i++)
    {
        G.adjMatrix[i] = new int[G.vexnum];
    }
    for (i = 0; i < G.vexnum; i++)
    {
        for (int k = 0; k < G.vexnum; k++)
        {
            if (G.kind == DG || G.kind == DN)
            {
                G.adjMatrix[i][k] = 0;
            }
            else {
                G.adjMatrix[i][k] = INT_MAX;
            }
        }

    }



    /*//输入每个元素的信息,这个信息,现在还不需要使用
    for (i = 0; i < G.vexnum; i++)
    {
        cin >> G.vex[i];
    }*/
    cout << "请输入两个有关系的顶点的序号:例如:1 2 代表1号顶点指向2号顶点" << endl;
    for (i = 0; i < G.edge; i++)
    {
        int a, b;
        cin >> a;
        cin >> b;
        if (G.kind == DN) {
            G.adjMatrix[b - 1][a - 1] = 1;
            G.adjMatrix[a - 1][b - 1] = 1;
        }
        else if (G.kind == DG)
        {
            G.adjMatrix[a - 1][b - 1] = 1;
        }
        else if (G.kind == UDG)
        {
            int weight;
            cout << "输入该边的权重:" << endl;
            cin >> weight;
            G.adjMatrix[a - 1][b - 1] = weight;
        }
        else {
            int weight;
            cout << "输入该边的权重:" << endl;
            cin >> weight;
            G.adjMatrix[b - 1][a - 1] = weight;
            G.adjMatrix[a - 1][b - 1] = weight;
        }   
    }
}


void print(MGraph g)
{
    int i, j;
    for (i = 0; i < g.vexnum; i++)
    {
        for (j = 0; j < g.vexnum; j++)
        {
            if (g.adjMatrix[i][j] == INT_MAX)
                cout << "∞" << " ";
            else
            cout << g.adjMatrix[i][j] << " ";
        }
        cout << endl;
    }
}

void clear(MGraph G)
{
    delete G.vex;
    G.vex = NULL;
    for (int i = 0; i < G.vexnum; i++)
    {
        delete G.adjMatrix[i];
        G.adjMatrix[i] = NULL;
    }
    delete G.adjMatrix;
}
int main()
{

        MGraph G;
        cout << "有向图例子:" << endl;
        createGraph(G, DG);
        print(G);
        clear(G);
        cout << endl;
        cout << "无向图例子:" << endl;
        createGraph(G, DN);
        print(G);
        clear(G);

        cout << endl;
        cout << "有向图网例子:" << endl;
        createGraph(G, UDG);
        print(G);
        clear(G);

        cout << endl;
        cout << "无向图网例子:" << endl;
        createGraph(G, UDN);
        print(G);
        clear(G);

        cout << endl;
    return 0;
}


2、邻接表

引入链式存储结构。他是将图中的每一个顶点都建立了一个链表,把与Vi相连接的顶点都放在了这个链表中了。这个邻接表可以说是顶点的出度表,邻接表关心了出度,但是如果求入度,则需要遍历整个数组了。

从图中可以看出,顶点是通过一个结点类型的一维数组在存储的,其中的头节点是的firstarc 指向的是第一条依附在该节点上的顶点的信息,表结点的adjvex表示的是该边的另一个节点的数组下标。nextarc指向下一个与头节点相连的结点。
weight是权重域,对于普通图没有意义。

  • 一个有向图的例子

代码实现
//
#include <iostream>
#include <string>

using namespace std;
typedef char VertexType;
// 表结构 
struct arcNode {
    int adjvex; // 节点索引
    arcNode *nextarc;  // 下一个节点 
    int weight; // 权重 
}; 

// 头节点 
struct Vnode{
    VertexType data;
    arcNode *firstNode;
};

struct Graph{
    int kind; //  (有向图:0,无向图:1,有向网:2,无向网:3)
    int vexnum; // 点数 
    int edegnum; // 边数 
    Vnode *node; // 头节点首地址 
}; 

// 创建 
void createGraph(Graph *q, int kind) {
    cout<<"请输入点数"<<endl;
    cin>>q->vexnum;
    cout<<"请输入边数"<<endl;
    cin>>q->edegnum;
    q->kind = kind;
    q->node = new Vnode[q->vexnum]; // 动态分配内存 
    int i ;
    cout << "输入每个顶点的信息:" << endl;//记录每个顶点的信息
    
    for(i = 0 ; i < q->vexnum; i++) {
        cin >> q->node[i].data;
        q->node[i].firstNode = NULL;
    }
    cout << "请输入每条边的起点和终点的编号:" << endl;
    
    for(i = 0; i<q->edegnum; i++) {
        int a,b;
        cin>>a >> b; // 起点 终点
        arcNode *next = new arcNode;
        next->adjvex = b-1;
        if(kind == 0  || kind == 1) {
            next->weight = -1;
        } else {
            cout<<"输入权重"<<endl;
            cin>> next->weight; 
        }
        next->nextarc = NULL;
        
        // 如果是第一个 
        if(q->node[a-1].firstNode == NULL) {
            q->node[a-1].firstNode = next;
        } else {
            
            // 如果不是第一个哦
            arcNode *p ;
            p = q->node[a-1].firstNode;
            while(p->nextarc){
                p = p->nextarc;
            }
            p->nextarc = next;
        }
        
    }
    
     
} 


// 打印

void print(Graph q) {
    int i;
    cout<<"图的邻接表为"<<endl;
    for(i = 0 ; i <q.vexnum; i++ )  {
        cout<<q.node[i].data<< " ";
        arcNode *p;
        p = q.node[i].firstNode;
        while(p) {
            cout<<p->adjvex << " ";
            p = p->nextarc;
        } 
        cout<<endl;
    }
}

int main() {
    Graph g;
    cout << "有向图的例子" << endl;
    createGraph(&g,0);
    print(g);
    cout << endl;
    cout << "无向图的例子" << endl;
    createGraph(&g, 1);
    print(g);
    cout << endl;
    return 0;
}
  • 优点

    1. 便于增删
    2. 便于统计数目,按找顶点扫描所有边表可以得到边的个数。
    3. 空间利用率高。但是不适合稠密图
  • 缺点

    1. 不便于判断顶点之间的是否有边,必须要扫描某一个边表。
    2. 不便于计算顶点的度。如果是无向图,顶点vi的度是第i个边表的结点的个数。如果是有向图,求出度较为方便,但是求出度则较为复杂,因为要遍历整个邻接表。如果是逆邻接表,那么是求入读比较容易,求出度较难。

3、十字链表

十字链表便于计算顶点的入度和出度。它是有向图的一个专门的链表结构。它跟邻接表一样也是两个结构,一个结构用于保存顶点信息,另一个用于保存各边的信息。

同样我们知道头结点就是用于保存每个顶点信息的结构,其中data主要是保存顶点的信息(如顶点的名称),firstin是保存第一个入度的边的信息,firstout保存第一个出度的边的信息。其中,表结点就是记录每条边的信息,其中tailvex是记录这条边弧头的顶点的在顶点表中的下标(不是箭头那个),headvex则是记录弧尾对应的那个顶点在顶点表中的下标(箭头的那个),hlink是指向具有下一个具有相同的headvex的表结点,tlink指向具有相同的tailvex的表结点,weight是表示边的权重(网图才需要使用)。

代码实现
// 
#include<iostream>
#include<string>
using namespace std;

typedef string Vertextype;
//表结点结构
struct ArcNode {
    int tailvex;   //弧尾的下标,一般都是和对应的头结点下标相同
    int headvex;   //弧头的下标
    ArcNode * hlink; //指向下一个弧头同为headvex的表结点 ,边是箭头的那边
    ArcNode * tlink;  //指向下一个弧尾为tailvex的表结点,边不是箭头的那边
    int weight;  //只有网才会用这个变量

};

//头结点
struct Vnode
{
    Vertextype data;  //这个是记录每个顶点的信息(现在一般都不需要怎么使用)
    ArcNode *firstin; //指向第一条(入度)在该顶点的表结点
    ArcNode *firstout; //指向第一条(出度)在该顶点的表结点
};

struct Graph
{
    int kind;  //图的种类(有向图:0,有向网:1)
    int vexnum; //图的顶点数
    int edge;  //图的边数
    Vnode * node; //图的(顶点)头结点数组
};

void createGraph(Graph & g,int kind)
{
    cout << "请输入顶点的个数:" << endl;
    cin >> g.vexnum;
    cout << "请输入边的个数(无向图/网要乘2):" << endl;
    cin >> g.edge;
    g.kind = kind; //决定图的种类
    g.node = new Vnode[g.vexnum];
    int i;
    cout << "输入每个顶点的信息:" << endl;//记录每个顶点的信息
    for (i = 0; i < g.vexnum; i++)
    {
        cin >> g.node[i].data;
        g.node[i].firstin = NULL;
        g.node[i].firstout = NULL;
    }

    cout << "请输入每条边的起点和终点的编号:" << endl;
    for (i = 0; i < g.edge; i++)
    {
        int a, b;
        cin >> a;
        cin >> b;

        ArcNode * next = new ArcNode;
        next->tailvex = a - 1; //首先是弧头的下标
        next-> headvex = b - 1; //弧尾的下标
        //只有网图需要权重信息
        if(kind==0)
        next->weight = -1;
        else
        {
            cout << "输入该边的权重:" << endl;
            cin >> next->weight;
        }
        next->tlink = NULL;
        next->hlink = NULL;
        //该位置的顶点的出度还为空时,直接让你fisrstout指针指向新的表结点
        //记录的出度信息
        if (g.node[a - 1].firstout == NULL)
        {
            g.node[a - 1].firstout = next;
        }
        else
        {
            ArcNode * now;
            now = g.node[a - 1].firstout;
            while (now->tlink)
            {
                now = now->tlink;
            }
            now->tlink = next;
        }
        //记录某个顶点的入度信息
        if (g.node[b - 1].firstin == NULL)
        {
            g.node[b - 1].firstin = next;
        }
        else {
            ArcNode * now;
            now = g.node[b - 1].firstin;
            while (now->hlink)//找到最后一个表结点
            {
                now = now->hlink;
            }
            now->hlink = next;//更新最后一个表结点
        }
    }
}

void print(Graph g)
{
    int i;
    cout << "各个顶点的出度信息" << endl;
    for (i = 0; i < g.vexnum; i++)
    {
        cout << g.node[i].data << " ";
        ArcNode * now;
        now = g.node[i].firstout;
        while (now)
        {
            cout << now->headvex << " ";
            now = now->tlink;
        }
        cout << "^" << endl;
    }

    cout << "各个顶点的入度信息" << endl;

    for (i = 0; i < g.vexnum; i++)
    {
        cout << g.node[i].data << " ";
        ArcNode * now;
        now = g.node[i].firstin;
        while (now)
        {
            cout << now->tailvex << " ";
            now = now->hlink;
        }
        cout << "^" << endl;
    }
}


int main()
{
    Graph g;
    cout << "有向图的例子" << endl;
    createGraph(g, 0);
    print(g);
    cout << endl;
    return 0;
}


3、邻接多重表

邻接多重表是无向图的另一种链式存储结构。我们之前也说了使用邻接矩阵来存储图比价浪费空间,但是如果我们使用邻接表来存储图时,对于无向图又有一些不便的地方,例如我们需要对一条已经访问过的边进行删除或者标记等操作时,我们除了需要找到表示同一条边的两个结点。这会给我们的程序执行效率大打折扣,所以这个时候,邻接多重表就派上用场啦。

首先,邻接多重表同样是对邻接表的一个改进得到来的结构,它同样需要一个头结点保存每个顶点的信息和一个表结点,保存每条边的信息,他们的结构如下:

其中,头结点的结构和邻接表一样,而表结点中就改变比较大了,其中mark为标志域,例如标志是否已经访问过,ivex和jvex代表边的两个顶点在顶点表中的下标,ilink指向下一个依附在顶点ivex的边,jlink指向下一个依附在顶点jvex的边,weight在网图的时候使用,代表该边的权重。

#include<iostream>
#include<string>
using namespace std;

//表结点
struct ArcNode
{
    int mark; //标志位
    int ivex; //输入边信息的那个起点
    ArcNode * ilink; //依附在顶点ivex的下一条边的信息
    int jvex;   //输入边信息的那个终点
    ArcNode * jlink; //依附在顶点jvex的下一条边的信息
    int weight;
};

//头结点
struct VexNode {
    string data;   //顶点的信息,如顶点名称
    ArcNode * firstedge; //第一条依附顶点的边
};

struct Graph {
    int vexnum;   //顶点的个数
    int edge;    //边的个数
    VexNode *node; //保存顶点信息
};

void createGraph(Graph & g)
{
    cout << "请输入顶点的个数:" << endl;
    cin >> g.vexnum;
    cout << "请输入边的个数(无向图/网要乘2):" << endl;
    cin >> g.edge;
    g.node = new VexNode[g.vexnum];

    int i;
    cout << "输入每个顶点的信息:" << endl;//记录每个顶点的信息
    for (i = 0; i < g.vexnum; i++)
    {
        cin >> g.node[i].data;
        g.node[i].firstedge = NULL;
    }

    cout << "请输入每条边的起点和终点的编号:" << endl;
    for (i = 0; i < g.edge; i++)
    {
        int a, b;
        cin >> a;
        cin >> b;

        ArcNode * next = new ArcNode;
        next->mark = 0;
        next->ivex = a - 1; //首先是弧头的下标
        next->jvex = b - 1; //弧尾的下标
        next->weight = -1;
        next->ilink = NULL;
        next->jlink = NULL;

        //更新顶点表a-1的信息
        if (g.node[a - 1].firstedge == NULL)
        {
            g.node[a - 1].firstedge = next;
        }
        else {
            ArcNode * now;
            now = g.node[a - 1].firstedge;
            while (1) {
                if (now->ivex == (a - 1) && now->ilink == NULL)
                {
                    now->ilink = next;
                    break;
                }
                else if (now->ivex == (a - 1) && now->ilink != NULL) {
                    now = now->ilink;
                }
                else if (now->jvex == (a - 1) && now->jlink == NULL)
                {
                    now->jlink = next;
                    break;
                }
                else if (now->jvex == (a - 1) && now->jlink != NULL) {
                    now = now->jlink;
                }
            }
        }
        //更新顶点表b-1
        if (g.node[b - 1].firstedge == NULL)
        {
            g.node[b - 1].firstedge = next;
        }
        else {
            ArcNode * now;
            now = g.node[b - 1].firstedge;
            while (1) {
                if (now->ivex == (b - 1) && now->ilink == NULL)
                {
                    now->ilink = next;
                    break;
                }
                else if (now->ivex == (b - 1) && now->ilink != NULL) {
                    now = now->ilink;
                }
                else if (now->jvex == (b - 1) && now->jlink == NULL)
                {
                    now->jlink = next;
                    break;
                }
                else if (now->jvex == (b - 1) && now->jlink != NULL) {
                    now = now->jlink;
                }
            }
        }

    }
}

void print(Graph g)
{
    int i;
    for (i = 0; i < g.vexnum; i++)
    {
        cout << g.node[i].data << " ";
        ArcNode * now;
        now = g.node[i].firstedge;
        while (now)
        {
            cout << "ivex=" << now->ivex << " jvex=" << now->jvex << " ";
            if (now->ivex == i)
            {
                now = now->ilink;
            }
            else if (now->jvex == i)
            {
                now = now->jlink;
            }
        }
        cout << endl;
    }
}
int main()
{
    Graph g;
    createGraph(g);
    print(g);
    system("pause");
    return 0;

}

图的遍历

从一个顶点出发,然后访问其余顶点,且每个顶点都必须访问一次。称为时图的遍历。图的遍历有两种,一种是深度优先搜需(DFS)、另一种是广度优先搜索(BFS)

为了避免重复访问,可设置一个标志顶点是否被访问过的辅助数组 visited []

思路: DFS 在访问图中某一起始顶点 v 后, 由 v 出发, 访问它的任一邻接顶点 w1; 再从 w1 出发,访问与 w1邻 接但还没有访问过的顶点 w2; 然后再从 w2 出发, 进行类似的访问, … 如此进行下去, 直至到达所有的邻接顶点都被访问过的顶点 u 为止。接着, 退回一步, 退到前一次刚访问过的顶点, 看是否还有其它没有被访问的邻接顶点。如果有, 则访问此顶点, 之后再从此顶点出发, 进行与前述类似的访问; 如果没有, 就再退回一步进行搜索。重复上述过程, 直到连通图中所有顶点都被访问过为止。

代码实现

  • 邻接矩阵的DFS
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
typedef char VertexType; 
typedef int EdegeType;

#define MAXSIZE 100
#define IUNFINITY 65535
bool visit[MAXSIZE]; // 是否已被遍历
typedef struct {
    string vexs[MAXSIZE]; // 顶点信息 
    EdegeType arc[MAXSIZE][MAXSIZE]; // 边或者弧
    int vnum,edgenum;  // 定义点个边的个数 
}MGraphy;

// 创建无向图 
void createGraphy(MGraphy *q) {
    cout<<"请输入点的个数和边数"<<endl; 
    cin>> q->vnum >> q->edgenum;
    // 初始化顶点数组 
    
    for(int i = 0; i < q->vnum; i++) {
        cout<<"请输入第"<<i+1<<"个顶点的信息"<<endl;
        cin >> q->vexs[i];
    }
    
    // 初始化边/弧
    for(int i = 0; i < q->vnum; i++) {
        for(int j = 0; j < q->vnum; j++) {
            q->arc[i][j] = 0;
        }
    }
    
    // 更改边的信息 
    for(int j = 0; j <q->edgenum; j++) {
        cout<<"请输入第"<<j+1<<"个边的相关信息,例如: 1 1 ,表示(1,1)位置上"<<endl;
        int a , b ;
        cin>>a>>b;
        q->arc[a][b] = 1;
        q->arc[b][a] = 1; 
    } 
    
} 

// 创建有向图
void createGraphy1(MGraphy *q) {
    cout<<"请输入点的个数和边数"<<endl; 
    cin>> q->vnum >> q->edgenum;
    // 初始化顶点数组 
    
    for(int i = 0; i < q->vnum; i++) {
        cout<<"请输入第"<<i+1<<"个顶点的信息"<<endl;
        cin >> q->vexs[i];
    }
    
    // 初始化边/弧
    for(int i = 0; i < q->vnum; i++) {
        for(int j = 0; j < q->vnum; j++) {
            q->arc[i][j] = 0;
        }
    }
    
    // 更改边的信息 
    for(int j = 0; j <q->edgenum; j++) {
        cout<<"请输入第"<<j+1<<"个边的相关信息,例如: 1 1 ,表示(1,1)位置上"<<endl;
        int a , b ;
        cin>>a>>b;
        q->arc[a][b] = 1;
    } 
    
} 

// 输出展示 
void display(MGraphy *q) {
    for(int i = 0 ; i < q->vnum; i++) {
        for(int j = 0 ; j < q->vnum; j++) {
            cout<< q->arc[i][j] <<"\t";
        }
        cout<<"\n";
    }
} 


// 无向图的深度优先遍历
void DFS_AM(MGraphy q, int v) {
    int w ;
    visit[v] = true;
    cout<<q.vexs[v]<<endl;
    for(w = 0; w < q.vnum; w++) {
        if(q.arc[v][w]==1 && !visit[w]) {
            DFS_AM(q, w);
        }
    } 
}
 

int main() {
//    MGraphy q;
//    createGraphy(&q); // 创建无向图 
//    display(&q);
//    cout<<"深度优先遍历无向图"<<endl;
//    DFS_AM(q, 0);


    MGraphy p;
    createGraphy1(&p); // 创建无向图 
    display(&p);
    cout<<"深度优先遍历有向图"<<endl;
    DFS_AM(p, 0);
    
    
    return 0;
}
  • 邻接表

Meils
1.6k 声望157 粉丝

前端开发实践者