数据结构---图的详细介绍

1、名词解释:

  • 图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。在图中的数据元素,我们称之为顶点(Vertex),顶点集合有穷非空。在图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。

  • 图按照边的有无方向分为无向图和有向图。无向图由顶点和边组成,有向图由顶点和弧构成。弧有弧尾和弧头之分,带箭头一端为弧头。

  • 图按照边或弧的多少分稀疏图和稠密图。如果图中的任意两个顶点之间都存在边叫做完全图,有向的叫有向完全图。若无重复的边或顶点到自身的边则叫简单图。

  • 图中顶点之间有邻接点、依附的概念。无向图顶点的边数叫做度。有向图顶点分为入度和出度。

  • 图上的边或弧带有权则称为网。

  • 图中顶点间存在路径,两顶点存在路径则说明是连通的,如果路径最终回到起始点则称为环,当中不重复的叫简单路径。若任意两顶点都是连通的,则图就是连通图,有向则称为强连通图。图中有子图,若子图极大连通则就是连通分量,有向的则称为强连通分量。

  • 无向图中连通且n个顶点n-1条边称为生成树。有向图中一顶点入度为0其余顶点入度为1的叫有向树。一个有向图由若干棵有向树构成生成森林。

2、图的存储结构—-邻接矩阵

图的邻接矩阵的表示方式需要两个数组来表示图的信息,一个一维数组表示每个数据元素的信息,一个二维数组(邻接矩阵)表示图中的边或者弧的信息。

如果图有n个顶点,那么邻接矩阵就是一个n*n的方阵,方阵中每个元素的值的计算公式如下:
这里写图片描述

邻接矩阵表示图的具体示例如下图所示:

首先给个无向图的实例:

扫描二维码关注公众号,回复: 1812473 查看本文章

这里写图片描述

下面是一个有向图的实例:
这里写图片描述

OK,到这里为止,我们给出一个无向图的邻接矩阵和一个有向图的邻接矩阵,我们可以从这两个邻接矩阵得出一些结论:

  • 无向图的邻接矩阵都是沿对角线对称的
  • 要知道无向图中某个顶点的度,其实就是这个顶点vi在邻接矩阵中第i行或(第i列)的元素之和;
  • 对于有向图,要知道某个顶点的出度,其实就是这个顶点vi在邻接矩阵中第i行的元素之和,如果要知道某个顶点的入度,那就是第i列的元素之和。

但是,如果我们需要表示的图是一个网的时候,例如假设有个图有n个顶点,同样该网的邻接矩阵也是一个n*n的方阵,只是方阵元素的值的计算方式不同,如下图所示:
这里写图片描述

这里的wij表示两个顶点vi和vj边上的权值。无穷大表示一个计算机允许的、大于所有边上权值的值,也就是一个不可能的极限值。下面是具体示例,表示的一个有向网的图和邻接矩阵:

这里写图片描述

这里写图片描述

3、图的存储结构—-邻接矩阵的代码实现

#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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142

输出结果:
这里写图片描述这里写图片描述

4、图的存储结构—-邻接矩阵的优缺点

  • 优点:
    直观、容易理解,可以很容易的判断出任意两个顶点是否有边,最大的优点就是很容易计算出各个顶点的度。
  • 缺点:
    当我么表示完全图的时候,邻接矩阵是最好的表示方法,但是对于稀疏矩阵,由于它边少,但是顶点多,这样就会造成空间的浪费。

5、 图的存储结构—邻接表

邻接表是图的一种链式存储结构。主要是应对于邻接矩阵在顶点多边少的时候,浪费空间的问题。它的方法就是声明两个结构。如下图所示:

这里写图片描述

OK,我们虽然知道了邻接表是这两个结构来表示图的,那么它的怎么表示的了,不急,我们先把它转为c++代码先,然后,再给个示例,你就明白了。

typedef char Vertextype;
//表结点结构
struct ArcNode {
    int adjvex;   //某条边指向的那个顶点的位置(一般是数组的下标)。
    ArcNode * nextarc; //指向下一个表结点
    int weight;   //这个只有网图才需要使用。普通的图可以直接忽略
};

//头结点
struct Vnode
{
    Vertextype data;  //这个是记录每个顶点的信息(现在一般都不需要怎么使用)
    ArcNode * firstarc; //指向第一条依附在该顶点边的信息(表结点)
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

无向图的示例:

这里写图片描述

从图中我们可以知道,顶点是通过一个头结点类型的一维数组来保存的,其中我们每个头结点的firstarc都是指向第一条依附在该顶点边的信息,表结点的adjvex表示的该边的另外一个顶点在顶点数组中的下标,weight域对于普通图是无意义的,可以忽略,nextarc指向的是下一条依附在该顶点的边的信息。
下面再给出一个有向图的例子:
这里写图片描述

通过上述的两个例子,我们应该明白邻接表是如何进行表示图的信息的了。

6、图的存储结构—-邻接表的代码实现

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

typedef string Vertextype;
//表结点结构
struct ArcNode {
    int adjvex;   //某条边指向的那个顶点的位置(一般是数组的下标)。
    ArcNode * nextarc; //指向下一个表结点
    int weight;   //这个只有网图才需要使用。
};

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

//
struct Graph
{
    int kind;  //图的种类(有向图:0,无向图:1,有向网:2,无向网:3)
    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].firstarc=NULL;

    }

    cout << "请输入每条边的起点和终点的编号:" << endl;
    for (i = 0; i < g.edge; i++)
    {
        int a;
        int b;
        cin >> a; //起点
        cin >> 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 (g.node[a - 1].firstarc == NULL) {
            g.node[a - 1].firstarc=next;

        }
        else 
        {
            ArcNode * p;
            p = g.node[a - 1].firstarc;
            while (p->nextarc)//找到该链表的最后一个表结点
            {
                p = p->nextarc;
            }
            p->nextarc = 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].firstarc;
        while (now)
        {
            cout << now->adjvex << " ";
            now = now->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
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

输出结果:
这里写图片描述这里写图片描述

7、图的存储结构—-邻接表的优缺点

  • 优点:
    对于,稀疏图,邻接表比邻接矩阵更节约空间。
  • 缺点:
    不容易判断两个顶点是有关系(边),顶点的出度容易,但是求入度需要遍历整个邻接表。

8、有向图的存储结构—-十字链表

十字链表是有向图的一个专有的链表结构,我们之前也说了,邻接表对于我们计算顶点的入度是一个很麻烦的事情,而十字链表正好可以解决这个问题。十字链表和邻接表一样,他会有两个结构来表示图:其中一个结构用于保存顶点信息,另外一个结构是用于保存每条边的信息,如下图所示:
这里写图片描述

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

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; //指向第一条(出度)在该顶点的表结点
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

下面,我们给出一个有向图的十字链表的例子:
这里写图片描述

其实,这个自己也可以去尝试手画一个十字链表出来,其实都是很简单的

9、有向图的存储结构—-十字链表代码实现

#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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145

这里写图片描述

10、无向图的存储结构—-邻接多重表

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

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

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

下面是一个无向图的邻接多重表的实例(自己也可以尝试去画画,具体的原理都是很简单的):
这里写图片描述

11、无向图的存储结构—-邻接多重表代码实现

#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;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148

输出结果:
这里写图片描述



原文:https://blog.csdn.net/qq_35644234/article/details/57083107

猜你喜欢

转载自blog.csdn.net/m0_37477061/article/details/80848064