当前位置: 首页 > article >正文

C++ 有向图算法

概念

Breadth-First Search (BFS)

目的: 主要用于遍历或搜索图中的所有顶点。
特点: 从根节点开始,先访问所有与之相邻的节点,然后再一层一层地深入。
应用: 可以用来寻找两节点间的最短路径(当边的权重相等时),检测图中是否存在环路,以及层次遍历二叉树等。
数据结构: 使用队列来存储待访问的节点。
Depth-First Search (DFS):
目的: 同样用于遍历或搜索图中的所有顶点。
特点: 从根节点开始,尽可能深地搜索树的分支。
应用: 用于解决连通性问题,如检测环路、拓扑排序、迷宫求解等。
数据结构: 使用栈(可以是递归栈)来存储待访问的节点。

Dijkstra算法

目的: 用于找到图中一个节点到其他所有节点的最短路径。
特点: 要求图中没有负权边,并且是从一个源节点开始计算最短路径。
应用: 寻找两点之间的最短路径,广泛应用于路由算法。
数据结构: 使用优先队列(最小堆)来存储待处理的节点。

Kruskal算法

目的: 用于找到图的最小生成树(Minimum Spanning Tree, MST)。
特点: 是一种贪心算法,适用于边稀疏的图。
应用: 在网络设计中用于构建成本最低的网络连接。
数据结构: 使用并查集(Union-Find)来维护生成树的形成过程。

需要注意的是,Kruskal算法通常不直接用于有向图,因为它主要用于无向图中的最小生成树问题。对于有向图,我们通常考虑的是最短路径问题,而不是生成树问题

用法

#include "../src/algo/bfs.h"
#include "../src/algo/dfs.h"
#include "../src/algo/dijkstra.h"
#include "../src/algo/kruskal.h"

#include <gtest/gtest.h>

#include <chrono>
#include <memory>
#include <vector>

class GraphTest : public ::testing::Test
{
protected:
};


TEST_F(GraphTest, BFSTest)
{
  Graph graph{ false, false };
  graph.addEdges('a', { 'b' });
  graph.addEdges('b', { 'a', 'c' });
  graph.addEdges('c', { 'b', 'd', 'e' });
  graph.addEdges('d', { 'c', 'e' });
  graph.addEdges('e', { 'c', 'd' });

  auto begin = std::chrono::high_resolution_clock::now();
  BFS bfs{ graph };
//  DFS dfs{ graph };
  bfs.traverseGraph();
  auto end = std::chrono::high_resolution_clock::now();
  auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
  std::cout << "BFSTest : time in microseconds : " << elapsed.count() << std::endl;

  // 节点遍历
  const auto& nodes = graph.getNodes();
}


TEST_F(GraphTest, DijkstraTest)
{
  Graph graph{ true, true };
  graph.addEdgesWeighted('a', { { 'd', 3 }, { 'h', 5 } });
  graph.addEdgesWeighted('b', { { 'c', 4 }, { 'i', 1 } });
  graph.addEdgesWeighted('c', { { 'a', 4 }, { 'l', 5 } });
  graph.addEdgesWeighted('d', { { 'b', 2 }, { 'e', 1 }, { 'f', 8 } });
  graph.addEdgesWeighted('e', { { 'c', 5 }, { 'j', 7 } });
  graph.addEdgesWeighted('f', { { 'e', 2 }, { 'h', 2 }, { 'i', 7 }, { 'k', 10 } });
  graph.addEdgesWeighted('g', { { 'e', 3 } });
  graph.addEdgesWeighted('h', { { 'g', 6 }, { 'l', 4 }});
  graph.addEdgesWeighted('i', { { 'k', 6 } });
  graph.addEdgesWeighted('j', { { 'c', 8 } });
  graph.addEdgesWeighted('k', { { 'g', 3 }, { 'j', 5 } });
  graph.addEdgesWeighted('l', { { 'g', 2 }, { 'e', 5 }, {'f', 12 } });

  char src = 'a';
  char dst = 'b';
  Dijkstra dijkstra{ graph };
  auto begin = std::chrono::high_resolution_clock::now();
  dijkstra.traverseGraph(src);
  auto end = std::chrono::high_resolution_clock::now();
  auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
  std::cout << "DijkstraTest : time in microseconds : " << elapsed.count() << std::endl;

  // 最短路径
  const auto nodesList = std::make_unique<std::list<char>>();
  nodesList->push_front(dst);
  dijkstra.traverseGraph(src);
  const std::map<char, route>& routes = dijkstra.getRoutes();

  std::optional<char> predecessor;
  predecessor = routes.at(dst).predecessor;
  while (predecessor != std::nullopt) {
    nodesList->push_front(predecessor.value());
    predecessor = routes.at(predecessor.value()).predecessor;
  }
  auto shortPaths = std::make_unique<std::vector<char>>(nodesList->begin(), nodesList->end());
}

