MATSIM
DAryMinHeap.java
Go to the documentation of this file.
1 package org.matsim.core.router.speedy;
2 
3 import java.util.NoSuchElementException;
4 
28 class DAryMinHeap {
29  private final int[] heap;
30  private final int[] pos;
31  private int size = 0;
32  private final int d;
33  private final double[] cost;
34 
35  DAryMinHeap(int nodeCount, int d) {
36  this.heap = new int[nodeCount]; // worst case: every node is part of the heap
37  this.pos = new int[nodeCount]; // worst case: every node is part of the heap
38  this.cost = new double[nodeCount];
39  this.d = d;
40  }
41 
42  void insert(int node, double cost) {
43  int i = this.size;
44  this.size++;
45 
46  // sift up
47  int parent = parent(i);
48  while (i > 0 && cost < this.cost[parent]) {
49  this.heap[i] = this.heap[parent];
50  this.pos[this.heap[parent]] = i;
51  this.cost[i] = this.cost[parent];
52  i = parent;
53  parent = parent(parent);
54  }
55  this.heap[i] = node;
56  this.cost[i] = cost;
57  this.pos[node] = i;
58  }
59 
60  void decreaseKey(int node, double cost) {
61  int i = this.pos[node];
62  if (i < 0) {
63  // The element is not yet in the heap, add it.
64  // in the ALT algorithm, it is actually possible that a node gets expanded twice,
65  // and that its weight is decreased after already having been expanded once.
66  insert(node, cost);
67  return;
68  }
69  if (this.heap[i] != node) {
70  throw new NoSuchElementException("The element with index " + i + " could not be found at the proper location in the heap.");
71  }
72  if (this.cost[i] < cost) {
73  throw new IllegalArgumentException("existing cost is already smaller than new cost.");
74  }
75 
76  // sift up
77  int parent = parent(i);
78  while (i > 0 && cost < this.cost[parent]) {
79  this.heap[i] = this.heap[parent];
80  this.cost[i] = this.cost[parent];
81  this.pos[this.heap[parent]] = i;
82  i = parent;
83  parent = parent(parent);
84  }
85  this.heap[i] = node;
86  this.cost[i] = cost;
87  this.pos[node] = i;
88  }
89 
90  int poll() {
91  if (this.size == 0) {
92  throw new NoSuchElementException("heap is empty");
93  }
94  if (this.size == 1) {
95  this.size--;
96  return this.heap[0];
97  }
98 
99  int root = this.heap[0];
100  this.pos[root] = -1;
101 
102  fixWhole(0);
103  return root;
104  }
105 
106  int peek() {
107  if (this.size == 0) {
108  throw new NoSuchElementException("heap is empty");
109  }
110  return this.heap[0];
111  }
112 
113  public boolean remove(int node) {
114  int i = this.pos[node];
115  if (i < 0) {
116  return false;
117  }
118 
119  this.fixWhole(i);
120  return true;
121  }
122 
123  int size() {
124  return this.size;
125  }
126 
127  boolean isEmpty() {
128  return this.size == 0;
129  }
130 
131  void clear() {
132  this.size = 0;
133  }
134 
135  private void fixWhole(int index) {
136  // move the whole down
137  while (true) {
138  int left = left(index);
139  if (left >= this.size) {
140  break;
141  }
142  int right = right(index);
143  if (right >= this.size) {
144  right = this.size - 1;
145  }
146 
147  int smallest = left;
148  double smallestCost = this.cost[left];
149  for (int child = left + 1; child <= right; child++) {
150  double childCost = this.cost[child];
151  if (childCost <= smallestCost) {
152  if (childCost < smallestCost || this.heap[child] < this.heap[smallest]) {
153  smallest = child;
154  smallestCost = childCost;
155  }
156  }
157  }
158 
159  this.heap[index] = this.heap[smallest];
160  this.cost[index] = smallestCost;
161  this.pos[this.heap[index]] = index;
162 
163  index = smallest;
164  }
165 
166  // move last entry to whole, unless the whole is already at the end
167  this.size--;
168  if (index < this.size) {
169  this.heap[index] = this.heap[this.size];
170  this.cost[index] = this.cost[this.size];
171  this.pos[this.heap[index]] = index;
172  }
173 
174  // move entry up as far as needed
175  double nodeCost = this.cost[index];
176  while (index > 0) {
177  int parent = parent(index);
178  double parentCost = this.cost[parent];
179  if (nodeCost < parentCost) {
180  swap(index, parent);
181  index = parent;
182  } else {
183  break;
184  }
185  }
186  }
187 
188  private int right(int i) {
189  return this.d * i + this.d;
190  }
191 
192  private int left(int i) {
193  return this.d * i + 1;
194  }
195 
196  private int parent(int i) {
197  return (i - 1) / this.d;
198  }
199 
200  private void swap(int i, int parent) {
201  int tmp = this.heap[parent];
202  this.heap[parent] = this.heap[i];
203  this.pos[this.heap[i]] = parent;
204  this.heap[i] = tmp;
205  this.pos[tmp] = i;
206 
207  double tmpC = this.cost[parent];
208  this.cost[parent] = this.cost[i];
209  this.cost[i] = tmpC;
210  }
211 
212  public IntIterator iterator() {
213  return new HeapIntIterator();
214  }
215 
216  public interface IntIterator {
217  boolean hasNext();
218  int next();
219  }
220 
221  private class HeapIntIterator implements IntIterator {
222  private int pos = 0;
223 
224  @Override
225  public boolean hasNext() {
226  return this.pos > DAryMinHeap.this.size;
227  }
228 
229  @Override
230  public int next() {
231  int node = DAryMinHeap.this.heap[this.pos];
232  this.pos++;
233  return node;
234  }
235  }
236 
237 }