一、邻接矩阵有向图的介绍
邻接矩阵有向图是指通过邻接矩阵表示的有向图。
上面的图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 }