fork download
  1. import java.util.AbstractQueue;
  2. import java.util.Iterator;
  3. import java.util.Random;
  4.  
  5. import java.util.NoSuchElementException;
  6.  
  7. import static java.lang.Math.min;
  8. import static java.lang.Math.max;
  9.  
  10. class MaxDaryHeap<T extends Comparable<? super T>>
  11. extends AbstractQueue<T> {
  12. private static final int MIN_HEIGHT = 1;
  13.  
  14. // unlike the binary heap implementation this d-ary heap
  15. // does not add an additional null element on the 0-th place
  16. // in the array, thus, the greatest element of the queue is
  17. // stored in the data[0]
  18. private T[] data;
  19. private int size;
  20. // the arity of the heap (how many children does each node have)
  21. private final int d;
  22.  
  23. /**
  24.   * Create a d-ary heap with arity {@code d}.
  25.   * @throws IllegalArgumentException in case the arity {@code d} is
  26.   * less than 2.
  27.   */
  28. @SuppressWarnings("unchecked")
  29. public MaxDaryHeap(int d) {
  30. if (d < 2) {
  31. throw new IllegalArgumentException(String.format("Expected: d >= 2."
  32. + " Got: d = %d.", d));
  33. }
  34. this.d = d;
  35. // size = d^0 + d^1 + ... + d^h = (d^(h + 1) - 1) / (d - 1)
  36. int dataLength = pow(d, MIN_HEIGHT + 1) / (d - 1);
  37. data = (T[]) new Comparable<?>[dataLength];
  38. size = 0;
  39. }
  40.  
  41. @SuppressWarnings("unchecked")
  42. private MaxDaryHeap(T[] data, int size, int d) {
  43. T[] copiedData = (T[]) new Comparable<?>[data.length];
  44. System.arraycopy(data, 0, copiedData, 0, data.length);
  45. this.data = copiedData;
  46. this.size = size;
  47. this.d = d;
  48. }
  49.  
  50. /**
  51.   * Inserts the specified value into the queue.
  52.   * @throws NullPointerException in case the {@code null} element
  53.   * is inserted.
  54.   */
  55. @Override
  56. public boolean offer(T value) {
  57. if (value == null) {
  58. "Null elements are not allowed"
  59. );
  60. }
  61. grow(1);
  62. size++;
  63. data[size - 1] = value;
  64. swim(size - 1);
  65. return true;
  66. }
  67.  
  68. @Override
  69. /**
  70.   * Retrieves but does not remove the max element stored in the queue.
  71.   */
  72. public T peek() {
  73. if (size == 0) {
  74. throw new NoSuchElementException("The heap is empty");
  75. }
  76. return data[0];
  77. }
  78.  
  79. @Override
  80. /**
  81.   * Retrieves and removes the max element stored in the queue.
  82.   */
  83. public T poll() {
  84. if (size == 0) {
  85. throw new NoSuchElementException("The heap is empty");
  86. }
  87. T value = data[0];
  88. data[0] = null;
  89. size--;
  90.  
  91. if (size > 0) {
  92. data[0] = data[size];
  93. sink(0);
  94. }
  95.  
  96. // `true` for only a single element removed from the queue
  97. shrink(true);
  98. return value;
  99. }
  100.  
  101. @Override
  102. public boolean isEmpty() {
  103. return size == 0;
  104. }
  105.  
  106. @Override
  107. public int size() {
  108. return size;
  109. }
  110.  
  111. @Override
  112. public Iterator<T> iterator() {
  113. return new QueueIterator();
  114. }
  115.  
  116. private void swim(int i) {
  117. assert i >= 0 && i < size;
  118.  
  119. while (i > 0 && less(data, (i - 1) / d, i)) {
  120. swap(data, (i - 1) / d, i);
  121. i = (i - 1) / d;
  122. }
  123. }
  124.  
  125. private void sink(int index) {
  126. assert index >= 0 && index < size;
  127.  
  128. while (index * d + 1 < size) {
  129. int iMaxChild = index * d + 1;
  130. int upperBound = min(size, (index + 1) * d + 1);
  131. for (int i = 2; index * d + i < upperBound; i++) {
  132. if (less(data, iMaxChild, index * d + i)) {
  133. iMaxChild = index * d + i;
  134. }
  135. }
  136. if (!less(data, index, iMaxChild)) {
  137. break;
  138. }
  139. swap(data, index, iMaxChild);
  140. index = iMaxChild;
  141. }
  142. }
  143.  
  144. // the `by` argument could be useful if we'd implement a method
  145. // that adds several elements to the queue in a row, not just one
  146. private void grow(int by) {
  147. assert by > 0;
  148.  
  149. if (size + by > data.length) {
  150. if (by == 1) {
  151. reallocate(data.length * d + 1);
  152. } else {
  153. reallocate(getFittingArraySize(size + by, d));
  154. }
  155. }
  156. }
  157.  
  158. private void shrink(boolean oneElementRemoved) {
  159. if (size <= data.length / (d * d)) {
  160. int minSize = pow(d, MIN_HEIGHT + 1) / (d - 1);
  161. if (oneElementRemoved) {
  162. reallocate(max(data.length / d, minSize));
  163. } else {
  164. reallocate(max(getFittingArraySize(size, d), minSize));
  165. }
  166. }
  167. }
  168.  
  169. @SuppressWarnings("unchecked")
  170. private void reallocate(int newSize) {
  171. assert newSize >= size;
  172.  
  173. T[] newData = (T[]) new Comparable<?>[newSize];
  174. System.arraycopy(data, 0, newData, 0, size);
  175. data = newData;
  176. }
  177.  
  178. private class QueueIterator implements Iterator<T> {
  179. private final MaxDaryHeap<T> pqCopy;
  180.  
  181. public QueueIterator() {
  182. pqCopy = new MaxDaryHeap<>(data, size, d);
  183. }
  184.  
  185. @Override
  186. public boolean hasNext() {
  187. return !pqCopy.isEmpty();
  188. }
  189.  
  190. @Override
  191. public T next() {
  192. if (!hasNext()) {
  193. throw new NoSuchElementException("The queue is empty.");
  194. }
  195. return pqCopy.poll();
  196. }
  197. }
  198.  
  199. private static int getFittingArraySize(int size, int d) {
  200. // size + by = (d^(height + 1) - 1) / (d - 1)
  201. // => height = floor[log_d((size + by) * (d - 1))] - 1
  202. int height = log(d, size * (d - 1)) - 1;
  203. int arrayLength = (pow(d, height + 1) - 1) / (d - 1);
  204. return arrayLength;
  205. }
  206.  
  207. private static <T extends Comparable<? super T>>
  208. boolean less(T[] array, int i, int j) {
  209. assert rangeCheck(array, i) && rangeCheck(array, j);
  210.  
  211. return array[i].compareTo(array[j]) < 0;
  212. }
  213.  
  214. private static void swap(Object[] array, int i, int j) {
  215. assert rangeCheck(array, i) && rangeCheck(array, j)
  216. : String.format("i = %d, j = %d, len(array) = %d",
  217. i, j, array.length);
  218.  
  219. Object swap = array[i];
  220. array[i] = array[j];
  221. array[j] = swap;
  222. }
  223.  
  224. private static boolean rangeCheck(Object[] array, int i) {
  225. return array != null && i >= 0 && i < array.length;
  226. }
  227.  
  228. /**
  229.   * Calculates the x^n value.
  230.   */
  231. private static int pow(int x, int n) {
  232. assert n >= 0;
  233.  
  234. int result = 1;
  235. for (int i = 0; i < n; i++) {
  236. result *= x;
  237. }
  238. return result;
  239. }
  240.  
  241. /**
  242.   * Calculates the floor(log_base(argument)) value.
  243.   */
  244. private static int log(int base, int argument) {
  245. assert argument > 0 && base > 1;
  246.  
  247. int log = 0;
  248. int intermediate = 1;
  249. while (intermediate <= argument) {
  250. intermediate *= base;
  251. log++;
  252. }
  253. return log;
  254. }
  255.  
  256. public static void main(String[] args) {
  257. MaxDaryHeap<Integer> heap = new MaxDaryHeap<>(5);
  258. Random random = new Random();
  259. for (int i = 0; i < 100; i++) {
  260. heap.offer(random.nextInt(10000));
  261. }
  262. for (int i = 0; i < 100; i++) {
  263. System.out.printf(" %d", heap.poll());
  264. }
  265. }
  266. }
Success #stdin #stdout 0.1s 34492KB
stdin
Standard input is empty
stdout
 9857 9761 9665 9636 9494 9281 9259 9224 9076 8962 8887 8852 8826 8545 8477 8386 8370 8368 8222 8222 8214 8147 8075 7795 7654 7550 7390 7385 7276 7226 7011 7005 6766 6671 6565 6371 6361 6045 5619 5499 5375 5233 4992 4930 4911 4902 4899 4787 4779 4692 4515 4271 4268 4235 4179 4156 3693 3439 3138 3032 3015 2725 2725 2565 2542 2517 2347 2322 2312 2297 2226 2014 1988 1524 1521 1369 1277 1276 1208 1170 1110 1077 941 734 726 699 687 528 448 397 379 375 352 339 317 313 228 183 162 67