A开始有3条分支,首先选择B走到底ABEG,走不通的时候回退走另外一条GBCFD
(1)A开始分叉选择一条边走,走到B分叉,再选择一条边E开始走,继续到G没有边了,然后回退到E看E有没有其他边,没有再回退到B,B 有其他边,选择C
只要在当前的顶点上面,有边可以走到其他顶点,那么就深入放入走下去
原材料:栈
(1)
从i顶点开始对图进行深度优先遍历
(1)原材料 :栈 stack(保存顶点) 队列 return 访问标记数组 visited
(2)初始值状态每个顶点都没有标记访问 visited = { false }
(3)初始顶点 i 压入栈顶
(4)判断栈是否为空 循环 ----------也就是栈内是否还有顶点
(5)没有------取出栈顶顶点 v=stack.top(); stack.pop();
(6)v判断取出的顶点v是否访问 visited[v]
(7)没有访问-----将顶点 v 的邻接顶点取出来,压入栈中
(8)将v顶点取出压入 reture 队列,将v标记为以访问
(9)判断栈内是否还有元素 -------- 循环找下一个栈顶
(10)判断访问状态 访问了----扔出去 没有 流程循环
队列 return---------保存的是深度优先访问下的顶点次序
添加DFS函数:
1 #ifndef GRAPH_H 2 #define GRAPH_H 3 4 #include "Object.h" 5 #include "SharePointer.h" 6 #include "DynamicArray.h" 7 #include "LinkQueue.h" 8 #include "LinkStack.h" 9 10 using namespace std; 11 namespace DTLib 12 { 13 14 /* 设置边的数据结构,用于邻接链表 */ 15 template < typename E > 16 struct Edge : public Object 17 { 18 int b; // 起点 19 int e; // 终点 20 E data; // 权值 21 22 Edge(int i = -1, int j = -1) //构造函数 23 { 24 b = i; 25 e = j; 26 } 27 28 Edge(int i, int j, const E& value) //重载函数 29 { 30 b = i; 31 e = j; 32 data = value; 33 } 34 35 /* 相等和不等不需要对权值进行比价,只比较起始点位置,终止位置,删除顶点操作中查找操作用到,在此处定义了 */ 36 bool operator == (const Edge<E>& obj) 37 { 38 return (b == obj.b) && (e == obj.e); //起点终点相等,边对象相等,不关注权值 39 } 40 41 bool operator != (const Edge<E>& obj) 42 { 43 return !(*this == obj); 44 } 45 46 bool operator < (const Edge<E>& obj) 47 { 48 return (data < obj.data); // 权值比较边的大小 49 } 50 51 bool operator > (const Edge<E>& obj) 52 { 53 return (data > obj.data); // 权值比较边的大小 54 } 55 }; 56 57 /* 抽象类不能够用来继承,能用来定义指针-----------队列转数组 */ 58 template < typename V, typename E > 59 class Graph : public Object 60 { 61 protected: 62 63 //队列转数组 64 template <typename T> 65 DynamicArray<T>* toArray(LinkQueue<T>& queue) 66 { 67 DynamicArray<T>* ret = new DynamicArray<T>(queue.length()) //堆空间申请与队列长度一致的数组对象 68 69 if (ret != NULL) 70 { 71 for (int i = 0; i < ret->length(); i++, queue.remove()) 72 { 73 ret->set(i, queue.front()); //队列中每个数组放在队列中 74 } 75 } 76 else 77 { 78 THROW_EXCEPTION(NoEnoughMemoryException, "no enough memoty ..."); 79 } 80 81 return ret; 82 } 83 84 public: 85 virtual V getVertex(int i) = 0; // V 表示与顶点相关联的数据类型 86 virtual bool getVertex(int i, V& value) = 0; 87 virtual bool setVertex(int i, const V& value) = 0; 88 virtual SharedPointer< Array<int> > getAdgacent(int i) = 0; 89 virtual bool isAdjacent(int i, int j) = 0;//i和j 是否连接,只能在继承中实现 90 virtual E getEdge(int i, int j) = 0;// E表示与边相关联的数据类型,得到边上的//权值 91 virtual bool getEdge(int i, int j, E& value) = 0; 92 virtual bool setEdge(int i, int j, const E& value) = 0; 93 virtual bool removeEdge(int i, int j) = 0; 94 virtual int vCount() = 0; 95 virtual int eCount() = 0; 96 virtual int OD(int i) = 0; 97 virtual int ID(int i) = 0; 98 virtual int TD(int i) // 顶点 i 的度,即与顶点 i 相关联的边的数目 99 { 100 return OD(i) + ID(i); // 出度加上入度 101 } 102 103 104 105 /* 判断在当前图中顶点i到顶点j是否邻接*/ 106 virtual bool isAdjacent(int i, int j) = 0; 107 108 /* 判断当前的有向图是否可以看做无向图*/ 109 bool asUndirected() 110 { 111 bool ret = true; 112 113 for (int i = 0; i < vCount(); i++) 114 { 115 for (int j = 0; j < vCount(); j++) 116 { 117 if (isAdjacent(i, j)) //i到j有边,j到i也有边,且i到j,j到i的权值相等 118 { 119 ret = ret && isAdjacent(j, i) && (getEdge(i, j) == getEdge(j, i)); 120 } 121 } 122 } 123 124 return ret; 125 } 126 127 128 129 /*广度优先遍历算法*/ 130 SharedPointer<Array<int>> BFS(int i) 131 { 132 DynamicArray<int>* ret = NULL; //返回值是数组:保存图中顶点的编号----- 133 //使用数组原因----通过数组元素次序访问顶点访问先后次序 134 135 if ((0 <= i) && (i < vCount())) 136 { 137 LinkQueue<int> q; //queue队列 138 LinkQueue<int> r; // rerurn 队列-----保存访问过的顶点 139 DynamicArray<bool> visited(vCount()); //标记数组:标记顶点是否被访问 140 141 /*初始值设置*/ 142 for (int i = 0; i < vCount(); i++) 143 { 144 visited[i] = false; //默认每个顶点都没有被访问 145 } 146 147 q.add(i); //顶点加队列queue 148 149 while (q.length()>0) //循环(queue不为空) 150 { 151 int v = q.front(); 152 q.remove(); //取队列头部顶点 153 154 if (!visited[i]) //判断顶点是否访问 155 { 156 SharedPointer<Array<int>> aj = getAdgacent(v); //取v的邻接顶点 157 158 /*邻接顶点放入Queue队列*/ 159 for (int j = 0; j < aj->length(); j++) 160 { 161 q.add(*(aj)[j]); 162 } 163 164 r.add(v); //顶点v压入return队列 165 166 visited[v] = true; //标记数组为true表示被访问 167 } 168 } 169 ret = toArray(r); //要实现队列转数组,因为返回值是数组 170 } 171 else 172 { 173 THROW_EXCEPTION(InvalidParameterException, "index i is invalid ..."); 174 } 175 176 return ret; 177 } 178 179 /*深度优先遍历算法*/---------------------------------------//深度优先算法------------------------------------------- 180 SharedPointer<Array<int>> DFS(int i) 181 { 182 DynamicArray<int>* ret = NULL; //返回值----数组 183 184 if ((0 <= i) && (i < vCount())) //顶点合法 185 { 186 //3个原材料 187 LinkStack<int> s; //栈---保存顶点数据元素 188 LinkQueue<int> r; //队列----保存的是深度优先访问下的顶点次序 189 DynamicArray<bool> visited(vCount()); //标记数组-----标记顶点有没有被访问 190 191 for (int j = 0; j < visited.length(); j++) 192 { 193 visited[j] = false; //标记数组初始化为false,所以顶点都没有被访问 194 } 195 196 s.push(i); //初始顶点i压栈 197 198 while (s.size() > 0) //栈内有顶点------一直循环 199 { 200 int v = s.top(); //找栈顶顶点v 201 202 s.pop(); //弹出栈顶顶点v 203 204 if (!visited[j]) //判断栈顶顶点有没有被标记 205 { 206 //未被标记访问 207 SharedPointer<Array<int>> aj = getAdgacent(v); //取出顶点v的邻接顶点 208 209 for (int j = aj->length() - 1; j >= 0; j--) 210 { 211 s.push((*aj)[i]); //顶点v的所有邻接顶点压入栈 212 } 213 214 r.add(v); //将顶点v弹出,保存在return队列 215 216 visited[v] = true; //标记此时顶点为访问状态---true 217 } 218 } 219 220 ret = toArray(r); //队列转化为数组-------因为返回值是数组 221 } 222 else 223 { 224 THROW_EXCEPTION(InvalidParameterException, "index i is invalid ..."); 225 } 226 } 227 //------------------------------------------------------------------------------------------------------------------- 228 229 }; 230 } 231 #endif // GRAPH_H
测试程序如下:
1 #include <iostream> 2 #include "BTreeNode.h" 3 #include "ListGraph.h" 4 #include "MatrixGraph.h" 5 6 using namespace std; 7 using namespace DTLib; 8 9 10 int main() 11 { 12 MatrixGraph<9, char, int> g; 13 const char* VD = "ABEDCGFHI"; 14 15 for(int i=0; i<9; i++) 16 { 17 g.setVertex(0, VD[i]); 18 } 19 20 g.setEdge(0, 1, 0); 21 g.setEdge(1, 0, 0); 22 23 g.setEdge(0, 3, 0); 24 g.setEdge(3, 0, 0); 25 26 g.setEdge(0, 4, 0); 27 g.setEdge(4, 0, 0); 28 29 g.setEdge(1, 2, 0); 30 g.setEdge(2, 1, 0); 31 32 g.setEdge(1, 4, 0); 33 g.setEdge(4, 1, 0); 34 35 g.setEdge(2, 5, 0); 36 g.setEdge(5, 2, 0); 37 38 g.setEdge(3, 6, 0); 39 g.setEdge(6, 3, 0); 40 41 g.setEdge(4, 6, 0); 42 g.setEdge(6, 4, 0); 43 44 g.setEdge(6, 7, 0); 45 g.setEdge(7, 6, 0); 46 47 g.setEdge(7, 8, 0); 48 g.setEdge(8, 7, 0); 49 50 SharedPointer< Array<int> > sa = g.DFS(0); //深度优先遍历 51 52 for(int i=0; i<sa->length(); i++) 53 { 54 cout << (*sa)[i] << " "; 55 } 56 57 cout << endl; 58 59 return 0; 60 }
结果如下:
(1)划分:起始顶点v0 + 剩余部分(原来图的子图)---------------1,先访问起始顶点 2,深度遍历剩余部分子图
深度优先的思想就是二叉树的先序遍历思想。
(1)graph 深度遍历的图 vex是起始顶点 DFS(graph,vex); 以vex为起始顶点,深度优先遍历graph
(2)vex 没有邻接顶点,访问结束
(3)vex 有邻接顶点 ,也就是vex到子图是有连接的,开始递归
1,访问起始顶点vex
2,取邻接顶点 aj
3,以aj 为新的起始顶点,深度优先遍历图
递归版的深入优先算法如下:
1 #include <iostream> 2 #include "BTreeNode.h" 3 #include "ListGraph.h" 4 #include "MatrixGraph.h" 5 6 using namespace std; 7 using namespace DTLib; 8 9 //二叉树先序遍历图 ---------- 递归函数 10 template < typename V, typename E> 11 void DFS(Graph<V, E>& g, int v, Array<bool>& visited) 12 { 13 if( (0 <= v) && (v < g.vCount()) ) //判断顶点v合法 14 { 15 cout << v << endl; 16 17 visited[v] = true; //标记当前图起始顶点v 是被访问状态 18 19 SharedPointer< Array<int> > aj = g.getAdjacent(v); //取当前顶点v的邻接顶点 20 21 //判断顶点v有没有邻接顶点-----有:指向递归循环深度遍历算法 22 for(int i=0; i<aj->length(); i++) 23 { 24 if( !visited[(*aj)[i]] ) //当前邻接顶点没有被访问 25 { 26 DFS(g, (*aj)[i], visited); //递归深度优先遍历 ---以邻接顶点为起始顶点 ,遍历图 27 } 28 } 29 } 30 else 31 { 32 THROW_EXCEPTION(InvalidParameterException, "Index v is invalid..."); 33 } 34 } 35 36 //二叉树先序遍历图 37 template < typename V, typename E > //g 深度遍历的图 v 图的顶点 38 void DFS(Graph<V, E>& g, int v) 39 { 40 DynamicArray<bool> visited(g.vCount()); //标记数组 ---- 标记顶点是否被访问 41 42 for(int i=0; i<visited.length(); i++) //每个元素顶点设置为未访问状态 43 { 44 visited[i] = false; 45 } 46 47 DFS(g, v, visited); //触发递归函数 48 } 49 50 int main() 51 { 52 MatrixGraph<9, char, int> g; 53 const char* VD = "ABEDCGFHI"; 54 55 for(int i=0; i<9; i++) 56 { 57 g.setVertex(0, VD[i]); 58 } 59 60 g.setEdge(0, 1, 0); 61 g.setEdge(1, 0, 0); 62 63 g.setEdge(0, 3, 0); 64 g.setEdge(3, 0, 0); 65 66 g.setEdge(0, 4, 0); 67 g.setEdge(4, 0, 0); 68 69 g.setEdge(1, 2, 0); 70 g.setEdge(2, 1, 0); 71 72 g.setEdge(1, 4, 0); 73 g.setEdge(4, 1, 0); 74 75 g.setEdge(2, 5, 0); 76 g.setEdge(5, 2, 0); 77 78 g.setEdge(3, 6, 0); 79 g.setEdge(6, 3, 0); 80 81 g.setEdge(4, 6, 0); 82 g.setEdge(6, 4, 0); 83 84 g.setEdge(6, 7, 0); 85 g.setEdge(7, 6, 0); 86 87 g.setEdge(7, 8, 0); 88 g.setEdge(8, 7, 0); 89 90 SharedPointer< Array<int> > sa = g.DFS(0); 91 92 for(int i=0; i<sa->length(); i++) 93 { 94 cout << (*sa)[i] << " "; 95 } 96 97 cout << endl; 98 99 DFS(g, 0); //递归版本 100 101 return 0; 102 }
结果如下:
小结:
使用栈----------深度优先--------
使用队列-------广度优先