26#include "absl/status/status.h"
27#include "absl/types/span.h"
35template <
typename IntQueue>
36inline void PopTop(IntQueue* q,
int* top) {
41template <
typename C,
typename F>
42void PopTop(std::priority_queue<int, C, F>* q,
int* top) {
48template <
bool stable_sort>
50 CHECK(!TraversalStarted()) <<
"Cannot add nodes after starting traversal";
51 CHECK_GE(node_index, 0) <<
"Index must not be negative";
53 if (
static_cast<std::size_t
>(node_index) >= adjacency_lists_.size()) {
54 adjacency_lists_.resize(node_index + 1);
68template <
bool stable_sort>
70 absl::Span<
const std::pair<int, int>> edges) {
71 CHECK(!TraversalStarted()) <<
"Cannot add edges after starting traversal";
75 for (
const auto& [from,
to] : edges) {
76 if (from > max_node) max_node = from;
77 if (
to > max_node) max_node =
to;
79 if (max_node >= 0) AddNode(max_node);
84 indegree_.assign(max_node + 1, 0);
85 for (
const auto& [from,
to] : edges) ++indegree_[from];
86 for (
int node = 0; node < max_node; ++node) {
87 adjacency_lists_[node].reserve(indegree_[node]);
94 for (
const auto& [from,
to] : edges) adjacency_lists_[from].push_back(
to);
97template <
bool stable_sort>
99 CHECK(!TraversalStarted()) <<
"Cannot add edges after starting traversal";
101 AddNode(std::max(from,
to));
104 const uint32_t adj_list_size = adj_list.size();
106 for (AdjacencyList::const_iterator it = adj_list.begin();
107 it != adj_list.end(); ++it) {
112 adj_list.push_back(
to);
115 adj_list.push_back(
to);
116 if (++num_edges_added_since_last_duplicate_removal_ > ++num_edges_ / 2) {
117 num_edges_added_since_last_duplicate_removal_ = 0;
122 num_edges_ -= RemoveDuplicates(&adjacency_lists_,
128template <
bool stable_sort>
130 int* next_node_index,
bool* cyclic, std::vector<int>* output_cycle_nodes) {
131 if (!TraversalStarted()) {
136 if (num_nodes_left_ == 0) {
139 if (nodes_with_zero_indegree_.empty()) {
140 VLOG(2) <<
"Not all nodes have been visited (" << num_nodes_left_
141 <<
" nodes left), but there aren't any zero-indegree nodes"
142 <<
" available. This graph is cyclic! Use ExtractCycle() for"
143 <<
" more information.";
145 if (output_cycle_nodes !=
nullptr) {
146 ExtractCycle(output_cycle_nodes);
153 PopTop(&nodes_with_zero_indegree_, next_node_index);
158 adj_list.swap(adjacency_lists_[*next_node_index]);
161 for (std::size_t i = 0; i < adj_list.size(); ++i) {
162 if (--indegree_[adj_list[i]] == 0) {
163 nodes_with_zero_indegree_.push(adj_list[i]);
169template <
bool stable_sort>
171 if (TraversalStarted()) {
175 const int num_nodes = adjacency_lists_.size();
176 indegree_.assign(num_nodes, 0);
182 for (
int from = 0; from < num_nodes; ++from) {
184 for (AdjacencyList::const_iterator it = adj_list.begin();
185 it != adj_list.end(); ++it) {
191 for (
int node = 0; node < num_nodes; ++node) {
192 if (indegree_[node] == 0) {
193 nodes_with_zero_indegree_.push(node);
197 num_nodes_left_ = num_nodes;
198 traversal_started_ =
true;
202template <
bool stable_sort>
204 std::vector<AdjacencyList>* lists,
int skip_lists_smaller_than) {
206 if (skip_lists_smaller_than < 2) {
207 skip_lists_smaller_than = 2;
209 const int n = lists->size();
210 std::vector<bool> visited(n,
false);
211 int num_duplicates_removed = 0;
212 for (std::vector<AdjacencyList>::iterator list = lists->begin();
213 list != lists->end(); ++list) {
214 if (list->size() <
static_cast<std::size_t
>(skip_lists_smaller_than)) {
217 num_duplicates_removed += list->size();
221 AdjacencyList::iterator it = list->begin();
222 DCHECK(it != list->end());
223 while (!visited[*it]) {
224 visited[*(it++)] =
true;
225 if (it == list->end()) {
230 if (it != list->end()) {
231 AdjacencyList::iterator it2 = it;
232 while (++it != list->end()) {
238 list->erase(it2, list->end());
240 for (it = list->begin(); it != list->end(); ++it) {
241 visited[*it] =
false;
243 num_duplicates_removed -= list->size();
245 return num_duplicates_removed;
252template <
bool stable_sort>
254 std::vector<int>* cycle_nodes)
const {
static int RemoveDuplicates(std::vector< AdjacencyList > *lists, int skip_lists_smaller_than)
static
void AddNode(int node_index)
void AddEdge(int from, int to)
void AddEdges(absl::Span< const std::pair< int, int > > edges)
Performs AddEdge() in bulk. Much faster if you add all edges at once.
absl::InlinedVector< int, 4 > AdjacencyList
To store the adjacency lists efficiently.
bool GetNext(int *next_node_index, bool *cyclic, std::vector< int > *output_cycle_nodes=nullptr)
void ExtractCycle(std::vector< int > *cycle_nodes) const
To extract a cycle. When there is no cycle, cycle_nodes will be empty.
absl::StatusOr< std::vector< int > > FindCycleInGraph(const AdjacencyLists &adj)
static const int kLazyDuplicateDetectionSizeThreshold
A collections of i/o utilities for the Graph classes in ./graph.h.
trees with all degrees equal to