All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.lucene.util.LongHeap Maven / Gradle / Ivy

There is a newer version: 6.4.2_1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.lucene.util;

/**
 * A min heap that stores longs; a primitive priority queue that like all priority queues maintains
 * a partial ordering of its elements such that the least element can always be found in constant
 * time. Put()'s and pop()'s require log(size). This heap provides unbounded growth via {@link
 * #push(long)}, and bounded-size insertion based on its nominal maxSize via {@link
 * #insertWithOverflow(long)}. The heap is a min heap, meaning that the top element is the lowest
 * value of the heap.
 *
 * @lucene.internal
 */
public final class LongHeap {

  private final int maxSize;

  private long[] heap;
  private int size = 0;

  /**
   * Create an empty priority queue of the configured initial size.
   *
   * @param maxSize the maximum size of the heap, or if negative, the initial size of an unbounded
   *     heap
   */
  public LongHeap(int maxSize) {
    final int heapSize;
    if (maxSize < 1 || maxSize >= ArrayUtil.MAX_ARRAY_LENGTH) {
      // Throw exception to prevent confusing OOME:
      throw new IllegalArgumentException(
          "maxSize must be > 0 and < " + (ArrayUtil.MAX_ARRAY_LENGTH - 1) + "; got: " + maxSize);
    }
    // NOTE: we add +1 because all access to heap is 1-based not 0-based.  heap[0] is unused.
    heapSize = maxSize + 1;
    this.maxSize = maxSize;
    this.heap = new long[heapSize];
  }

  /**
   * Adds a value in log(size) time. Grows unbounded as needed to accommodate new values.
   *
   * @return the new 'top' element in the queue.
   */
  public final long push(long element) {
    size++;
    if (size == heap.length) {
      heap = ArrayUtil.grow(heap, (size * 3 + 1) / 2);
    }
    heap[size] = element;
    upHeap(size);
    return heap[1];
  }

  /**
   * Adds a value to an LongHeap in log(size) time. If the number of values would exceed the heap's
   * maxSize, the least value is discarded.
   *
   * @return whether the value was added (unless the heap is full, or the new value is less than the
   *     top value)
   */
  public boolean insertWithOverflow(long value) {
    if (size >= maxSize) {
      if (value < heap[1]) {
        return false;
      }
      updateTop(value);
      return true;
    }
    push(value);
    return true;
  }

  /**
   * Returns the least element of the LongHeap in constant time. It is up to the caller to verify
   * that the heap is not empty; no checking is done, and if no elements have been added, 0 is
   * returned.
   */
  public final long top() {
    return heap[1];
  }

  /**
   * Removes and returns the least element of the PriorityQueue in log(size) time.
   *
   * @throws IllegalStateException if the LongHeap is empty.
   */
  public final long pop() {
    if (size > 0) {
      long result = heap[1]; // save first value
      heap[1] = heap[size]; // move last to first
      size--;
      downHeap(1); // adjust heap
      return result;
    } else {
      throw new IllegalStateException("The heap is empty");
    }
  }

  /**
   * Replace the top of the pq with {@code newTop}. Should be called when the top value changes.
   * Still log(n) worst case, but it's at least twice as fast to
   *
   * 
   * pq.updateTop(value);
   * 
* * instead of * *
   * pq.pop();
   * pq.push(value);
   * 
* * Calling this method on an empty LongHeap has no visible effect. * * @param value the new element that is less than the current top. * @return the new 'top' element after shuffling the heap. */ public final long updateTop(long value) { heap[1] = value; downHeap(1); return heap[1]; } /** Returns the number of elements currently stored in the PriorityQueue. */ public final int size() { return size; } /** Removes all entries from the PriorityQueue. */ public final void clear() { size = 0; } private void upHeap(int origPos) { int i = origPos; long value = heap[i]; // save bottom value int j = i >>> 1; while (j > 0 && value < heap[j]) { heap[i] = heap[j]; // shift parents down i = j; j = j >>> 1; } heap[i] = value; // install saved value } private void downHeap(int i) { long value = heap[i]; // save top value int j = i << 1; // find smaller child int k = j + 1; if (k <= size && heap[k] < heap[j]) { j = k; } while (j <= size && heap[j] < value) { heap[i] = heap[j]; // shift up child i = j; j = i << 1; k = j + 1; if (k <= size && heap[k] < heap[j]) { j = k; } } heap[i] = value; // install saved value } public void pushAll(LongHeap other) { for (int i = 1; i <= other.size; i++) { push(other.heap[i]); } } /** * Return the element at the ith location in the heap array. Use for iterating over elements when * the order doesn't matter. Note that the valid arguments range from [1, size]. */ public long get(int i) { return heap[i]; } /** * This method returns the internal heap array. * * @lucene.internal */ // pkg-private for testing final long[] getHeapArray() { return heap; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy