当前位置:   article > 正文

有向图找环的递归/非递归算法_有向图邻接矩阵查询所有的环

有向图邻接矩阵查询所有的环

参考网址:有向图找环_c语言有向图里面找环-CSDN博客

实验数据

算法运行结果

递归 + 邻接矩阵 

参数

  • map,图的邻接表;
  • visit, 记录每一个点的访问状态;
  • path, 已遍历的点列表;
  • m,当前遍历的点,即在path的索引位置;
  • k, 起始遍历点的点索引,即对应map的行
  • fun,回调函数,当找到一个环时调用,回调函数的参数表示path中环的起点和终点的位置索引
  1. //递归算法
  2. //优点:结构简单,缺点:递归太深容易爆栈
  3. void route_searching1(Eigen::MatrixXi& map, std::vector<int>& visit, std::vector<int>&path, int& m, int k, std::function<void(int,int)>fun){
  4. visit[k]=1;
  5. //正在访问
  6. path[m++]=k;
  7. for(int i=0;i<map.cols();i++){
  8. if(map(k,i)==1){
  9. //2个点之间有边
  10. if(visit[i]==0){
  11. route_searching1(map, visit, path, m, i, fun);
  12. //递归去访问
  13. }
  14. if(visit[i]==1){
  15. //出现环 打印出来
  16. for(int j=m-1;;j--){
  17. if(path[j]==i){
  18. fun(j, m-1);
  19. break;
  20. }
  21. }
  22. }
  23. //表示当前点访问过
  24. if(visit[i]==-1)
  25. {
  26. continue;
  27. }
  28. }
  29. }
  30. visit[k]=-1;
  31. //访问结束
  32. m--;
  33. }

非递归 + 邻接矩阵 

参数

  • map,图的邻接表;
  • visit, 记录每一个点的访问状态;
  • fun,回调函数,当找到一个环时调用,回调函数的参数表示path,以及环的起点和终点的位置索引
  1. //使用栈,非递归
  2. //优点:不会爆栈
  3. void route_searching2(Eigen::MatrixXi& map, std::vector<int>& visit, std::function<void(std::vector<int>&,int,int)>fun){
  4. std::vector<int> path(map.rows(),0);
  5. //路径
  6. int m = 0;
  7. //路径中当前位置
  8. std::vector<std::pair<int,int>>stack;
  9. //栈
  10. for(int i=0;i<map.rows();i++){
  11. stack.push_back({i, m});
  12. while(stack.size()){
  13. std::pair<int,int> pair = stack.back();
  14. stack.pop_back();
  15. //回溯(将当前点后面的路径设置为已访问过)
  16. while(pair.second < m){
  17. visit[path[--m]] = -1;
  18. }
  19. int id = pair.first;
  20. if(visit[id]==0){
  21. //未访问
  22. path[m++] = id;
  23. //添加路径
  24. visit[id] = 1;
  25. //正在访问
  26. //下一个点(有可能有多个)
  27. for(int j = 0; j < map.cols(); ++j){
  28. if(map(id,j)){
  29. stack.push_back({j, m});
  30. }
  31. }
  32. }
  33. else if(visit[id]==1){
  34. //找到环
  35. for(int j=m-1;;j--){
  36. if(path[j]==id){
  37. fun(path, j, m-1);
  38. break;
  39. }
  40. }
  41. }
  42. else if(visit[id]==-1){
  43. //已访问过
  44. continue;
  45. }
  46. }
  47. //清空路径并设置已访问
  48. while(m){
  49. visit[path[--m]] = -1;
  50. }
  51. }
  52. }

非递归+邻接表

参数:

  • n:点的个数
  • adjacency_list、first,、next,:邻接表
    out:输出
  1. struct STACK {
  2. int idx;
  3. int m;
  4. };
  5. //使用栈,非递归
  6. //优点:不会爆栈,内存占用少
  7. void route_searching3(int n, std::vector<std::pair<int, int>>&adjacency_list,std::vector<int>&first,std::vector<int>&next, std::function<void(int*, int, int)>fun) {
  8. std::vector<int> visit(n, 0);
  9. std::vector<int> path(n, -1);
  10. int m = 0;
  11. //路径中当前位置
  12. std::vector<STACK>stack;
  13. //栈
  14. for (int i = 0; i < n; i++) {
  15. if (visit[i] == -1)
  16. continue;
  17. stack.push_back({ i, m });
  18. while (stack.size()) {
  19. STACK cur_pt = stack.back();
  20. stack.pop_back();
  21. //回溯(将当前点后面的路径设置为已访问过)
  22. while (cur_pt.m < m) {
  23. visit[path[--m]] = -1;
  24. }
  25. int idx = cur_pt.idx;
  26. if (visit[idx] == 0) {
  27. //未访问
  28. path[m++] = cur_pt.idx;
  29. //添加路径
  30. visit[idx] = 1;
  31. //正在访问
  32. int next_id = first[idx];
  33. while (next_id != -1) {
  34. stack.push_back({ adjacency_list[next_id].second, m });
  35. next_id = next[next_id];
  36. }
  37. }
  38. else if (visit[idx] == 1) {
  39. //找到环
  40. for (int j = m - 1;; j--) {
  41. if (path[j] == idx) {
  42. fun(path.data(), j, m-1);
  43. break;
  44. }
  45. }
  46. }
  47. else if (visit[idx] == -1) {
  48. //已访问过
  49. continue;
  50. }
  51. }
  52. while (m) {
  53. visit[path[--m]] = -1;
  54. }
  55. }
  56. }

