// Copyright 2010-2018 Google LLC // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef OR_TOOLS_ALGORITHMS_DENSE_DOUBLY_LINKED_LIST_H_ #define OR_TOOLS_ALGORITHMS_DENSE_DOUBLY_LINKED_LIST_H_ #include #include "ortools/base/logging.h" namespace operations_research { // Specialized doubly-linked list that initially holds [0..n-1] in an arbitrary // (user-specified) and fixed order. // It then supports O(1) removal and access to the next and previous element of // a given (non-removed) element. // // It is very fast and compact: it uses exactly 8*n bytes of memory. class DenseDoublyLinkedList { public: // You can construct a DenseDoublyLinkedList with any range-iterable class // that also has a size() method. The order of the elements is given by the // user and will never change (modulo the removal of elements). template explicit DenseDoublyLinkedList(const T& sorted_elements); int Size() const { return next_.size(); } // Next() (resp. Prev()) must be called on elements that haven't yet been // removed. They will return -1 if called on the last (resp. first) element. int Next(int i) const; int Prev(int i) const; // You must not call Remove() twice with the same element. void Remove(int i); private: std::vector next_; std::vector prev_; }; // Inline implementations (forced inline for the speed). inline int DenseDoublyLinkedList::Next(int i) const { DCHECK_GE(i, 0); DCHECK_LT(i, Size()); DCHECK_GE(next_[i], -1); return next_[i]; } inline int DenseDoublyLinkedList::Prev(int i) const { DCHECK_GE(i, 0); DCHECK_LT(i, Size()); DCHECK_GE(prev_[i], -1); return prev_[i]; } inline void DenseDoublyLinkedList::Remove(int i) { const int prev = Prev(i); const int next = Next(i); if (prev >= 0) next_[prev] = next; if (next >= 0) prev_[next] = prev; if (DEBUG_MODE) next_[i] = prev_[i] = -2; // To catch bugs. } template DenseDoublyLinkedList::DenseDoublyLinkedList(const T& elements) : next_(elements.size(), -2), prev_(elements.size(), -2) { int last = -1; for (const int e : elements) { DCHECK_GE(e, 0); DCHECK_LE(e, Size()); DCHECK_EQ(-2, prev_[e]) << "Duplicate element: " << e; prev_[e] = last; if (last >= 0) next_[last] = e; last = e; } if (!elements.empty()) next_[elements.back()] = -1; if (DEBUG_MODE) { for (int p : prev_) DCHECK_NE(-2, p); for (int n : next_) DCHECK_NE(-2, n); } } } // namespace operations_research #endif // OR_TOOLS_ALGORITHMS_DENSE_DOUBLY_LINKED_LIST_H_