OR-Tools  8.1
integer_pq.h
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 // This file contains and adjustable priority queue templated by an Element
15 // class that must:
16 // - Be efficiently copiable and storable in a std::vector<Element>.
17 // - Be comparable via the templated Compare class. Top() will returns
18 // the element with the largest priority (like std::priority_queue).
19 // - Implements the "int Index() const" function that must returns an integer
20 // that uniquely identify this particular element. Ideally this index must
21 // be dense in [0, max_num_elements).
22 //
23 #ifndef OR_TOOLS_UTIL_INTEGER_PQ_H_
24 #define OR_TOOLS_UTIL_INTEGER_PQ_H_
25 
26 #include <vector>
27 
28 #include "ortools/base/logging.h"
29 #include "ortools/base/macros.h"
30 
31 namespace operations_research {
32 
33 // Classic asjustable priority queue implementation. It behaves exactly the same
34 // as AdjustablePriorityQueue regarding identical elements, but it uses less
35 // memory and is in general slightly faster.
36 template <typename Element, class Compare = std::less<Element>>
38  public:
39  // Starts with an empty queue and reserve space for n elements.
40  explicit IntegerPriorityQueue(int n = 0, Compare comp = Compare())
41  : size_(0), less_(comp) {
42  Reserve(n);
43  }
44 
45  // Increases the space reservation to n elements indices in [0, n). All
46  // elements passed to the other functions must have an Index() smaller than
47  // this n.
48  void Reserve(int n) {
49  // The heap_ starts at 1 for faster left/right child indices computation.
50  // This also allow us to use position 0 for element not in the queue.
51  heap_.resize(n + 1);
52  position_.resize(n, 0);
53  }
54 
55  // Returns the number of elements currently present.
56  int Size() const { return size_; }
57  bool IsEmpty() const { return size_ == 0; }
58 
59  // Removes all elements from the queue.
60  // TODO(user): we could make this sparse if it is needed.
61  void Clear() {
62  size_ = 0;
63  position_.assign(position_.size(), 0);
64  }
65 
66  // Returns true if the element with given index is currently in the queue.
67  bool Contains(int index) const { return position_[index] != 0; }
68 
69  // Adds the given element to the queue and set its priority.
70  // Preconditions: Contains(element) must be false.
71  void Add(Element element) {
72  DCHECK(!Contains(element.Index()));
73  SetAndIncreasePriority(++size_, element);
74  }
75 
76  // Top() returns the top element and Pop() remove it from the queue.
77  // Preconditions: IsEmpty() must be false.
78  Element Top() const { return heap_[1]; }
79  void Pop() {
80  DCHECK(!IsEmpty());
81  position_[Top().Index()] = 0;
82  const int old_size = size_--;
83  if (old_size > 1) SetAndDecreasePriority(1, heap_[old_size]);
84  }
85 
86  // Removes the element with given index from the queue.
87  // Preconditions: Contains(index) must be true.
88  void Remove(int index) {
90  const int to_replace = position_[index];
91  position_[index] = 0;
92  const int old_size = size_--;
93  if (to_replace == old_size) return;
94  const Element element = heap_[old_size];
95  if (less_(element, heap_[to_replace])) {
96  SetAndDecreasePriority(to_replace, element);
97  } else {
98  SetAndIncreasePriority(to_replace, element);
99  }
100  }
101 
102  // Change the priority of the given element and adjust the queue.
103  //
104  // Preconditions: Contains(element) must be true.
105  void ChangePriority(Element element) {
106  DCHECK(Contains(element.Index()));
107  const int i = position_[element.Index()];
108  if (i > 1 && less_(heap_[i >> 1], element)) {
109  SetAndIncreasePriority(i, element);
110  } else {
111  SetAndDecreasePriority(i, element);
112  }
113  }
114 
115  // Optimized version of ChangePriority() when we know the direction.
116  void IncreasePriority(Element element) {
117  SetAndIncreasePriority(position_[element.Index()], element);
118  }
119  void DecreasePriority(Element element) {
120  SetAndDecreasePriority(position_[element.Index()], element);
121  }
122 
123  // Returns the element with given index.
124  Element GetElement(int index) const { return heap_[position_[index]]; }
125 
126  // For i in [0, Size()) returns an element currently in the queue.
127  // This can be used to get a random element from the queue for instance.
128  Element QueueElement(int i) const { return heap_[1 + i]; }
129 
130  private:
131  // Puts the given element at heap index i.
132  void Set(int i, Element element) {
133  heap_[i] = element;
134  position_[element.Index()] = i;
135  }
136 
137  // Puts the given element at heap index i and update the heap knowing that the
138  // element has a priority <= than the priority of the element currently at
139  // this position.
140  void SetAndDecreasePriority(int i, const Element element) {
141  const int size = size_;
142  while (true) {
143  const int left = i * 2;
144  const int right = left + 1;
145  if (right > size) {
146  if (left > size) break;
147  const Element left_element = heap_[left];
148  if (!less_(element, left_element)) break;
149  Set(i, left_element);
150  i = left;
151  break;
152  }
153  const Element left_element = heap_[left];
154  const Element right_element = heap_[right];
155  if (less_(left_element, right_element)) {
156  if (!less_(element, right_element)) break;
157  Set(i, right_element);
158  i = right;
159  } else {
160  if (!less_(element, left_element)) break;
161  Set(i, left_element);
162  i = left;
163  }
164  }
165  Set(i, element);
166  }
167 
168  // Puts the given element at heap index i and update the heap knowing that the
169  // element has a priority >= than the priority of the element currently at
170  // this position.
171  void SetAndIncreasePriority(int i, const Element element) {
172  while (i > 1) {
173  const int parent = i >> 1;
174  const Element parent_element = heap_[parent];
175  if (!less_(parent_element, element)) break;
176  Set(i, parent_element);
177  i = parent;
178  }
179  Set(i, element);
180  }
181 
182  int size_;
183  Compare less_;
184  std::vector<Element> heap_;
185  std::vector<int> position_;
186 };
187 
188 } // namespace operations_research
189 
190 #endif // OR_TOOLS_UTIL_INTEGER_PQ_H_
operations_research::IntegerPriorityQueue::DecreasePriority
void DecreasePriority(Element element)
Definition: integer_pq.h:119
operations_research::IntegerPriorityQueue::Size
int Size() const
Definition: integer_pq.h:56
operations_research::IntegerPriorityQueue::IncreasePriority
void IncreasePriority(Element element)
Definition: integer_pq.h:116
operations_research::IntegerPriorityQueue::GetElement
Element GetElement(int index) const
Definition: integer_pq.h:124
logging.h
operations_research::IntegerPriorityQueue
Definition: integer_pq.h:37
operations_research::IntegerPriorityQueue::Clear
void Clear()
Definition: integer_pq.h:61
macros.h
operations_research::IntegerPriorityQueue::Contains
bool Contains(int index) const
Definition: integer_pq.h:67
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
operations_research::IntegerPriorityQueue::Top
Element Top() const
Definition: integer_pq.h:78
operations_research::IntegerPriorityQueue::IsEmpty
bool IsEmpty() const
Definition: integer_pq.h:57
index
int index
Definition: pack.cc:508
operations_research::IntegerPriorityQueue::IntegerPriorityQueue
IntegerPriorityQueue(int n=0, Compare comp=Compare())
Definition: integer_pq.h:40
operations_research::IntegerPriorityQueue::Reserve
void Reserve(int n)
Definition: integer_pq.h:48
DCHECK
#define DCHECK(condition)
Definition: base/logging.h:884
operations_research::Set
Definition: hamiltonian_path.h:127
operations_research::IntegerPriorityQueue::QueueElement
Element QueueElement(int i) const
Definition: integer_pq.h:128
operations_research::IntegerPriorityQueue::Remove
void Remove(int index)
Definition: integer_pq.h:88
operations_research::IntegerPriorityQueue::Add
void Add(Element element)
Definition: integer_pq.h:71
operations_research::IntegerPriorityQueue::ChangePriority
void ChangePriority(Element element)
Definition: integer_pq.h:105
operations_research::IntegerPriorityQueue::Pop
void Pop()
Definition: integer_pq.h:79