QT完整代码

  1. //.h
  2. //数据结构
  3. struct holeEdge{
  4. QPoint p1;
  5. QPoint p2;
  6. };
  7. //类成员变量
  8. std::vector<holeEdge*> circularNodes;//有向线段
  9. std::vector<std::vector<QPoint>>out_pts;//输出
  10. std::vector<QPoint>pts;
  11. //.cpp
  12. bool operator < (const QPoint& p1,const QPoint& p2){
  13. if(p1.x() != p2.x())
  14. return p1.x() < p2.x();
  15. if(p1.y() != p2.y())
  16. return p1.y() < p2.y();
  17. return false;
  18. }
  19. void Widget::getCircular(std::vector<holeEdge*> &circularNodes, int flag ){
  20. //递归算法 + 邻接矩阵
  21. if(flag == 0){
  22. std::map<QPoint, int>pts_map;
  23. std::vector<std::pair<int,int>>pairs;
  24. pts.clear();
  25. for(auto& edge : circularNodes){
  26. auto pair1 = pts_map.insert(std::make_pair(edge->p1, pts.size()));
  27. if(pair1.second){
  28. pts.push_back(edge->p1);
  29. }
  30. auto pair2 = pts_map.insert(std::make_pair(edge->p2, pts.size()));
  31. if(pair2.second){
  32. pts.push_back(edge->p2);
  33. }
  34. pairs.push_back(std::make_pair(pair1.first->second, pair2.first->second));
  35. }
  36. Eigen::MatrixXi map(pts.size(),pts.size());//邻接矩阵
  37. map.setZero();
  38. std::vector<int> visit(pts.size(),0);//访问标记 -1:已访问;0为访问;1正在访问
  39. std::vector<int> path(pts.size(), -1);
  40. int m = 0;
  41. for(int i = 0; i < pairs.size(); ++i){
  42. auto pair = pairs[i];
  43. map(pair.first,pair.second) = 1;
  44. }
  45. out_pts.clear();
  46. for(int i=0;i<pts.size();i++){
  47. if(visit[i]!=-1)
  48. route_searching1(map, visit, path, m, i,[&](int a, int b){
  49. std::vector<QPoint> pt;
  50. for(int j = a; j <= b; j++)
  51. pt.push_back(pts[path[j]]);
  52. out_pts.push_back(pt);
  53. });
  54. }
  55. }
  56. //非递归 + 邻接矩阵
  57. else if (flag == 1){
  58. std::map<QPoint, int>pts_map;
  59. std::vector<std::pair<int,int>>pairs;
  60. pts.clear();
  61. for(auto& edge : circularNodes){
  62. auto pair1 = pts_map.insert(std::make_pair(edge->p1, pts.size()));
  63. if(pair1.second){
  64. pts.push_back(edge->p1);
  65. }
  66. auto pair2 = pts_map.insert(std::make_pair(edge->p2, pts.size()));
  67. if(pair2.second){
  68. pts.push_back(edge->p2);
  69. }
  70. pairs.push_back(std::make_pair(pair1.first->second, pair2.first->second));
  71. }
  72. Eigen::MatrixXi map(pts.size(),pts.size());//邻接矩阵
  73. map.setZero();
  74. std::vector<int> visit(pts.size(),0);//访问标记 -1:已访问;0为访问;1正在访问
  75. std::vector<int> path(pts.size(), -1);
  76. int m = 0;
  77. for(int i = 0; i < pairs.size(); ++i){
  78. auto pair = pairs[i];
  79. map(pair.first,pair.second) = 1;
  80. }
  81. out_pts.clear();
  82. for(int i=0;i<pts.size();i++){
  83. if(visit[i]!=-1)
  84. route_searching2(map, visit,[&](std::vector<int>&path, int a, int b){
  85. std::vector<QPoint> pt;
  86. for(int j = a; j <= b; j++)
  87. pt.push_back(pts[path[j]]);
  88. out_pts.push_back(pt);
  89. });
  90. }
  91. }
  92. //非递归 + 邻接表
  93. else if (flag == 2){
  94. std::vector<std::vector<int>> points_out;
  95. std::map<QPoint, int>map_pt;
  96. std::vector<QPoint>vertices;
  97. for (int i = 0; i < circularNodes.size(); i++) {
  98. holeEdge* edge = circularNodes[i];
  99. auto pair1 = map_pt.insert({ edge->p1, vertices.size()});
  100. if (pair1.second) {
  101. vertices.push_back(edge->p1);
  102. }
  103. auto pair2 = map_pt.insert({ edge->p2, vertices.size() });
  104. if (pair2.second) {
  105. vertices.push_back(edge->p2);
  106. }
  107. }
  108. std::vector<std::pair<int,int>>adjacency_list;//邻接表
  109. std::vector<int>first(vertices.size(),-1);
  110. std::vector<int>next(circularNodes.size(), -1);
  111. for (int i = 0; i < circularNodes.size(); i++) {
  112. holeEdge* edge = circularNodes[i];
  113. int u = map_pt[edge->p1];
  114. int v = map_pt[edge->p2];
  115. adjacency_list.push_back({u,v});
  116. int idx = adjacency_list.size() - 1;
  117. next[idx] = first[u];
  118. first[u] = idx;
  119. }
  120. route_searching3(vertices.size(), adjacency_list, first, next, [&points_out](int *path, int start, int end) {
  121. if (end - start >= 2) {
  122. std::vector<int>& vec = points_out.emplace_back();
  123. while (start <= end)
  124. vec.push_back(path[start++]);
  125. }
  126. });
  127. out_pts.clear();
  128. for(auto& vec : points_out){
  129. std::vector<QPoint> vec2;
  130. for(int i : vec){
  131. vec2.push_back(vertices[i]);
  132. }
  133. out_pts.push_back(vec2);
  134. }
  135. }
  136. }
  137. Widget::Widget(QWidget *parent)
  138. : QWidget(parent)
  139. , ui(new Ui::Widget)
  140. {
  141. ui->setupUi(this);
  142. //构建实验数据
  143. //1
  144. circularNodes.push_back(new holeEdge{QPoint(146,431),QPoint(270,461)});
  145. circularNodes.push_back(new holeEdge{QPoint(270,461),QPoint(254,321)});
  146. circularNodes.push_back(new holeEdge{QPoint(254,321),QPoint(163,338)});
  147. circularNodes.push_back(new holeEdge{QPoint(163,338),QPoint(146,431)});
  148. //2
  149. circularNodes.push_back(new holeEdge{QPoint(254,321),QPoint(309,388)});
  150. circularNodes.push_back(new holeEdge{QPoint(309,388),QPoint(425,407)});
  151. circularNodes.push_back(new holeEdge{QPoint(425,407),QPoint(465,337)});
  152. circularNodes.push_back(new holeEdge{QPoint(465,337),QPoint(404,268)});
  153. circularNodes.push_back(new holeEdge{QPoint(404,268),QPoint(254,321)});
  154. //3
  155. circularNodes.push_back(new holeEdge{QPoint(254,321),QPoint(326,241)});
  156. circularNodes.push_back(new holeEdge{QPoint(326,241),QPoint(308,158)});
  157. circularNodes.push_back(new holeEdge{QPoint(308,158),QPoint(162,160)});
  158. circularNodes.push_back(new holeEdge{QPoint(162,160),QPoint(125,255)});
  159. circularNodes.push_back(new holeEdge{QPoint(125,255),QPoint(254,321)});
  160. //4
  161. circularNodes.push_back(new holeEdge{QPoint(308,158),QPoint(370,94)});
  162. circularNodes.push_back(new holeEdge{QPoint(370,94),QPoint(238,49)});
  163. circularNodes.push_back(new holeEdge{QPoint(238,49),QPoint(197,118)});
  164. circularNodes.push_back(new holeEdge{QPoint(197,118),QPoint(308,158)});
  165. //5
  166. circularNodes.push_back(new holeEdge{QPoint(577,528),QPoint(712,515)});
  167. circularNodes.push_back(new holeEdge{QPoint(712,515),QPoint(713,395)});
  168. circularNodes.push_back(new holeEdge{QPoint(713,395),QPoint(577,528)});
  169. circularNodes.push_back(new holeEdge{QPoint(569,406),QPoint(577,528)});
  170. //6
  171. circularNodes.push_back(new holeEdge{QPoint(519,211),QPoint(625,298)});
  172. circularNodes.push_back(new holeEdge{QPoint(625,298),QPoint(719,247)});
  173. //7
  174. circularNodes.push_back(new holeEdge{QPoint(480,94),QPoint(574,131)});
  175. circularNodes.push_back(new holeEdge{QPoint(574,131),QPoint(543,21)});
  176. circularNodes.push_back(new holeEdge{QPoint(543,21),QPoint(480,94)});
  177. //getCircular(circularNodes, 0);
  178. //getCircular(circularNodes, 1);
  179. getCircular(circularNodes, 2);
  180. }
  181. Widget::~Widget()
  182. {
  183. delete ui;
  184. }
  185. void Widget::paintEvent(QPaintEvent *event)
  186. {
  187. QPainter painter(this);
  188. #if 0
  189. painter.setPen(Qt::red);
  190. for(auto& edge : circularNodes){
  191. painter.drawLine(edge->p1, edge->p2);
  192. }
  193. #else
  194. for(auto& path : out_pts){
  195. painter.setBrush(QColor(rand()%255,rand()%255,rand()%255));
  196. painter.drawPolygon(path.data(), path.size());
  197. }
  198. #endif
  199. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/64531
推荐阅读
相关标签
  

闽ICP备14008679号