3 Copyright (c) 2003-2004 Niels Kokholm <kokholm@itu.dk> and Peter Sestoft <sestoft@dina.kvl.dk>
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 using System
.Diagnostics
;
25 using MSG
= System
.Collections
.Generic
;
30 /// A priority queue class based on an interval heap data structure.
32 public class IntervalHeap
<T
>: CollectionValueBase
<T
>, IPriorityQueue
<T
>
37 internal T first
, last
;
40 public override string ToString() { return String.Format("[{0}
; {1}
]", first, last); }
45 object syncroot = new object();
49 IComparer<T> comparer;
57 void heapifyMin(int i)
60 T pv = heap[j].first, min = pv;
64 int l = 2 * j + 1, r = l + 1;
67 if (2 * l < size && comparer.Compare(lv = heap[l].first, min) < 0) { minpt = l; min = lv; }
69 if (2 * r < size && comparer.Compare(rv = heap[r].first, min) < 0) { minpt = r; min = rv; }
74 other = heap[minpt].last;
76 if (2 * minpt + 1 < size && comparer.Compare(pv, other) > 0)
77 { heap[minpt].last = pv; pv = other; }
84 heap[minpt].first = min;
88 void heapifyMax(int i)
91 T pv = heap[j].last, max = pv;
95 int l = 2 * j + 1, r = l + 1;
98 if (2 * l + 1 < size && comparer.Compare(lv = heap[l].last, max) > 0) { maxpt = l; max = lv; }
100 if (2 * r + 1 < size && comparer.Compare(rv = heap[r].last, max) > 0) { maxpt = r; max = rv; }
105 other = heap[maxpt].first;
107 if (comparer.Compare(pv, other) < 0)
109 heap[maxpt].first = pv;
118 heap[maxpt].last = max;
122 void bubbleUpMin(int i)
126 T min = heap[i].first, iv = min;
127 int p = (i + 1) / 2 - 1;
131 if (comparer.Compare(iv, min = heap[p = (i + 1) / 2 - 1].first) < 0)
133 heap[i].first = min; min = iv;
145 void bubbleUpMax(int i)
149 T max = heap[i].last, iv = max;
150 int p = (i + 1) / 2 - 1;
154 if (comparer.Compare(iv, max = heap[p = (i + 1) / 2 - 1].last) > 0)
156 heap[i].last = max; max = iv;
171 /// Create an interval heap with natural item comparer and default initial capacity (16)
173 public IntervalHeap() : this(16) { }
177 /// Create an interval heap with external item comparer and default initial capacity (16)
179 /// <param name="c
">The external comparer</param>
180 public IntervalHeap(IComparer<T> c) : this(c,16) { }
184 /// Create an interval heap with natural item comparer and prescribed initial capacity
186 /// <param name="capacity
">The initial capacity</param>
187 public IntervalHeap(int capacity) : this(ComparerBuilder.FromComparable<T>.Examine(),capacity) { }
191 /// Create an interval heap with external item comparer and prescribed initial capacity
193 /// <param name="c
">The external comparer</param>
194 /// <param name="capacity
">The initial capacity</param>
195 public IntervalHeap(IComparer<T> c, int capacity)
201 while (length < capacity) length <<= 1;
203 heap = new Interval[length];
207 #region IPriorityQueue<T> Members
210 /// Find the current least item of this priority queue.
211 /// <exception cref="InvalidOperationException
"/> if queue is empty
213 /// <returns>The least item.</returns>
218 throw new InvalidOperationException("Heap
is empty
");
220 return heap[0].first;
225 /// Remove the least item from this priority queue.
226 /// <exception cref="InvalidOperationException
"/> if queue is empty
228 /// <returns>The removed item.</returns>
234 throw new InvalidOperationException("Heap
is empty
");
236 T retval = heap[0].first;;
240 heap[0].first = default(T);
244 int ind = (size - 1) / 2;
248 heap[0].first = heap[ind].last;
249 heap[ind].last = default(T);
253 heap[0].first = heap[ind].first;
254 heap[ind].first = default(T);
266 /// Find the current largest item of this priority queue.
267 /// <exception cref="InvalidOperationException
"/> if queue is empty
269 /// <returns>The largest item.</returns>
274 throw new InvalidOperationException("Heap
is empty
");
276 return heap[0].first;
283 /// Remove the largest item from this priority queue.
284 /// <exception cref="InvalidOperationException
"/> if queue is empty
286 /// <returns>The removed item.</returns>
292 throw new InvalidOperationException("Heap
is empty
");
299 retval = heap[0].first;
300 heap[0].first = default(T);
305 retval = heap[0].last;
307 int ind = (size - 1) / 2;
311 heap[0].last = heap[ind].last;
312 heap[ind].last = default(T);
316 heap[0].last = heap[ind].first;
317 heap[ind].first = default(T);
328 /// The comparer object supplied at creation time for this collection
330 /// <value>The comparer</value>
331 public IComparer<T> Comparer { get { return comparer; } }
335 #region ISink<T> Members
340 /// <value>True since this collection has bag semantics</value>
342 public bool AllowsDuplicates { [Tested]get { return true; } }
348 /// <value>The distinguished object to use for locking to synchronize multithreaded access</value>
350 public object SyncRoot { [Tested]get { return syncroot; } }
356 /// <value>True if this collection is empty.</value>
358 public bool IsEmpty { [Tested]get { return size == 0; } }
362 /// Add an item to this priority queue.
364 /// <param name="item
">The item to add.</param>
365 /// <returns>True</returns>
367 public bool Add(T item)
373 heap[0].first = item;
377 if (size == 2 * heap.Length)
379 Interval[] newheap = new Interval[2 * heap.Length];
381 Array.Copy(heap, newheap, heap.Length);
387 int i = size / 2, p = (i + 1) / 2 - 1;
391 if (comparer.Compare(item, tmp = heap[p].last) > 0)
399 heap[i].first = item;
400 if (comparer.Compare(item, heap[p].first) < 0)
407 T other = heap[i].first;
410 if (comparer.Compare(item, other) < 0)
412 heap[i].first = item;
413 heap[i].last = other;
428 /// Add the elements from another collection to this collection.
430 /// <param name="items
">The items to add.</param>
432 public void AddAll(MSG.IEnumerable<T> items)
434 //TODO: avoid incrementing stamp repeatedly
435 foreach (T item in items)
440 /// Add the elements from another collection with a more specialized item type
441 /// to this collection.
443 /// <typeparam name="U
">The type of items to add</typeparam>
444 /// <param name="items
">The items to add</param>
445 public void AddAll<U>(MSG.IEnumerable<U> items) where U : T
447 //TODO: avoid incrementing stamp repeatedly
448 foreach (T item in items)
454 #region ICollection<T> members
458 /// <value>The size of this collection</value>
460 public override int Count { [Tested]get { return size; } }
464 /// The value is symbolic indicating the type of asymptotic complexity
465 /// in terms of the size of this collection (worst-case or amortized as
468 /// <value>A characterization of the speed of the
469 /// <code>Count</code> property in this collection.</value>
470 public override Speed CountSpeed { get { return Speed.Constant; } }
473 /// Create an enumerator for the collection
474 /// <para>Note: the enumerator does *not* enumerate the items in sorted order,
475 /// but in the internal table order.</para>
477 /// <returns>The enumerator(SIC)</returns>
479 public override MSG.IEnumerator<T> GetEnumerator()
482 for (int i = 0; i < size; i++)
484 if (mystamp != stamp) throw new InvalidOperationException();
485 yield return i % 2 == 0 ? heap[i >> 1].first : heap[i >> 1].last;
495 private bool check(int i, T min, T max)
498 Interval interval = heap[i];
499 T first = interval.first, last = interval.last;
501 if (2 * i + 1 == size)
503 if (comparer.Compare(min, first) > 0)
505 Console.WriteLine("Cell {0}
: parent
.first({1}
) > first({2}
) [size
={3}
]", i, min, first, size);
509 if (comparer.Compare(first, max) > 0)
511 Console.WriteLine("Cell {0}
: first({1}
) > parent
.last({2}
) [size
={3}
]", i, first, max, size);
519 if (comparer.Compare(min, first) > 0)
521 Console.WriteLine("Cell {0}
: parent
.first({1}
) > first({2}
) [size
={3}
]", i, min, first, size);
525 if (comparer.Compare(first, last) > 0)
527 Console.WriteLine("Cell {0}
: first({1}
) > last({2}
) [size
={3}
]", i, first, last, size);
531 if (comparer.Compare(last, max) > 0)
533 Console.WriteLine("Cell {0}
: last({1}
) > parent
.last({2}
) [size
={3}
]", i, last, max, size);
537 int l = 2 * i + 1, r = l + 1;
540 retval = retval && check(l, first, last);
543 retval = retval && check(r, first, last);
551 /// Check the integrity of the internal data structures of this collection.
552 /// Only avaliable in DEBUG builds???
554 /// <returns>True if check does not fail.</returns>
562 return (object)(heap[0].first) != null;
564 return check(0, heap[0].first, heap[0].last);