图
定义: 图是由有穷的定点集合和有穷的顶点之间的关系集合组成的.
树是一种特殊的图,链表是一种特殊的树
无向边:顶点x和顶点y之间没有方向,(x,y)和(y,x)意义相同表示xy之间有联系
无向图:图中任意两个顶点都是无向边.
有向边:顶点xy之间都是有方向的,<x,y>表示x连接到y,从顶点x可以到顶点y,不可逆. x是尾部,y是头部. <y,x>
有向图:图中任意两个顶点之间都是有方向的
顶点邻接:两个顶点互相可以抵达.无向图中两个顶点有边则两个顶点互为邻接.有向图中顶点X可以抵达顶点y则顶点x邻接到顶点y
度: 顶点v的度等于和顶点v相关联的边的数目.记为TD(v)
入度: 以v为头的边的数目.记为ID(v)
出度: 以v为尾的边的数目.记为OD(v)
权:表示图中顶点间的距离
图的存储:
用一维数组存储顶点:描述相关顶点的数据
用二维数组存储边:描述顶点间的关系
1. 邻接矩阵法:]
A = (V , E)是一个有n个顶点的图,则图的邻接矩阵表示为: Edeg[n][n]
用一个二维数组表示顶点间的关系,二维数组 Edge[i][j] 元素的值表示边的值(权值(距离)).
二维数组 Edge[i][j] 的下标表示顶点的编号,有值表示顶点 i 连接到顶点 j的权值. 空值表示没有连接
/* * Graph: 图类 * 成员变量: * * 成员函数: * V getVertex(int i) 获取位置为i的节点 * bool getVertex(int i, V& value) 判断位置为i的节点和value节点是否相等 * bool setVertex(int i, const V& value) 设置节点i的为value * SharedPointer< Array<int> > getAdjacent(int i) 获取节点的i的所有邻接节点 * E getEdeg(int i, int j) 获取节点i和节点j之间的边 * bool getEdge(int i, int j, E& value) 判断节点i和节点j之间的边是否和value相等 * bool setEdge(int i, int j, const E& value) 设置节点i和节点j之间的边的权重 * bool removeEdge(int i, int j) 去掉节点i和节点j之间的权重 * int vCount() 计算图中所有的节点 * int eCount() 计算图中所有的边 * int OD(int i) 计算节点i的出度 * int ID(int i) 计算节点i的入度 * int TD(int i) 计算节点i的度 */ #ifndef GRAPH_H #define GRAPH_H #include "TopClass.h" #include "SharedPointer.h" #include "Array.h" namespace DSL { template <typename V, typename E> class Graph : public TopClass { public: virtual V getVertex(int i) = 0; virtual bool getVertex(int i, V& value) = 0; virtual bool setVertex(int i, const V& value) = 0; virtual SharedPointer< Array<int> > getAdjacent(int i) = 0; virtual E getEdeg(int i, int j) = 0; virtual bool getEdge(int i, int j, E& value) = 0; virtual bool setEdge(int i, int j, const E& value) = 0; virtual bool removeEdge(int i, int j) = 0; virtual int vCount() = 0; virtual int eCount() = 0; virtual int OD(int i) =0; virtual int ID(int i) = 0; virtual int TD(int i) = 0; }; } #endif
1 /* 2 * MartixGraph: 邻接矩阵 3 * 4 * 模板参数: 5 N: 顶点的数目 6 * V: 顶点的数据元素类型 7 * E: 边的数据元素类型 8 * 9 * 成员变量: 10 * V* m_vertexes[N]; 数组保存顶点数据元素,指针数组高效 11 * V* m_edges[N][N]; 数组值为边的权值,第一个N可看作顶点位置 12 * int m_ecount; 边总数 13 * 成员函数: 14 * V getVertex(int i) 获取位置为i的节点 15 * bool getVertex(int i, V& value) 判断位置为i的节点和value节点是否相等 16 * bool setVertex(int i, const V& value) 设置节点i的为value 17 * SharedPointer< Array<int> > getAdjacent(int i) 获取节点的i的所有邻接节点 18 * E getEdeg(int i, int j) 获取节点i和节点j之间的边 19 * bool getEdge(int i, int j, E& value) 判断节点i和节点j之间的边是否和value相等 20 * bool setEdge(int i, int j, const E& value) 设置节点i和节点j之间的边的权重 21 * bool removeEdge(int i, int j) 去掉节点i和节点j之间的权重 22 * int vCount() 计算图中所有的节点 23 * int eCount() 计算图中所有的边 24 * int OD(int i) 计算节点i的出度 25 * int ID(int i) 计算节点i的入度 26 * int TD(int i) 计算节点i的度 27 */ 28 29 #ifndef MARTIXGRAPH_H 30 #define MARTIXGRAPH_H 31 32 #include "Graph.h" 33 #include "Exception.h" 34 #include "DynamicArray.h" 35 36 namespace DSL 37 { 38 template <int N, typename V, typename E> 39 class MartixGraph : public Graph<V, E> 40 { 41 protected: 42 V* m_vertexes[N]; 43 E* m_edges[N][N]; 44 int m_ecount; 45 public: 46 MartixGraph() 47 { 48 for(int i = 0; i < vCount(); i++) 49 { 50 m_vertexes[i] = NULL; 51 for(int j = 0; j < vCount(); j++) 52 m_edges[i][j] = NULL; 53 } 54 m_ecount = 0; 55 } 56 57 58 V getVertex(int i) 59 { 60 V value; 61 if(!getVertex(i, value)) 62 THROW_EXCEPTION(InvalidParameterException, "error: invalid params i"); 63 return value; 64 } 65 66 bool getVertex(int i, V& value) 67 { 68 if((0 <= i) && (i < vCount())) 69 { 70 if(m_vertexes[i] != NULL) 71 { 72 value = *(m_vertexes[i]); 73 } 74 else 75 { 76 THROW_EXCEPTION(InvalidOperationException, "error: No element in this vertex!"); 77 } 78 return ture; 79 } 80 return false; 81 } 82 83 bool setVertex(int i, const V& value) 84 { 85 if((0 <= i) && (i < vCount())) 86 { 87 V* temp = m_vertexes[i]; 88 if(temp == NULL) 89 temp = new V(); 90 if(temp == NULL) 91 { 92 THROW_EXCEPTION(NotEnoughMemoryException, "error: no enough memory to malloc new vertex!"); 93 } 94 else 95 { 96 *temp = value; 97 m_vertexes[i] = temp; 98 } 99 return ture; 100 } 101 return false; 102 } 103 104 SharedPointer< Array<int> > getAdjacent(int i) 105 { 106 DynamicArray<int>* vertex_array = NULL; 107 if((0 <= i) && (i < vCount())) 108 { 109 int count = 0; 110 for(int j = 0; j < vCount(); j++) 111 { 112 if(m_edges[i][j] != NULL) 113 count++; 114 } 115 vertex_array = new DynamicArray<int>(count); 116 if(vertex_array == NULL) 117 { 118 THROW_EXCEPTION(NotEnoughMemoryException, "error: no enough memory to malloc new vertex!"); 119 } 120 else 121 { 122 for(int j = 0, m = 0; j < vCount(); j++) 123 { 124 if(m_edges[i][j] != NULL) 125 vertex_array->set(m++, j); 126 } 127 } 128 } 129 else 130 { 131 THROW_EXCEPTION(InvalidParameterException, "error: invalid params"); 132 } 133 return vertex_array; 134 } 135 136 E getEdeg(int i, int j) 137 { 138 E value; 139 if(!getEdge(i, j, value)) 140 THROW_EXCEPTION(InvalidParameterException, "error: invalid params"); 141 return value; 142 } 143 144 bool getEdge(int i, int j, E& value) 145 { 146 if((0 <= i) && (i < vCount()) && (0 <= j) && (j < vCount())) 147 { 148 if(m_edges[i][j] != NULL) 149 value = *(m_edges[i][j]); 150 else 151 THROW_EXCEPTION(InvalidOperationException, "error: No element in this vertex!"); 152 return ture; 153 } 154 else 155 { 156 return false; 157 } 158 } 159 160 bool setEdge(int i, int j, const E& value) 161 { 162 if((0 <= i) && (i < vCount()) && (0 <= j) && (j < vCount())) 163 { 164 E* temp = m_edges[i][j]; 165 if(temp == NULL) 166 { 167 temp = new E(); 168 if(temp) 169 { 170 *temp = value; 171 m_edges[i][j] = temp; 172 m_ecount++; 173 } 174 else 175 { 176 THROW_EXCEPTION(NotEnoughMemoryException, "error: no enough memory to malloc edge"); 177 } 178 } 179 else 180 { 181 *temp = value; 182 } 183 return ture; 184 } 185 else 186 { 187 return false; 188 } 189 } 190 191 bool removeEdge(int i, int j) 192 { 193 if((0 <= i) && (i < vCount()) && (0 <= j) && (j < vCount())) 194 { 195 E* toDel = m_edges[i][j]; 196 m_edges[i][j] = NULL; 197 if(toDel != NULL) 198 { 199 m_ecount--; 200 delete toDel; 201 } 202 return ture; 203 } 204 else 205 { 206 return false; 207 } 208 } 209 210 int vCount() 211 { 212 return N; 213 } 214 215 int eCount() 216 { 217 return m_ecount; 218 } 219 220 int OD(int i) 221 { 222 int count = 0; 223 if((0 <= i) && (i < vCount())) 224 { 225 for(int j = 0; j < vCount(); j++) 226 { 227 if(m_edges[i][j] != NULL) 228 count++; 229 } 230 } 231 else 232 { 233 THROW_EXCEPTION(InvalidParameterException, "error: inalid parameter"); 234 } 235 return count; 236 } 237 238 int ID(int i) 239 { 240 int count = 0; 241 if((0 < i) && (i < vCount())) 242 { 243 for(int j = 0; j < vCount(); j++) 244 { 245 if(m_edges[j][i] != NULL) 246 count++; 247 } 248 } 249 else 250 { 251 THROW_EXCEPTION(InvalidParameterException, "error: inalid parameter"); 252 } 253 return count; 254 } 255 256 int TD(int i) 257 { 258 return (ID(i) + OD(i)); 259 } 260 261 ~MartixGraph() 262 { 263 for(int i = 0; i < eCount(); i++) 264 { 265 for(int j = 0; j < eCount(); j++) 266 delete m_edges[i][j]; 267 delete m_vertexes[i]; 268 } 269 m_ecount = 0; 270 } 271 }; 272 } 273 274 #endif
2.邻接链表法
所有顶点按照编号存储于同一链表中
每一个顶点对应的节点又是一个链表的头节点,链表的每个节点存储指向其他节点边的信息,一条边的信息包含:起点,终点,权重
/* * ListGraph: 邻接链表 * * 模板参数: * V: 顶点的数据元素类型 * E: 边的数据元素类型 * * 成员变量: * struct Edges{ * int e_start; 边的起始点 * int e_end; 边的终点 * E data;} 边的权值 * * struct Vertex{ * V* data; 顶点的数据元素 * LinkList<Edges> edges;} 保存所有邻接到这个顶点边的信息 * LinkList<Vertex*> m_list 邻接链表 * int m_ecount; 边总数 * 成员函数: * int addVertex() 在链表尾部插入新的顶点,返回顶点编号 * int addVertex(const& value) 增加新的顶点并添加顶点元素 * bool removeVertex() 删除链表尾部的顶点,删除相关边 * V getVertex(int i) 获取位置为i的节点 * bool getVertex(int i, V& value) 判断位置为i的节点和value节点是否相等 * bool setVertex(int i, const V& value) 设置节点i的为value * SharedPointer< Array<int> > getAdjacent(int i) 获取节点的i的所有邻接节点 * E getEdge(int i, int j) 获取节点i和节点j之间的边 * bool getEdge(int i, int j, E& value) 判断节点i和节点j之间的边是否和value相等 * bool setEdge(int i, int j, const E& value) 设置节点i和节点j之间的边的权重 * bool removeEdge(int i, int j) 去掉节点i和节点j之间的权重 * int vCount() 计算图中所有的节点 * int eCount() 计算图中所有的边 * int OD(int i) 计算节点i的出度 * int ID(int i) 计算节点i的入度 * int TD(int i) 计算节点i的度 */ #ifndef LISTGRAPH_H #define LISTGRAPH_H #include "Graph.h" #include "LinkList.h" #include "Exception.h" #include "DynamicArray.h" namespace DSL { template<typename E> struct Edge : public TopClass { int e_sta; int e_end; E data; Edge(int i = -1, int j = -1) { e_sta = i; e_end = j; } Edge(int i, int j, const E& value) { e_sta = i; e_end = j; data = value; } bool operator == (const Edge<E>& obj) { return ((e_sta == obj.e_sta) && (e_end == obj.e_end)); } bool operator != (const Edge<E>& obj) { return !(obj == *this); } }; template <typename V, typename E> class ListGraph : public TopClass { protected: struct Vertex : public TopClass { V* data; LinkList<Edge<E>> edge; Vertex() { data = NULL; } }; LinkList<Vertex*> m_list; public: ListGraph(unsigned int pos = 0) { for(int i = 0; i < pos; i++) addVertex(); } int addVertex() { int pos = -1; Vertex* temp_v = new Vertex(); if(temp_v != NULL) { m_list.insert(temp_v); pos = m_list.length() - 1; } else { THROW_EXCEPTION(NotEnoughMemoryException, "error: no enough memory to create Vertex"); } return pos; } int addVertex(const V& value) { int pos = addVertex(); if(pos >= 0) { setVertex(pos, value); } else { THROW_EXCEPTION(IdexOutOfBoundException, "error: index out of bound"); } } bool removeVertex() { int index = m_list.length() - 1; if(index >= 0) { Vertex* v = m_list.get(index); if(m_list.remove(index)) { for(int i = (m_list.move(0), 0); !m_list.end(); i++, m_list.next()) { int pos = m_list.current()->edge.find(Edge<E>(i, index)); // 删除与这个顶点相关的边 if(pos >= 0) m_list.current()->edge.remove(pos); } } delete v->data; delete v; return ture; } else { THROW_EXCEPTION(InvalidOperationException, "error: no vertex in this graph"); } } V getVertex(int i) { V ret; if(!getVertex(i, ret)) THROW_EXCEPTION(IdexOutOfBoundException, "error: index out of bound"); return ret; } bool getVertex(int i, V& value) { bool ret = ((0 <= i) && (i < vCount())); if(ret) { Vertex* temp_v = m_list.get(i); if(temp_v->data != NULL) { value = *(temp_v->data); } else { THROW_EXCEPTION(InvalidOperationException, "error: no value assigned to this vertex"); } } return ret; } bool setVertex(int i, const V& value) { bool ret = ((0 <= i) && (i < vCount())); if(ret) { Vertex* temp_v = m_list.get(i); V* temp_d = temp_v->data; if(temp_d == NULL) { temp_d = new V(); if(temp_d) { *temp_d = value; temp_v->data = temp_d; ret = ture; } else { THROW_EXCEPTION(NotEnoughMemoryException, "error: no enough memory to create data"); } } } else { THROW_EXCEPTION(IdexOutOfBoundException, "error: index out of bound"); } return ret; } SharedPointer< Array<int> > getAdjacent(int i) { DynamicArray<int>* ad_array = NULL; if((0 <= i) && (i < vCount())) { Vertex* temp_v = m_list.get(i); ad_array = new DynamicArray<int>(temp_v->edge.length()); if(ad_array != NULL) { for(int i = (temp_v->edge.move(0), 0); !temp_v->edge.end(); i++, temp_v->edge.next()) { ad_array->set(i, temp_v->edge.current().e_end); } } else { THROW_EXCEPTION(NotEnoughMemoryException, "error: no enough memory to create data"); } } else { THROW_EXCEPTION(IdexOutOfBoundException, "error: index out of bound"); } return ad_array; } E getEdge(int i, int j) { E ret; if(!getEdge(i, j, ret)) THROW_EXCEPTION(InvalidParameterException, "error: Invalid Parameter"); return ret; } bool getEdge(int i, int j, E& value) { bool ret = ((0 <= i) && (i < vCount()) && (0 <= j) && (j < vCount())); if(ret) { Vertex* temp_v = m_list.get(i); int pos = temp_v->edge.find(Edge<E>(i, j)); if(pos >= 0) { value = temp_v->edge.get(pos).data; } else { THROW_EXCEPTION(IdexOutOfBoundException, "error: index out of bound"); } } else { THROW_EXCEPTION(IdexOutOfBoundException, "index out of bound"); } return ret; } bool setEdge(int i, int j, const E& value) { bool ret = ((0 <= i) && (i < vCount()) && (0 <= j) && (j < vCount())); if(ret) { Vertex* temp_v = m_list.get(i); int pos = temp_v->edge.find(Edge<E>(i, j)); if(pos >= 0) { ret = temp_v->edge.set(pos, Edge<E>(i, j, value)); } else { ret = temp_v->edge.insert(0, Edge<E>(i, j, value)); } } else { THROW_EXCEPTION(IdexOutOfBoundException, "index out of bound"); } return ret; } bool removeEdge(int i, int j) { bool ret = ((0 <= i) && (i < vCount()) && (0 <= j) && (j < vCount())); if(ret) { Vertex* temp_v = m_list.get(i); int pos = temp_v->edge.find(Edge<E>(i, j)); if(pos >= 0) { ret = temp_v->edge.remove(pos); } else { THROW_EXCEPTION(IdexOutOfBoundException, "index out of bound"); } } else { THROW_EXCEPTION(IdexOutOfBoundException, "index out of bound"); } return ret; } int vCount() { return m_list.length(); } int eCount() { int count = 0; for(m_list.move(0); !m_list.end(); m_list.next()) count += m_list.current()->edge.length(); return count; } int ID(int i) { int count = 0; if((0 <= i) && (i < vCount())) { for(m_list.move(0); !m_list.end(); m_list.next()) { for(m_list.current()->edge.move(0); !m_list.current()->edge.end(); m_list.current()->edge.next()) { if(m_list.current()->edge.current().e_end == i) { count++; break; } } } } else { THROW_EXCEPTION(IdexOutOfBoundException, "index out of bound"); } return count; } int OD(int i) { int count = 0; if((0 <= i) && (i < vCount())) { count = m_list.get(i)->edge.length(); } else { THROW_EXCEPTION(IdexOutOfBoundException, "index out of bound"); } return count; } int TD(int i) { return (ID(i) + OD(i)); } ~ListGraph() { while(m_list.length() > 0) { Vertex* toDel = m_list.get(0); m_list.remove(0); delete toDel->data; delete toDel; } } }; } #endif
图的遍历
1. BFS(广度优先算法)
类似于树的层次遍历,先遍历同一层次的横向节点,
使用两个队列temp_queue,ret_queue,一个数组marked[]标记节点是否访问过
a. 先将起始顶点V压入队列temp_queue中
b. 再将队列temp_queue的头顶点V弹出,判断是否访问过(访问过转b,没有访问过转c)
c. 标记顶点V为访问过,将V的邻接节点压入队列temp_queue
d. 判断队列temp_queue是否为空,空则返回ret_queue(非空转b)
1 SharedPointer<Array<int>> BFS(int i) 2 { 3 DynamicArray<int>* output_array = NULL; 4 5 if((0 <= i) && (i < vCount())) 6 { 7 DynamicArray<bool> marked(vCount()); 8 LinkListQueue<int> tmp_queue; 9 LinkListQueue<int> ret_queue; 10 11 for(int j = 0; j < vCount(); j++) 12 marked[j] = false; 13 14 tmp_queue.add(i); 15 while(0 < tmp_queue.length()) 16 { 17 int v = tmp_queue.front(); 18 tmp_queue.remove(); 19 if(!marked[i]) 20 { 21 SharedPointer<Array<int>> ad = getAdjacent(v); 22 for(int j = 0; j < ad->length(); j++) 23 tmp_queue.add((*ad)[j]); 24 } 25 ret_queue.add(v); 26 marked[i] = ture; 27 } 28 29 output_array = new DynamicArray<int>(ret_queue.length()); 30 if(output_array) 31 { 32 for(int j = 0; j < output_array->length(); j++, ret_queue.remove()) 33 output_array->set(j, ret_queue.front()); 34 } 35 else 36 { 37 THROW_EXCEPTION(NotEnoughMemoryException, "error: no enough to create array"); 38 } 39 } 40 else 41 { 42 THROW_EXCEPTION(IdexOutOfBoundException, "error: index out of bound"); 43 } 44 return output_array; 45 } 46
2. DFS(深度优先算法)
类似于树的前序遍历,先遍历纵向的节点,当前节点没有可以访问的邻接节点则回退
使用一个栈temp_stack,一个队列ret_queue,一个数组marked[]标记节点是否被访问过
a. 将起始顶点V_top压入栈中
b. 弹出起始顶点v_top,判断是否被访问过/标记过(被访问过则丢掉当前节点再转b,没有转c)
c. 标记顶点v_top,将v_top顶点压入ret_queue中,并将顶点v_top的邻接顶点压入栈中
d. 栈为空则返回(非空转b)
1 SharedPointer< Array<int> > DFS(int i) 2 { 3 DynamicArray<int>* output_array = NULL; 4 if((0 <= i) && (i < vCount())) 5 { 6 LinkListStack<int> temp_stack; 7 LinkListQueue<int> ret_queue; 8 DynamicArray<bool> marked(vCount()); 9 10 for(int j = 0; j < vCount(); j++) 11 marked.set(j, false); 12 13 temp_stack.push(i); 14 while(0 < temp_stack.size()) 15 { 16 int v = temp_stack.top(); 17 temp_stack.pop(); 18 if(marked[i] != ture) 19 { 20 SharedPointer< Array<int> > temp_ad = getAdjacent(v); 21 for(int j = temp_ad->length() - 1; 0 <= j; j--) 22 temp_stack.push((*temp_ad)[j]); 23 } 24 ret_queue.add(v); 25 marked[i] = ture; 26 } 27 28 output_array = new DynamicArray<int>(ret_queue.length()); 29 if(output_array) 30 { 31 for(int j = 0; j < output_array->length(); j++, ret_queue.remove()) 32 output_array->set(j, ret_queue.front()); 33 } 34 else 35 { 36 THROW_EXCEPTION(NotEnoughMemoryException, "error: no enough to create array"); 37 } 38 return output_array; 39 } 40 else 41 { 42 THROW_EXCEPTION(IdexOutOfBoundException, "error: index out of bound"); 43 } 44 }
3. DFS (递归实现)
将遍历的图G分为两个部分,第一部分是起始顶点V0,第二部分其他顶点组成的子图G'。
DFS(G) = visited(V0) + DFS(G') //G'为空则返回
DFS(graph, vex) 以顶点vex为起始顶点深度优先遍历graph
a. 访问vex节点,如果vex的邻接顶点为空,即返回
b. 先访问起始顶点vex,再判断vex的邻接顶点不为空,获取临界顶点为新的起始顶点,继续递归。
1 SharedPointer< Array<int> > DFS_R(int i) 2 { 3 DynamicArray<int>* output_array = NULL; 4 if((0 <= i) && (i < vCount())) 5 { 6 LinkListQueue<int> ret_queue; 7 DynamicArray<bool> marked(vCount()); 8 for(int j = 0; j < vCount(); j++) 9 marked.set(j, false); 10 11 DFS_R_core(*this, i, marked, ret_queue); 12 13 output_array = new DynamicArray<int>(ret_queue.length()); 14 if(output_array) 15 { 16 for(int j = 0; j < output_array->length(); j++, ret_queue.remove()) 17 output_array->set(j, ret_queue.front()); 18 } 19 } 20 else 21 { 22 THROW_EXCEPTION(IdexOutOfBoundException, "error: index out of bound"); 23 } 24 return output_array; 25 } 26 27 void DFS_R_core(Graph<V, E>& g, int i, Array<bool>& marked, LinkListQueue<int>& ret_queue) 28 { 29 ret_queue.add(i); 30 marked[i] = ture; 31 SharedPointer< Array<int> > ad = g.getAdjacent(i); 32 for(int j = 0; j < ad->length(); j++) 33 { 34 if(!marked[(*ad)[j]]) 35 DFS_R_core(g, (*ad)[j], marked, ret_queue); 36 } 37 } 38 };
4. Prim(最小生成树)
如何使得再图中选择n-1条边使得n个顶点之间两两可达,并使得n-1条边权值最小
a. 仅使用图中的n-1条边连接图中的n个顶点
b. 不能使用产生回路的边
c. 各边的权值总和达到最小
d.只针对无向图
算法组成:
Array<bool> marked 标记顶点所属集合{T / F}.数组下标表示顶点坐标,数组值表示顶点的位置.
Array<E> cost 记录T集合到F集合中所有不同顶点之间边的集合并选择最小那条边并标记边的末尾顶点到marked数组(如果T顶点集合到F顶点集合之间F的同一顶点连接有多条,选取权值最小的连接).
数组值表示边的权值,数组下标和adjVex数组下标一一对应并表示图的边
Array<int> adjVex 记录cost数组中权值对应的顶点.数组下标表示边的终止顶点,数组值表示边的起始顶点.
Queue<Edge> ret 记录最小生成树中的边
算法步骤:
a. 选择某一项顶点v0作为起始顶点,使得T = {v0};F = {v1,v2,,,vn}; E = { };
b. 每次选择一条边,这条边是边集合(U, V)中权值最小的边,且U属于T,V属于F
c. 修改T,F,E:T = T + {V}, F = F - {V}, E = E + {(U, V)}
d. 当F != NULL时且T到F是有连接的,即是(U,V)存在,则转b.否则结束