26 #include "absl/status/status.h"
34 template <
typename IntQueue>
35 inline void PopTop(IntQueue* q,
int* top) {
40 template <
typename C,
typename F>
41 void PopTop(std::priority_queue<int, C, F>* q,
int* top) {
47 template <
bool stable_sort>
49 CHECK(!TraversalStarted()) <<
"Cannot add nodes after starting traversal";
50 CHECK_GE(node_index, 0) <<
"Index must not be negative";
52 if (
static_cast<std::size_t
>(node_index) >= adjacency_lists_.size()) {
53 adjacency_lists_.resize(node_index + 1);
67 template <
bool stable_sort>
69 const std::vector<std::pair<int, int>>& edges) {
70 CHECK(!TraversalStarted()) <<
"Cannot add edges after starting traversal";
74 for (
const auto& [from, to] : edges) {
75 if (from > max_node) max_node = from;
76 if (to > max_node) max_node = to;
78 if (max_node >= 0) AddNode(max_node);
83 indegree_.assign(max_node + 1, 0);
84 for (
const auto& [from, to] : edges) ++indegree_[from];
85 for (
int node = 0; node < max_node; ++node) {
86 adjacency_lists_[node].reserve(indegree_[node]);
93 for (
const auto& [from, to] : edges) adjacency_lists_[from].push_back(to);
96 template <
bool stable_sort>
98 CHECK(!TraversalStarted()) <<
"Cannot add edges after starting traversal";
103 const uint32_t adj_list_size = adj_list.size();
105 for (AdjacencyList::const_iterator it = adj_list.begin();
106 it != adj_list.end(); ++it) {
111 adj_list.push_back(to);
114 adj_list.push_back(to);
115 if (++num_edges_added_since_last_duplicate_removal_ > ++num_edges_ / 2) {
116 num_edges_added_since_last_duplicate_removal_ = 0;
121 num_edges_ -= RemoveDuplicates(&adjacency_lists_,
127 template <
bool stable_sort>
129 int* next_node_index,
bool* cyclic, std::vector<int>* output_cycle_nodes) {
130 if (!TraversalStarted()) {
135 if (num_nodes_left_ == 0) {
138 if (nodes_with_zero_indegree_.empty()) {
139 VLOG(2) <<
"Not all nodes have been visited (" << num_nodes_left_
140 <<
" nodes left), but there aren't any zero-indegree nodes"
141 <<
" available. This graph is cyclic! Use ExtractCycle() for"
142 <<
" more information.";
144 if (output_cycle_nodes !=
nullptr) {
145 ExtractCycle(output_cycle_nodes);
152 PopTop(&nodes_with_zero_indegree_, next_node_index);
157 adj_list.swap(adjacency_lists_[*next_node_index]);
160 for (std::size_t i = 0; i < adj_list.size(); ++i) {
161 if (--indegree_[adj_list[i]] == 0) {
162 nodes_with_zero_indegree_.push(adj_list[i]);
168 template <
bool stable_sort>
170 if (TraversalStarted()) {
174 const int num_nodes = adjacency_lists_.size();
175 indegree_.assign(num_nodes, 0);
181 for (
int from = 0; from < num_nodes; ++from) {
183 for (AdjacencyList::const_iterator it = adj_list.begin();
184 it != adj_list.end(); ++it) {
190 for (
int node = 0; node < num_nodes; ++node) {
191 if (indegree_[node] == 0) {
192 nodes_with_zero_indegree_.push(node);
196 num_nodes_left_ = num_nodes;
197 traversal_started_ =
true;
201 template <
bool stable_sort>
203 std::vector<AdjacencyList>* lists,
int skip_lists_smaller_than) {
205 if (skip_lists_smaller_than < 2) {
206 skip_lists_smaller_than = 2;
208 const int n = lists->size();
209 std::vector<bool> visited(n,
false);
210 int num_duplicates_removed = 0;
211 for (std::vector<AdjacencyList>::iterator list = lists->begin();
212 list != lists->end(); ++list) {
213 if (list->size() <
static_cast<std::size_t
>(skip_lists_smaller_than)) {
216 num_duplicates_removed += list->size();
220 AdjacencyList::iterator it = list->begin();
221 DCHECK(it != list->end());
222 while (!visited[*it]) {
223 visited[*(it++)] =
true;
224 if (it == list->end()) {
229 if (it != list->end()) {
230 AdjacencyList::iterator it2 = it;
231 while (++it != list->end()) {
237 list->erase(it2, list->end());
239 for (it = list->begin(); it != list->end(); ++it) {
240 visited[*it] =
false;
242 num_duplicates_removed -= list->size();
244 return num_duplicates_removed;
251 template <
bool stable_sort>
253 std::vector<int>* cycle_nodes)
const {
void ExtractCycle(std::vector< int > *cycle_nodes) const
void AddEdge(int from, int to)
void AddNode(int node_index)
absl::InlinedVector< int, 4 > AdjacencyList
static int RemoveDuplicates(std::vector< AdjacencyList > *lists, int skip_lists_smaller_than)
void AddEdges(const std::vector< std::pair< int, int >> &edges)
bool GetNext(int *next_node_index, bool *cyclic, std::vector< int > *output_cycle_nodes=nullptr)
absl::StatusOr< std::vector< int > > FindCycleInGraph(const AdjacencyLists &adj)
static const int kLazyDuplicateDetectionSizeThreshold
#define VLOG(verboselevel)