图结构:拓扑排序

pre

  • 可排序拓扑图:有相无环图
  • 网上资料很多,结构也比较明确:
  • 是在想找到一种预设寻路算法关键点,减轻寻路算法对服务端压力是看到的一种结构
  • 这个结构比较简单,可以用在游戏的任务模块里面,把任务串成一个有向无环图,然后根据这个图进行拓扑排序,把任务串起来

拓扑排序

  • 看了网上不少代码,不过在明确这个结构可以用在任务模块的情况下,需要的接口大体如下:
  • (从配置表读取后)把任务添加到拓扑结构里
  • 指定某个(些)任务依赖的前置任务是什么
  • 源码基本参考:https://github.com/graphitemaster/dep_sort/tree/master
  • 修改为自己的写法习惯

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#pragma once
#include <unordered_map>
#include <unordered_set>
#include <vector>

/// dep topological sort
namespace easy::utils {

template <class tt> class dep_sort {
public:
struct relation;
using relation_type = relation;

struct result;
using result_type = result;

using value_type = tt;
using map_type = std::unordered_map<value_type, relation_type>;
public:
struct relation {
std::size_t dependencies;
std::unordered_set<value_type> dependents;
};

struct result {
std::vector<value_type> sorted;
std::vector<value_type> non_sorted;

bool has_cycles() const { return non_sorted.empty() == false; }
};

private:
map_type _values;

public:
bool has_node(const value_type& node) {
return _values.contains(node);
}

void clear() { _values.clear(); }

bool add_node(const value_type &node) {
auto res = _values.insert({node, {}});
return res.second;
}

bool add_node(value_type &&node) {
auto res = _values.insert({std::move(node), {}});
return res.second;
}

bool has_dependency(const value_type &node, const value_type &dependency) {
if (!has_node(node))
return false;
const auto &value = _values.at(node);
return value.dependents.find(dependency) != value.dependents.end();
}

bool add_dependency(const value_type &node, value_type &&dependency) {
if (node == dependency)
return false;
auto res_value = _values.insert({std::move(dependency), {}});
auto &dependents = res_value.first->second.dependents;
if (dependents.find(node) == dependents.end()) {
dependents.insert(node);
_values[node].dependencies += 1;
return true;
}
return false;
}

bool add_dependency(const value_type &node, const value_type &dependency) {
if (node == dependency)
return false;
auto res_value = _values.insert({dependency, {}});
auto &dependents = res_value.first->second.dependents;
if (dependents.find(node) == dependents.end()) {
dependents.insert(node);
_values[node].dependencies += 1;
return true;
}
return false;
}

template <template <typename, typename...> class container_tt, typename... container_tt_params>
bool add_dependencies(
const value_type &node,
const container_tt<value_type, container_tt_params...> &dependencies) {
for (const auto &one : dependencies) {
if (!add_dependency(node, one))
return false;
}
return true;
}

result_type sort() const {
auto copyed = *this;
result_type res;
for (const auto &[node, relations] : copyed._values) {
if (relations.dependencies == 0) {
res.sorted.push_back(node);
}
}
for (std::size_t index = 0; index < res.sorted.size(); ++index) {
for (const auto &one : copyed._values[res.sorted.at(index)].dependents) {
if (--copyed._values[one].dependencies == 0) {
res.sorted.push_back(one);
}
}
}
for (const auto &[node, relations] : copyed._values) {
if (relations.dependencies != 0) {
res.non_sorted.push_back(node);
}
}
return res;
}
};
};
  • 图示:

实现过程中关注到的点:

1
2
3
4
5
6
template <template <typename...> class container_tt, typename... container_params>
void test_any_container(const container_tt<std::string, container_params...> &cc) {
for (const auto& one : cc) {
std::cout << one << std::endl;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
template<typename T, typename _ = void>
struct is_container : std::false_type {};

template<typename... Ts>
struct is_container_helper {};

template<typename T>
struct is_container<
T,
std::conditional_t<
false,
is_container_helper<
typename T::value_type,
typename T::size_type,
typename T::allocator_type,
typename T::iterator,
typename T::const_iterator,
decltype(std::declval<T>().size()),
decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end()),
decltype(std::declval<T>().cbegin()),
decltype(std::declval<T>().cend())
>,
void
>
> : public std::true_type {};
  • emplace 并不能完全替代 insert/push 等操作:c++20 之前 emplace 不能进行初始化的聚合,比如 const char* -> std::string,或者构造一个结构体
------ 本文结束 ------
------ 版权声明:转载请注明出处 ------