Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
integer_pq.h
Go to the documentation of this file.
1// Copyright 2010-2024 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 <functional>
27#include <vector>
28
30
31namespace 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.
36template <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) {
89 DCHECK(Contains(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_
IntegerValue size
IntegerPriorityQueue(int n=0, Compare comp=Compare())
Starts with an empty queue and reserve space for n elements.
Definition integer_pq.h:40
void IncreasePriority(Element element)
Optimized version of ChangePriority() when we know the direction.
Definition integer_pq.h:116
int Size() const
Returns the number of elements currently present.
Definition integer_pq.h:56
Element GetElement(int index) const
Returns the element with given index.
Definition integer_pq.h:124
bool Contains(int index) const
Returns true if the element with given index is currently in the queue.
Definition integer_pq.h:67
int index
In SWIG mode, we don't want anything besides these top-level includes.