TEST_F(GraphTest, KruskalTest)
{
  Graph graph{ false, true };
  graph.addEdgesWeighted('a', { { 'b', 3 }, { 'f', 2 } });
  graph.addEdgesWeighted('b', { { 'c', 17 }, { 'd', 16 } });
  graph.addEdgesWeighted('c', { { 'd', 8 }, { 'i', 18 } });
  graph.addEdgesWeighted('d', { { 'e', 11 }, { 'i', 4 } });
  graph.addEdgesWeighted('e', { { 'f', 1 }, { 'g', 6 }, { 'h', 5 }, { 'i', 10 } });
  graph.addEdgesWeighted('f', { { 'g', 7 } });
  graph.addEdgesWeighted('g', { { 'h', 15 } });
  graph.addEdgesWeighted('h', { { 'i', 12 }, { 'j', 13 } });
  graph.addEdgesWeighted('i', { { 'j', 9 } });

  auto begin = std::chrono::high_resolution_clock::now();
  Kruskal kruskal{ graph };
  std::unique_ptr<std::vector<Edge>> edges = kruskal.makeMinSpanningTree();
  auto end = std::chrono::high_resolution_clock::now();
  auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - begin);
  std::cout << "KruskalTest : time in microseconds : " << elapsed.count() << std::endl;

  // 最小生成树,边的权值之和最低的子图
  auto edgesTuple  = std::make_unique<std::vector<std::tuple<char, char>>>();
  for (const Edge& edge : *edges) {
    edgesTuple->push_back(std::tuple<char, char>{ edge.src, edge.dst });
  }
}
参考

C++ 有向图拓扑排序算法_有向图排序c++-CSDN博客

https://github.com/Przemyslawmd/Graphs


创作不易,小小的支持一下吧!


http://www.kler.cn/news/285128.html

相关文章:

  • Tiptap中BubbleMenu讲解
  • CAN协议通信 学习笔记
  • 如何使用Hive构建高校考试分析系统:大数据技术在教育领域的应用
  • Ubuntu中qt类与类信号槽的创建及使用
  • 滑动窗口元素的平均值 ← STL : deque
  • GD32F4xx---RTC初始化设置及闹钟方式实现秒中断讲解
  • 数据结构概念
  • 代码随想录算法训练营第 56 天 |108冗余连接 109冗余连接 II
  • 地平线—征程2(Journey 2-J2)芯片详解(28)—MIPI RX/TX+SD/SDIO/eMMC Interface Timings
  • Python Excel 操作全面总结
  • 计算物理精解【3】
  • 10分钟了解OPPO中间件容器化实践
  • ue Rotate to face BB entry转向不对
  • springboot+redis+mybatis体会布隆过滤器
  • VMware中安装 Ubuntu ,实现 Windows 和 Ubuntu 之间自由复制粘贴
  • 7个流行的开源数据治理工具
  • 51单片机.之ADC数字模拟转换
  • 如何使用vcftools提取特定的染色体
  • vim 修改文件
  • 常见协议工作原理 https ARP ICMP DHCP PING
  • 华为手机数据丢失如何恢复?
  • 具身智能(Embodied Intelligence)概述
  • 【Redis】哨兵(Sentinel)
  • 1098 Insertion or Heap Sort
  • 在Docker中使用环境变量改变SpringBoot程序配置
  • 在React中使用TypeScript和Material-UI v5时,要为单个.tsx文件创建一个局部作用域的.scss文件如何做? 另外主题如何获取呢?
  • 【Linux修行路】进程通信——共享内存
  • erlang学习:用OTP构建系统1
  • Java算法之堆排序(Heap Sort)
  • 【软考】路由器