一、邻接矩阵无向图的介绍
邻接矩阵无向图是指通过邻接矩阵表示的无向图。
上面的图G1包含了"A,B,C,D,E,F,G"共7个顶点,而且包含了"(A,C),(A,D),(A,F),(B,C),(C,D),(E,G),(F,G)"共7条边。由于这是无向图,所以边(A,C)和边(C,A)是同一条边;这里列举边时,是按照字母先后顺序列举的。
上图右边的矩阵是G1在内存中的邻接矩阵示意图。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 class MatrixUDG { 2 private: 3 char mVexs[MAX]; // 顶点集合 4 int mVexNum; // 顶点数 5 int mEdgNum; // 边数 6 int mMatrix[MAX][MAX]; // 邻接矩阵 7 8 public: 9 // 创建图(自己输入数据) 10 MatrixUDG(); 11 // 创建图(用已提供的矩阵) 12 MatrixUDG(char vexs[], int vlen, char edges[][2], int elen); 13 ~MatrixUDG(); 14 15 // 打印矩阵队列图 16 void print(); 17 18 private: 19 // 读取一个输入字符 20 char readChar(); 21 // 返回ch在mMatrix矩阵中的位置 22 int getPosition(char ch); 23 };
MatrixUDG是邻接矩阵对应的结构体。
mVexs用于保存顶点,mVexNum是顶点数,mEdgNum是边数;mMatrix则是用于保存矩阵信息的二维数组。例如,mMatrix[i][j]=1,则表示"顶点i(即mVexs[i])"和"顶点j(即mVexs[j])"是邻接点;mMatrix[i][j]=0,则表示它们不是邻接点。
2. 创建矩阵
这里介绍提供了两个创建矩阵的方法。一个是用已知数据,另一个则需要用户手动输入数据。
2.1 创建图(用已提供的矩阵)
1 /* 2 * 创建图(用已提供的矩阵) 3 * 4 * 参数说明: 5 * vexs -- 顶点数组 6 * vlen -- 顶点数组的长度 7 * edges -- 边数组 8 * elen -- 边数组的长度 9 */ 10 MatrixUDG::MatrixUDG(char vexs[], int vlen, char edges[][2], int elen) 11 { 12 int i, p1, p2; 13 14 // 初始化"顶点数"和"边数" 15 mVexNum = vlen; 16 mEdgNum = elen; 17 // 初始化"顶点" 18 for (i = 0; i < mVexNum; i++) 19 mVexs[i] = vexs[i]; 20 21 // 初始化"边" 22 for (i = 0; i < mEdgNum; i++) 23 { 24 // 读取边的起始顶点和结束顶点 25 p1 = getPosition(edges[i][0]); 26 p2 = getPosition(edges[i][1]); 27 28 mMatrix[p1][p2] = 1; 29 mMatrix[p2][p1] = 1; 30 } 31 }
该函数的作用是利用已知数据来创建一个邻接矩阵无向图。 实际上,在本文的测试程序源码中,该方法创建的无向图就是上面图G1。具体的调用代码如下:
1 char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; 2 char edges[][2] = { 3 {'A', 'C'}, 4 {'A', 'D'}, 5 {'A', 'F'}, 6 {'B', 'C'}, 7 {'C', 'D'}, 8 {'E', 'G'}, 9 {'F', 'G'}}; 10 int vlen = sizeof(vexs)/sizeof(vexs[0]); 11 int elen = sizeof(edges)/sizeof(edges[0]); 12 MatrixUDG* pG; 13 14 pG = new MatrixUDG(vexs, vlen, edges, elen);
2.2 创建图(自己输入)
1 /* 2 * 创建图(自己输入数据) 3 */ 4 MatrixUDG::MatrixUDG() 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 mMatrix[p2][p1] = 1; 45 } 46 }
三、邻接矩阵无向图的C++实现
1 /** 2 * C++: 邻接矩阵表示的"无向图(List Undirected Graph)" 3 */ 4 5 #include <iomanip> 6 #include <iostream> 7 #include <vector> 8 using namespace std; 9 10 #define MAX 100 11 class MatrixUDG { 12 private: 13 char mVexs[MAX]; // 顶点集合 14 int mVexNum; // 顶点数 15 int mEdgNum; // 边数 16 int mMatrix[MAX][MAX]; // 邻接矩阵 17 18 public: 19 // 创建图(自己输入数据) 20 MatrixUDG(); 21 // 创建图(用已提供的矩阵) 22 MatrixUDG(char vexs[], int vlen, char edges[][2], int elen); 23 ~MatrixUDG(); 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 MatrixUDG::MatrixUDG() 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 mMatrix[p2][p1] = 1; 79 } 80 } 81 82 /* 83 * 创建图(用已提供的矩阵) 84 * 85 * 参数说明: 86 * vexs -- 顶点数组 87 * vlen -- 顶点数组的长度 88 * edges -- 边数组 89 * elen -- 边数组的长度 90 */ 91 MatrixUDG::MatrixUDG(char vexs[], int vlen, char edges[][2], int elen) 92 { 93 int i, p1, p2; 94 95 // 初始化"顶点数"和"边数" 96 mVexNum = vlen; 97 mEdgNum = elen; 98 // 初始化"顶点" 99 for (i = 0; i < mVexNum; i++) 100 mVexs[i] = vexs[i]; 101 102 // 初始化"边" 103 for (i = 0; i < mEdgNum; i++) 104 { 105 // 读取边的起始顶点和结束顶点 106 p1 = getPosition(edges[i][0]); 107 p2 = getPosition(edges[i][1]); 108 109 mMatrix[p1][p2] = 1; 110 mMatrix[p2][p1] = 1; 111 } 112 } 113 114 /* 115 * 析构函数 116 */ 117 MatrixUDG::~MatrixUDG() 118 { 119 } 120 121 /* 122 * 返回ch在mMatrix矩阵中的位置 123 */ 124 int MatrixUDG::getPosition(char ch) 125 { 126 int i; 127 for(i=0; i<mVexNum; i++) 128 if(mVexs[i]==ch) 129 return i; 130 return -1; 131 } 132 133 /* 134 * 读取一个输入字符 135 */ 136 char MatrixUDG::readChar() 137 { 138 char ch; 139 140 do { 141 cin >> ch; 142 } while(!((ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z'))); 143 144 return ch; 145 } 146 147 /* 148 * 打印矩阵队列图 149 */ 150 void MatrixUDG::print() 151 { 152 int i,j; 153 154 cout << "Martix Graph:" << endl; 155 for (i = 0; i < mVexNum; i++) 156 { 157 for (j = 0; j < mVexNum; j++) 158 cout << mMatrix[i][j] << " "; 159 cout << endl; 160 } 161 } 162 163 int main() 164 { 165 char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; 166 char edges[][2] = { 167 {'A', 'C'}, 168 {'A', 'D'}, 169 {'A', 'F'}, 170 {'B', 'C'}, 171 {'C', 'D'}, 172 {'E', 'G'}, 173 {'F', 'G'}}; 174 int vlen = sizeof(vexs)/sizeof(vexs[0]); 175 int elen = sizeof(edges)/sizeof(edges[0]); 176 MatrixUDG* pG; 177 178 // 自定义"图"(输入矩阵队列) 179 //pG = new MatrixUDG(); 180 // 采用已有的"图" 181 pG = new MatrixUDG(vexs, vlen, edges, elen); 182 183 pG->print(); // 打印图 184 185 return 0; 186 }
四、邻接表无向图介绍
邻接表无向图是指通过邻接表表示的无向图。
上面的图G1包含了"A,B,C,D,E,F,G"共7个顶点,而且包含了"(A,C),(A,D),(A,F),(B,C),(C,D),(E,G),(F,G)"共7条边。
上图右边的矩阵是G1在内存中的邻接表示意图。每一个顶点都包含一条链表,该链表记录了"该顶点的邻接点的序号"。例如,第2个顶点(顶点C)包含的链表所包含的节点的数据分别是"0,1,3";而这"0,1,3"分别对应"A,B,D"的序号,"A,B,D"都是C的邻接点。就是通过这种方式记录图的信息的。
五、邻接表无向图的代码说明
1. 基本定义
1 #define MAX 100 2 // 邻接表 3 class ListUDG 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 ListUDG(); 30 // 创建邻接表对应的图(用已提供的数据) 31 ListUDG(char vexs[], int vlen, char edges[][2], int elen); 32 ~ListUDG(); 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) ListUDG是邻接表对应的结构体。
mVexNum是顶点数,mEdgNum是边数;mVexs则是保存顶点信息的一维数组。
(2) VNode是邻接表顶点对应的结构体。
data是顶点所包含的数据,而firstEdge是该顶点所包含链表的表头指针。
(3) ENode是邻接表顶点所包含的链表的节点对应的结构体。
ivex是该节点所对应的顶点在vexs中的索引,而nextEdge是指向下一个节点的。
2. 创建矩阵
这里介绍提供了两个创建矩阵的方法。一个是用已知数据,另一个则需要用户手动输入数据。
2.1 创建图(用已提供的矩阵)
/* * 创建邻接表对应的图(用已提供的数据) */ ListUDG::ListUDG(char vexs[], int vlen, char edges[][2], int elen) { char c1, c2; int i, p1, p2; ENode *node1, *node2; // 初始化"顶点数"和"边数" mVexNum = vlen; mEdgNum = elen; // 初始化"邻接表"的顶点 for(i=0; i<mVexNum; i++) { mVexs[i].data = vexs[i]; mVexs[i].firstEdge = NULL; } // 初始化"邻接表"的边 for(i=0; i<mEdgNum; i++) { // 读取边的起始顶点和结束顶点 c1 = edges[i][0]; c2 = edges[i][1]; p1 = getPosition(c1); p2 = getPosition(c2); // 初始化node1 node1 = new ENode(); node1->ivex = p2; // 将node1链接到"p1所在链表的末尾" if(mVexs[p1].firstEdge == NULL) mVexs[p1].firstEdge = node1; else linkLast(mVexs[p1].firstEdge, node1); // 初始化node2 node2 = new ENode(); node2->ivex = p1; // 将node2链接到"p2所在链表的末尾" if(mVexs[p2].firstEdge == NULL) mVexs[p2].firstEdge = node2; else linkLast(mVexs[p2].firstEdge, node2); } }
该函数的作用是创建一个邻接表无向图。实际上,该方法创建的无向图,就是上面图G1。调用代码如下:
1 char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; 2 char edges[][2] = { 3 {'A', 'C'}, 4 {'A', 'D'}, 5 {'A', 'F'}, 6 {'B', 'C'}, 7 {'C', 'D'}, 8 {'E', 'G'}, 9 {'F', 'G'}}; 10 int vlen = sizeof(vexs)/sizeof(vexs[0]); 11 int elen = sizeof(edges)/sizeof(edges[0]); 12 ListUDG* pG; 13 14 pG = new ListUDG(vexs, vlen, edges, elen);
2.2 创建图(自己输入)
1 /* 2 * 创建邻接表对应的图(自己输入) 3 */ 4 ListUDG::ListUDG() 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 // 初始化node2 49 node2 = new ENode(); 50 node2->ivex = p1; 51 // 将node2链接到"p2所在链表的末尾" 52 if(mVexs[p2].firstEdge == NULL) 53 mVexs[p2].firstEdge = node2; 54 else 55 linkLast(mVexs[p2].firstEdge, node2); 56 } 57 }
该函数是读取用户的输入,将输入的数据转换成对应的无向图。
六、邻接表无向图的C++实现