31template <
typename IntQueue>
32inline void PopTop(IntQueue* q,
int* top) {
37template <
typename C,
typename F>
38void PopTop(std::priority_queue<int, C, F>* q,
int* top) {
44template <
bool stable_sort>
46 CHECK(!TraversalStarted()) <<
"Cannot add nodes after starting traversal";
47 CHECK_GE(node_index, 0) <<
"Index must not be negative";
49 if (
static_cast<std::size_t
>(node_index) >= adjacency_lists_.size()) {
50 adjacency_lists_.resize(node_index + 1);
64template <
bool stable_sort>
66 CHECK(!TraversalStarted()) <<
"Cannot add edges after starting traversal";
71 const uint32_t adj_list_size = adj_list.size();
73 for (AdjacencyList::const_iterator it = adj_list.begin();
74 it != adj_list.end(); ++it) {
79 adj_list.push_back(to);
82 adj_list.push_back(to);
83 if (++num_edges_added_since_last_duplicate_removal_ > ++num_edges_ / 2) {
84 num_edges_added_since_last_duplicate_removal_ = 0;
89 num_edges_ -= RemoveDuplicates(&adjacency_lists_,
95template <
bool stable_sort>
97 int* next_node_index,
bool* cyclic, std::vector<int>* output_cycle_nodes) {
98 if (!TraversalStarted()) {
103 if (num_nodes_left_ == 0) {
106 if (nodes_with_zero_indegree_.empty()) {
107 VLOG(2) <<
"Not all nodes have been visited (" << num_nodes_left_
108 <<
" nodes left), but there aren't any zero-indegree nodes"
109 <<
" available. This graph is cyclic! Use ExtractCycle() for"
110 <<
" more information.";
112 if (output_cycle_nodes !=
nullptr) {
113 ExtractCycle(output_cycle_nodes);
120 PopTop(&nodes_with_zero_indegree_, next_node_index);
125 adj_list.swap(adjacency_lists_[*next_node_index]);
128 for (std::size_t i = 0; i < adj_list.size(); ++i) {
129 if (--indegree_[adj_list[i]] == 0) {
130 nodes_with_zero_indegree_.push(adj_list[i]);
136template <
bool stable_sort>
138 if (TraversalStarted()) {
142 const int num_nodes = adjacency_lists_.size();
143 indegree_.assign(num_nodes, 0);
149 for (
int from = 0; from < num_nodes; ++from) {
151 for (AdjacencyList::const_iterator it = adj_list.begin();
152 it != adj_list.end(); ++it) {
158 for (
int node = 0; node < num_nodes; ++node) {
159 if (indegree_[node] == 0) {
160 nodes_with_zero_indegree_.push(node);
164 num_nodes_left_ = num_nodes;
165 traversal_started_ =
true;
169template <
bool stable_sort>
171 std::vector<AdjacencyList>* lists,
int skip_lists_smaller_than) {
173 if (skip_lists_smaller_than < 2) {
174 skip_lists_smaller_than = 2;
176 const int n = lists->size();
177 std::vector<bool> visited(n,
false);
178 int num_duplicates_removed = 0;
179 for (std::vector<AdjacencyList>::iterator list = lists->begin();
180 list != lists->end(); ++list) {
181 if (list->size() <
static_cast<std::size_t
>(skip_lists_smaller_than)) {
184 num_duplicates_removed += list->size();
188 AdjacencyList::iterator it = list->begin();
189 DCHECK(it != list->end());
190 while (!visited[*it]) {
191 visited[*(it++)] =
true;
192 if (it == list->end()) {
197 if (it != list->end()) {
198 AdjacencyList::iterator it2 = it;
199 while (++it != list->end()) {
205 list->erase(it2, list->end());
207 for (it = list->begin(); it != list->end(); ++it) {
208 visited[*it] =
false;
210 num_duplicates_removed -= list->size();
212 return num_duplicates_removed;
219template <
bool stable_sort>
221 std::vector<int>* cycle_nodes)
const {
222 const int num_nodes = adjacency_lists_.size();
223 cycle_nodes->clear();
228 std::vector<bool> no_cycle_reachable_from(num_nodes,
false);
234 std::size_t adj_list_index;
235 explicit DfsState(
int _node) : node(_node), adj_list_index(0) {}
237 std::vector<DfsState> dfs_stack;
238 std::vector<bool> in_cur_stack(num_nodes,
false);
239 for (
int start_node = 0; start_node < num_nodes; ++start_node) {
240 if (no_cycle_reachable_from[start_node]) {
244 dfs_stack.push_back(DfsState(start_node));
245 in_cur_stack[start_node] =
true;
246 while (!dfs_stack.empty()) {
247 DfsState* cur_state = &dfs_stack.back();
248 if (cur_state->adj_list_index >=
249 adjacency_lists_[cur_state->node].size()) {
250 no_cycle_reachable_from[cur_state->node] =
true;
251 in_cur_stack[cur_state->node] =
false;
252 dfs_stack.pop_back();
258 adjacency_lists_[cur_state->node][cur_state->adj_list_index];
259 ++(cur_state->adj_list_index);
260 if (no_cycle_reachable_from[child]) {
263 if (in_cur_stack[child]) {
266 cycle_nodes->push_back(dfs_stack.back().node);
267 if (dfs_stack.back().node == child) {
268 std::reverse(cycle_nodes->begin(), cycle_nodes->end());
271 dfs_stack.pop_back();
275 dfs_stack.push_back(DfsState(child));
276 in_cur_stack[child] =
true;
292 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
293 std::vector<int> cycle;
298 for (
const auto&
arc : arcs) {
#define CHECK_GE(val1, val2)
#define DCHECK(condition)
#define VLOG(verboselevel)
void ExtractCycle(std::vector< int > *cycle_nodes) const
void AddEdge(int from, int to)
void AddNode(int node_index)
std::vector< int > AdjacencyList
static const int kLazyDuplicateDetectionSizeThreshold
std::vector< int > FindCycleInDenseIntGraph(int num_nodes, const std::vector< std::pair< int, int > > &arcs)