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