C++的拓扑排序实现

template<typename T = CString, typename _Data = CString>
struct Union_node//!< 节点
{
Union_node() :nColor(0) {}
std::vector<Union_node*> vecNodeSon;
T key;//!< 关键数据
_Data data;//!< 卫星数据
mutable int nColor;//0:白色节点(未发现),1:灰色节点(发现),2:黑色节点(完毕)
};

template<typename T = CString, typename _Data = CString>
class TopologicalSort//!< 拓扑排序
{
using node = std::shared_ptr<Union_node<T, _Data>>;
public:
void setSpNode(const std::vector<node>& spNode) { m_vecSpNode = spNode; }
void setSpNode(std::vector<node>&& spNode) { m_vecSpNode.swap(spNode); }

/*!
* 拓扑排序
* \return 是否是有向无环图
*/
bool topologicalSort(std::vector<node>& vecSpRes) const;
private:
/*!
* 深搜,如果图规模较大,可能会栈溢出,需要用栈辅助
*/
bool dfs(const node& spNode, std::vector<node>& vecSpRes) const;
private:
std::vector<node> m_vecSpNode;//!< 所有节点
};

template<typename T, typename _Data>
bool TopologicalSort<T, _Data>::topologicalSort(std::vector<node>& vecSpRes) const
{
vecSpRes.clear();

// 将所有节点的颜色标记为白色(未发现)
for (auto spNode : m_vecSpNode)
spNode->nColor = 0;

// 对每个白色节点进行深搜
for (auto spNode : m_vecSpNode)
{
if (spNode->nColor != 0)
continue;
if (!dfs(spNode, vecSpRes))
return false;//遇到环,则返回false
}

// 拓扑排列(完成时间晚的放到前面)
std::reverse(vecSpRes.begin(), vecSpRes.end());
return true;
}

template<typename T, typename _Data>
bool TopologicalSort<T, _Data>::dfs(const node& spNode, std::vector<node>& vecSpRes) const
{
spNode->nColor = 1;//标记为灰色节点(未发现)

for (auto spSon : spNode->vecNodeSon)
{
if (spSon->nColor == 1)
return false;//!< 如果遇到了灰色节点,则表示发现了环
else if (spSon->nColor == 0)
{
if (!dfs(spSon, vecSpRes))
return false;//!< 后继节点包含环,返回false
}
}

spNode->nColor = 2;//标记为黑色节点(已完成)
vecSpRes.emplace_back(spNode);
return true;
}

原文链接:https://www.cnblogs.com/shizhimofa/p/17343415.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++的拓扑排序实现 - Python技术站

(0)
上一篇 2023年4月22日
下一篇 2023年4月24日

相关文章

  • STL 容器 002 (vector 详解)

    为什么 各方面表现都比较中等, 适用范围广 尾插很快, 查找也比较快 是什么 动态数组 特点: 动态数组, 三个指针控制 两倍增长 扩充的方法: 不能原地扩充, 因为后面可能会有其他的东西, 必须在 其他地方开辟一块更大的内存 提供[] 所有的有连续空间的容器都有[] iterator是class类型的 怎么样 制造 两倍增长 //push_back() 检…

    C++ 2023年4月18日
    00
  • 05、【算例】openFoam盖驱动空腔流动

    管网:https://doc.cfd.direct/openfoam/user-guide-v9/cavity 一、算例实现 文件结构 0:存放初场 constant:存放网格信息 system:存放网格划分、计算等工具 1、画网格 blockMesh 2、求解 icoFoam 3、保存文件 touch cavity.OpenFOAM 4、后处理 parav…

    C++ 2023年4月18日
    00
  • 【Visual Leak Detector】配置项 StartDisabled

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 配置文件中配置项 StartDisabled 的使用方法。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 配置文件使用说明 2. 设置是否禁用自动初始化 2.1 测试代码 2.2 StartDisabled = no 时的输出 2.3 StartDisabled …

    C++ 2023年4月18日
    00
  • 【Visual Leak Detector】配置项 StackWalkMethod

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 配置文件中配置项 StackWalkMethod 的使用方法。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 配置文件使用说明 2. 设置调用堆栈的跟踪方法 2.1 测试代码 2.2 StackWalkMethod = fast 时的输出 2.3 StackWal…

    C++ 2023年4月18日
    00
  • 聊一聊 Valgrind 监视非托管内存泄露和崩溃

    一:背景 1. 讲故事 只要是程序总会出现各种莫名其妙的问题,比如:非托管内存泄露,程序崩溃,在 Windows 平台上一般用微软自家的官方工具 App Verifier 就可以洞察,那问题出在 Linux 上怎么办呢?由于 Linux 崇尚自由,需要在各种牛鬼蛇神写的非官方开源软件中寻找一个比较靠谱的,比如本篇所说的 Valgrind。 个人感觉 Valg…

    C++ 2023年5月5日
    00
  • day3 函数的定义和调用,练习编写简单的程序(记录1)

    一、函数的定义 可以分为以下两种: 1、函数声明和函数定义分离 这种方法将函数声明和函数定义分开,通常在头文件中先声明函数原型,然后在源文件中实现函数定义。 例如,头文件 example.h 中声明了一个函数 add: #ifndef EXAMPLE_H #define EXAMPLE_H int add(int a, int b); // 声明函数原型 #…

    C++ 2023年4月18日
    00
  • 最少步数

    在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100*100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一…

    C++ 2023年4月25日
    00
  • 【Visual Leak Detector】Release 模式下使用 VLD

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍如何在 Release 模式下使用 VLD。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 思路概述 2. 在 QT 中实践 1. 思路概述 要在 RELEASE 模式下使用 VLD,必须在包含头文件 vld.h 前预先定义 VLD_FORCE_ENABLE 宏(参考 VL…

    C++ 2023年4月17日
    00
合作推广
合作推广
分享本页
返回顶部