阿牧路泽

哪有那么多坚强,无非是死扛罢了
  博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

16、【图】邻接矩阵有向图和邻接表有向图

Posted on 2018-10-14 22:32  阿牧路泽  阅读(2004)  评论(0编辑  收藏  举报

一、邻接矩阵有向图的介绍

邻接矩阵有向图是指通过邻接矩阵表示的有向图。

上面的图G2包含了"A,B,C,D,E,F,G"共7个顶点,而且包含了"<A,B>,<B,C>,<B,E>,<B,F>,<C,E>,<D,C>,<E,B>,<E,D>,<F,G>"共9条边。

上图右边的矩阵是G2在内存中的邻接矩阵示意图。A[i][j]=1表示第i个顶点到第j个顶点是一条边,A[i][j]=0则表示不是一条边;而A[i][j]表示的是第i行第j列的值;例如,A[1,2]=1,表示第1个顶点(即顶点B)到第2个顶点(C)是一条边。

二、邻接矩阵有向图的代码说明

1. 基本定义

 1 #define MAX 100
 2 
 3 class MatrixDG {
 4     private:
 5         char mVexs[MAX];    // 顶点集合
 6         int mVexNum;             // 顶点数
 7         int mEdgNum;             // 边数
 8         int mMatrix[MAX][MAX];   // 邻接矩阵
 9 
10     public:
11         // 创建图(自己输入数据)
12         MatrixDG();
13         // 创建图(用已提供的矩阵)
14         MatrixDG(char vexs[], int vlen, char edges[][2], int elen);
15         ~MatrixDG();
16 
17         // 打印矩阵队列图
18         void print();
19 
20     private:
21         // 读取一个输入字符
22         char readChar();
23         // 返回ch在mMatrix矩阵中的位置
24         int getPosition(char ch);
25 };

(1) ListDG是邻接表对应的结构体。 mVexNum是顶点数,mEdgNum是边数;mVexs则是保存顶点信息的一维数组。
(2) VNode是邻接表顶点对应的结构体。 data是顶点所包含的数据,而firstEdge是该顶点所包含链表的表头指针。
(3) ENode是邻接表顶点所包含的链表的节点对应的结构体。 ivex是该节点所对应的顶点在vexs中的索引,而nextEdge是指向下一个节点的。

2. 创建矩阵

这里介绍提供了两个创建矩阵的方法。一个是用已知数据,另一个则需要用户手动输入数据

2.1 创建图(用已提供的矩阵)

/*
 * 创建图(用已提供的矩阵)
 *
 * 参数说明:
 *     vexs  -- 顶点数组
 *     vlen  -- 顶点数组的长度
 *     edges -- 边数组
 *     elen  -- 边数组的长度
 */
MatrixDG::MatrixDG(char vexs[], int vlen, char edges[][2], int elen)
{
    int i, p1, p2;

    // 初始化"顶点数"和"边数"
    mVexNum = vlen;
    mEdgNum = elen;
    // 初始化"顶点"
    for (i = 0; i < mVexNum; i++)
        mVexs[i] = vexs[i];

    // 初始化"边"
    for (i = 0; i < mEdgNum; i++)
    {
        // 读取边的起始顶点和结束顶点
        p1 = getPosition(edges[i][0]);
        p2 = getPosition(edges[i][1]);

        mMatrix[p1][p2] = 1;
    }
}

该函数的作用是创建一个邻接表有向图。实际上,该方法创建的有向图,就是上面的图G2。该函数的调用方法如下:

 1 char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
 2 char edges[][2] = {
 3     {'A', 'B'}, 
 4     {'B', 'C'}, 
 5     {'B', 'E'}, 
 6     {'B', 'F'}, 
 7     {'C', 'E'}, 
 8     {'D', 'C'}, 
 9     {'E', 'B'}, 
10     {'E', 'D'}, 
11     {'F', 'G'}}; 
12 int vlen = sizeof(vexs)/sizeof(vexs[0]);
13 int elen = sizeof(edges)/sizeof(edges[0]);
14 MatrixDG* pG;
15 
16 pG = new MatrixDG(vexs, vlen, edges, elen);

2.2 创建图(自己输入)

 1 /* 
 2  * 创建图(自己输入数据)
 3  */
 4 MatrixDG::MatrixDG()
 5 {
 6     char c1, c2;
 7     int i, p1, p2;
 8 
 9     // 输入"顶点数"和"边数"
10     cout << "input vertex number: ";
11     cin >> mVexNum;
12     cout << "input edge number: ";
13     cin >> mEdgNum;
14     if ( mVexNum < 1 || mEdgNum < 1 || (mEdgNum > (mVexNum * (mVexNum-1))))
15     {
16         cout << "input error: invalid parameters!" << endl;
17         return ;
18     }
19 
20     // 初始化"顶点"
21     for (i = 0; i < mVexNum; i++)
22     {
23         cout << "vertex(" << i << "): ";
24         mVexs[i] = readChar();
25     }
26 
27     // 初始化"边"
28     for (i = 0; i < mEdgNum; i++)
29     {
30         // 读取边的起始顶点和结束顶点
31         cout << "edge(" << i << "): ";
32         c1 = readChar();
33         c2 = readChar();
34 
35         p1 = getPosition(c1);
36         p2 = getPosition(c2);
37         if (p1==-1 || p2==-1)
38         {
39             cout << "input error: invalid edge!" << endl;
40             return ;
41         }
42 
43         mMatrix[p1][p2] = 1;
44     }
45 }

三、邻接矩阵有向图的C++实现

  1 /**
  2  * C++: 邻接矩阵图
  3  */
  4 
  5 #include <iomanip>
  6 #include <iostream>
  7 #include <vector>
  8 using namespace std;
  9 
 10 #define MAX 100
 11 class MatrixDG {
 12     private:
 13         char mVexs[MAX];    // 顶点集合
 14         int mVexNum;             // 顶点数
 15         int mEdgNum;             // 边数
 16         int mMatrix[MAX][MAX];   // 邻接矩阵
 17 
 18     public:
 19         // 创建图(自己输入数据)
 20         MatrixDG();
 21         // 创建图(用已提供的矩阵)
 22         MatrixDG(char vexs[], int vlen, char edges[][2], int elen);
 23         ~MatrixDG();
 24 
 25         // 打印矩阵队列图
 26         void print();
 27 
 28     private:
 29         // 读取一个输入字符
 30         char readChar();
 31         // 返回ch在mMatrix矩阵中的位置
 32         int getPosition(char ch);
 33 };
 34 
 35 /* 
 36  * 创建图(自己输入数据)
 37  */
 38 MatrixDG::MatrixDG()
 39 {
 40     char c1, c2;
 41     int i, p1, p2;
 42     
 43     // 输入"顶点数"和"边数"
 44     cout << "input vertex number: ";
 45     cin >> mVexNum;
 46     cout << "input edge number: ";
 47     cin >> mEdgNum;
 48     if ( mVexNum < 1 || mEdgNum < 1 || (mEdgNum > (mVexNum * (mVexNum-1))))
 49     {
 50         cout << "input error: invalid parameters!" << endl;
 51         return ;
 52     }
 53     
 54     // 初始化"顶点"
 55     for (i = 0; i < mVexNum; i++)
 56     {
 57         cout << "vertex(" << i << "): ";
 58         mVexs[i] = readChar();
 59     }
 60 
 61     // 初始化"边"
 62     for (i = 0; i < mEdgNum; i++)
 63     {
 64         // 读取边的起始顶点和结束顶点
 65         cout << "edge(" << i << "): ";
 66         c1 = readChar();
 67         c2 = readChar();
 68 
 69         p1 = getPosition(c1);
 70         p2 = getPosition(c2);
 71         if (p1==-1 || p2==-1)
 72         {
 73             cout << "input error: invalid edge!" << endl;
 74             return ;
 75         }
 76 
 77         mMatrix[p1][p2] = 1;
 78     }
 79 }
 80 
 81 /*
 82  * 创建图(用已提供的矩阵)
 83  *
 84  * 参数说明:
 85  *     vexs  -- 顶点数组
 86  *     vlen  -- 顶点数组的长度
 87  *     edges -- 边数组
 88  *     elen  -- 边数组的长度
 89  */
 90 MatrixDG::MatrixDG(char vexs[], int vlen, char edges[][2], int elen)
 91 {
 92     int i, p1, p2;
 93     
 94     // 初始化"顶点数"和"边数"
 95     mVexNum = vlen;
 96     mEdgNum = elen;
 97     // 初始化"顶点"
 98     for (i = 0; i < mVexNum; i++)
 99         mVexs[i] = vexs[i];
100 
101     // 初始化"边"
102     for (i = 0; i < mEdgNum; i++)
103     {
104         // 读取边的起始顶点和结束顶点
105         p1 = getPosition(edges[i][0]);
106         p2 = getPosition(edges[i][1]);
107 
108         mMatrix[p1][p2] = 1;
109     }
110 }
111 
112 /* 
113  * 析构函数
114  */
115 MatrixDG::~MatrixDG() 
116 {
117 }
118 
119 /*
120  * 返回ch在mMatrix矩阵中的位置
121  */
122 int MatrixDG::getPosition(char ch)
123 {
124     int i;
125     for(i=0; i<mVexNum; i++)
126         if(mVexs[i]==ch)
127             return i;
128     return -1;
129 }
130 
131 /*
132  * 读取一个输入字符
133  */
134 char MatrixDG::readChar()
135 {
136     char ch;
137 
138     do {
139         cin >> ch;
140     } while(!((ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z')));
141 
142     return ch;
143 }
144 
145 /*
146  * 打印矩阵队列图
147  */
148 void MatrixDG::print()
149 {
150     int i,j;
151 
152     cout << "Martix Graph:" << endl;
153     for (i = 0; i < mVexNum; i++)
154     {
155         for (j = 0; j < mVexNum; j++)
156             cout << mMatrix[i][j] << " ";
157         cout << endl;
158     }
159 }
160 
161 int main()
162 {
163     char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
164     char edges[][2] = {
165         {'A', 'B'}, 
166         {'B', 'C'}, 
167         {'B', 'E'}, 
168         {'B', 'F'}, 
169         {'C', 'E'}, 
170         {'D', 'C'}, 
171         {'E', 'B'}, 
172         {'E', 'D'}, 
173         {'F', 'G'}}; 
174     int vlen = sizeof(vexs)/sizeof(vexs[0]);
175     int elen = sizeof(edges)/sizeof(edges[0]);
176     MatrixDG* pG;
177 
178     // 自定义"图"(输入矩阵队列)
179     //pG = new MatrixDG();
180     // 采用已有的"图"
181     pG = new MatrixDG(vexs, vlen, edges, elen);
182 
183     pG->print();   // 打印图
184 
185     return 0;
186 }

四、邻接表有向图的介绍

邻接表有向图是指通过邻接表表示的有向图。

上面的图G2包含了"A,B,C,D,E,F,G"共7个顶点,而且包含了"<A,B>,<B,C>,<B,E>,<B,F>,<C,E>,<D,C>,<E,B>,<E,D>,<F,G>"共9条边。

上图右边的矩阵是G2在内存中的邻接表示意图。每一个顶点都包含一条链表,该链表记录了"该顶点所对应的出边的另一个顶点的序号"。例如,第1个顶点(顶点B)包含的链表所包含的节点的数据分别是"2,4,5";而这"2,4,5"分别对应"C,E,F"的序号,"C,E,F"都属于B的出边的另一个顶点。

五、邻接表有向图的代码说明

1. 基本定义

 1 #define MAX 100
 2 // 邻接表
 3 class ListDG
 4 {
 5     private: // 内部类
 6         // 邻接表中表对应的链表的顶点
 7         class ENode
 8         {
 9             public:
10                 int ivex;           // 该边所指向的顶点的位置
11                 ENode *nextEdge;    // 指向下一条弧的指针
12         };
13 
14         // 邻接表中表的顶点
15         class VNode
16         {
17             public:
18                 char data;          // 顶点信息
19                 ENode *firstEdge;   // 指向第一条依附该顶点的弧
20         };
21 
22     private: // 私有成员
23         int mVexNum;             // 图的顶点的数目
24         int mEdgNum;             // 图的边的数目
25         VNode mVexs[MAX];
26 
27     public:
28         // 创建邻接表对应的图(自己输入)
29         ListDG();
30         // 创建邻接表对应的图(用已提供的数据)
31         ListDG(char vexs[], int vlen, char edges[][2], int elen);
32         ~ListDG();
33 
34         // 打印邻接表图
35         void print();
36 
37     private:
38         // 读取一个输入字符
39         char readChar();
40         // 返回ch的位置
41         int getPosition(char ch);
42         // 将node节点链接到list的最后
43         void linkLast(ENode *list, ENode *node);
44 };

(1) ListDG是邻接表对应的结构体。 mVexNum是顶点数,mEdgNum是边数;mVexs则是保存顶点信息的一维数组。
(2) VNode是邻接表顶点对应的结构体。 data是顶点所包含的数据,而firstEdge是该顶点所包含链表的表头指针。
(3) ENode是邻接表顶点所包含的链表的节点对应的结构体。 ivex是该节点所对应的顶点在vexs中的索引,而nextEdge是指向下一个节点的。

2. 创建矩阵

这里介绍提供了两个创建矩阵的方法。一个是用已知数据,另一个则需要用户手动输入数据

2.1 创建图(用已提供的矩阵)

 1 /*
 2  * 创建邻接表对应的图(用已提供的数据)
 3  */
 4 ListDG::ListDG(char vexs[], int vlen, char edges[][2], int elen)
 5 {
 6     char c1, c2;
 7     int i, p1, p2;
 8     ENode *node1, *node2;
 9 
10     // 初始化"顶点数"和"边数"
11     mVexNum = vlen;
12     mEdgNum = elen;
13     // 初始化"邻接表"的顶点
14     for(i=0; i<mVexNum; i++)
15     {
16         mVexs[i].data = vexs[i];
17         mVexs[i].firstEdge = NULL;
18     }
19 
20     // 初始化"邻接表"的边
21     for(i=0; i<mEdgNum; i++)
22     {
23         // 读取边的起始顶点和结束顶点
24         c1 = edges[i][0];
25         c2 = edges[i][1];
26 
27         p1 = getPosition(c1);
28         p2 = getPosition(c2);
29         // 初始化node1
30         node1 = new ENode();
31         node1->ivex = p2;
32         // 将node1链接到"p1所在链表的末尾"
33         if(mVexs[p1].firstEdge == NULL)
34           mVexs[p1].firstEdge = node1;
35         else
36             linkLast(mVexs[p1].firstEdge, node1);
37     }
38 }

 该函数的作用是创建一个邻接表有向图。实际上,该方法创建的有向图,就是上面的图G2。该函数的调用方法如下:

 1 char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
 2 char edges[][2] = {
 3     {'A', 'B'}, 
 4     {'B', 'C'}, 
 5     {'B', 'E'}, 
 6     {'B', 'F'}, 
 7     {'C', 'E'}, 
 8     {'D', 'C'}, 
 9     {'E', 'B'}, 
10     {'E', 'D'}, 
11     {'F', 'G'}}; 
12 int vlen = sizeof(vexs)/sizeof(vexs[0]);
13 int elen = sizeof(edges)/sizeof(edges[0]);
14 ListDG* pG;
15 
16 pG = new ListDG(vexs, vlen, edges, elen);

 2.2 创建图(自己输入)

 1 /*
 2  * 创建邻接表对应的图(自己输入)
 3  */
 4 ListDG::ListDG()
 5 {
 6     char c1, c2;
 7     int v, e;
 8     int i, p1, p2;
 9     ENode *node1, *node2;
10 
11     // 输入"顶点数"和"边数"
12     cout << "input vertex number: ";
13     cin >> mVexNum;
14     cout << "input edge number: ";
15     cin >> mEdgNum;
16     if ( mVexNum < 1 || mEdgNum < 1 || (mEdgNum > (mVexNum * (mVexNum-1))))
17     {
18         cout << "input error: invalid parameters!" << endl;
19         return ;
20     }
21 
22     // 初始化"邻接表"的顶点
23     for(i=0; i<mVexNum; i++)
24     {
25         cout << "vertex(" << i << "): ";
26         mVexs[i].data = readChar();
27         mVexs[i].firstEdge = NULL;
28     }
29 
30     // 初始化"邻接表"的边
31     for(i=0; i<mEdgNum; i++)
32     {
33         // 读取边的起始顶点和结束顶点
34         cout << "edge(" << i << "): ";
35         c1 = readChar();
36         c2 = readChar();
37 
38         p1 = getPosition(c1);
39         p2 = getPosition(c2);
40         // 初始化node1
41         node1 = new ENode();
42         node1->ivex = p2;
43         // 将node1链接到"p1所在链表的末尾"
44         if(mVexs[p1].firstEdge == NULL)
45           mVexs[p1].firstEdge = node1;
46         else
47             linkLast(mVexs[p1].firstEdge, node1);
48     }
49 }

六、邻接表有向图的C++实现

  1 /**
  2  * C++: 邻接表图
  3  */
  4 
  5 #include <iomanip>
  6 #include <iostream>
  7 #include <vector>
  8 using namespace std;
  9 
 10 #define MAX 100
 11 // 邻接表
 12 class ListDG
 13 {
 14     private: // 内部类
 15         // 邻接表中表对应的链表的顶点
 16         class ENode
 17         {
 18             public:
 19                 int ivex;           // 该边所指向的顶点的位置
 20                 ENode *nextEdge;    // 指向下一条弧的指针
 21         };
 22 
 23         // 邻接表中表的顶点
 24         class VNode
 25         {
 26             public:
 27                 char data;          // 顶点信息
 28                 ENode *firstEdge;   // 指向第一条依附该顶点的弧
 29         };
 30 
 31     private: // 私有成员
 32         int mVexNum;             // 图的顶点的数目
 33         int mEdgNum;             // 图的边的数目
 34         VNode mVexs[MAX];
 35 
 36     public:
 37         // 创建邻接表对应的图(自己输入)
 38         ListDG();
 39         // 创建邻接表对应的图(用已提供的数据)
 40         ListDG(char vexs[], int vlen, char edges[][2], int elen);
 41         ~ListDG();
 42 
 43         // 打印邻接表图
 44         void print();
 45 
 46     private:
 47         // 读取一个输入字符
 48         char readChar();
 49         // 返回ch的位置
 50         int getPosition(char ch);
 51         // 将node节点链接到list的最后
 52         void linkLast(ENode *list, ENode *node);
 53 };
 54 
 55 /*
 56  * 创建邻接表对应的图(自己输入)
 57  */
 58 ListDG::ListDG()
 59 {
 60     char c1, c2;
 61     int v, e;
 62     int i, p1, p2;
 63     ENode *node1, *node2;
 64 
 65     // 输入"顶点数"和"边数"
 66     cout << "input vertex number: ";
 67     cin >> mVexNum;
 68     cout << "input edge number: ";
 69     cin >> mEdgNum;
 70     if ( mVexNum < 1 || mEdgNum < 1 || (mEdgNum > (mVexNum * (mVexNum-1))))
 71     {
 72         cout << "input error: invalid parameters!" << endl;
 73         return ;
 74     }
 75  
 76     // 初始化"邻接表"的顶点
 77     for(i=0; i<mVexNum; i++)
 78     {
 79         cout << "vertex(" << i << "): ";
 80         mVexs[i].data = readChar();
 81         mVexs[i].firstEdge = NULL;
 82     }
 83 
 84     // 初始化"邻接表"的边
 85     for(i=0; i<mEdgNum; i++)
 86     {
 87         // 读取边的起始顶点和结束顶点
 88         cout << "edge(" << i << "): ";
 89         c1 = readChar();
 90         c2 = readChar();
 91 
 92         p1 = getPosition(c1);
 93         p2 = getPosition(c2);
 94         // 初始化node1
 95         node1 = new ENode();
 96         node1->ivex = p2;
 97         // 将node1链接到"p1所在链表的末尾"
 98         if(mVexs[p1].firstEdge == NULL)
 99           mVexs[p1].firstEdge = node1;
100         else
101             linkLast(mVexs[p1].firstEdge, node1);
102     }
103 }
104 
105 /*
106  * 创建邻接表对应的图(用已提供的数据)
107  */
108 ListDG::ListDG(char vexs[], int vlen, char edges[][2], int elen)
109 {
110     char c1, c2;
111     int i, p1, p2;
112     ENode *node1, *node2;
113 
114     // 初始化"顶点数"和"边数"
115     mVexNum = vlen;
116     mEdgNum = elen;
117     // 初始化"邻接表"的顶点
118     for(i=0; i<mVexNum; i++)
119     {
120         mVexs[i].data = vexs[i];
121         mVexs[i].firstEdge = NULL;
122     }
123 
124     // 初始化"邻接表"的边
125     for(i=0; i<mEdgNum; i++)
126     {
127         // 读取边的起始顶点和结束顶点
128         c1 = edges[i][0];
129         c2 = edges[i][1];
130 
131         p1 = getPosition(c1);
132         p2 = getPosition(c2);
133         // 初始化node1
134         node1 = new ENode();
135         node1->ivex = p2;
136         // 将node1链接到"p1所在链表的末尾"
137         if(mVexs[p1].firstEdge == NULL)
138           mVexs[p1].firstEdge = node1;
139         else
140             linkLast(mVexs[p1].firstEdge, node1);
141     }
142 }
143 
144 /* 
145  * 析构函数
146  */
147 ListDG::~ListDG() 
148 {
149 }
150 
151 /*
152  * 将node节点链接到list的最后
153  */
154 void ListDG::linkLast(ENode *list, ENode *node)
155 {
156     ENode *p = list;
157 
158     while(p->nextEdge)
159         p = p->nextEdge;
160     p->nextEdge = node;
161 }
162 
163 
164 /*
165  * 返回ch的位置
166  */
167 int ListDG::getPosition(char ch)
168 {
169     int i;
170     for(i=0; i<mVexNum; i++)
171         if(mVexs[i].data==ch)
172             return i;
173     return -1;
174 }
175 
176 /*
177  * 读取一个输入字符
178  */
179 char ListDG::readChar()
180 {
181     char ch;
182 
183     do {
184         cin >> ch;
185     } while(!((ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z')));
186 
187     return ch;
188 }
189 
190 /*
191  * 打印邻接表图
192  */
193 void ListDG::print()
194 {
195     int i,j;
196     ENode *node;
197 
198     cout << "List Graph:" << endl;
199     for (i = 0; i < mVexNum; i++)
200     {
201         cout << i << "(" << mVexs[i].data << "): ";
202         node = mVexs[i].firstEdge;
203         while (node != NULL)
204         {
205             cout << node->ivex << "(" << mVexs[node->ivex].data << ") ";
206             node = node->nextEdge;
207         }
208         cout << endl;
209     }
210 }
211 
212 int main()
213 {
214     char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
215     char edges[][2] = {
216         {'A', 'B'}, 
217         {'B', 'C'}, 
218         {'B', 'E'}, 
219         {'B', 'F'}, 
220         {'C', 'E'}, 
221         {'D', 'C'}, 
222         {'E', 'B'}, 
223         {'E', 'D'}, 
224         {'F', 'G'}}; 
225     int vlen = sizeof(vexs)/sizeof(vexs[0]);
226     int elen = sizeof(edges)/sizeof(edges[0]);
227     ListDG* pG;
228 
229     // 自定义"图"(输入矩阵队列)
230     //pG = new ListDG();
231     // 采用已有的"图"
232     pG = new ListDG(vexs, vlen, edges, elen);
233 
234     pG->print();   // 打印图
235 
236     return 0;
237 }