首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >最小堆优先级队列

最小堆优先级队列
EN

Code Review用户
提问于 2019-08-18 17:44:35
回答 1查看 402关注 0票数 4

这是我在网上找到的一项任务的一部分,并试图自己解决。

目标是使用Min堆实现一个优先级队列,并使用Array作为底层数据结构来存储数据。

代码语言:javascript
运行
复制
public class ArrayHeapMinPQ<T> {


   private PriorityNode<T>[] items;
   private int INITIALCAPACITY = 4;
   private int capacity = INITIALCAPACITY;
   private int size = 0;
   private Set<T> itemSet;

   // Declaring a construtor to intialize items as an array of PriorityNodes
   public ArrayHeapMinPQ() {
       itemSet = new HashSet<>();
       items = new PriorityNode[INITIALCAPACITY]; 
       items[0] = new PriorityNode(null, -1);

   }

   /*
    * Adds an item with the given priority value. Throws an
    * IllegalArgumentException if item is already present
    */
   @Override
   public void add(T item, double priority) {
       ensureCapacity();

       // To ensure that duplicate keys are not being used in the queue
       if (itemSet.contains(item)) {
           throw new IllegalArgumentException();
       }

       items[size + 1] = new PriorityNode(item, priority);
       size++;
       itemSet.add(item);
       upwardHeapify(items[size]);
   }

   /*
    * Returns true if the PQ contains the given item
    */
   @Override
   public boolean contains(T item) {
       return itemSet.contains(item); 
   }

   /*
    * Returns the minimum item. Throws NoSuchElementException if the PQ is
    * empty
    */
   @Override
   public T getSmallest() {
       if (this.size == 0) throw new NoSuchElementException();
       return items[1].getItem();
   }

   @Override
   public T removeSmallest() {
       if (this.size == 0) throw new NoSuchElementException();
       T toReturn = items[1].getItem();
       items[1] = items[size];
       items[size] = null;
       size -= 1;
       itemSet.remove(toReturn);
       downwardHeapify();

       ensureCapacity();

       return toReturn;
   }

   // TODO: Implementation of changePriority is pending

    /**
     * Changes the priority of the given item. Throws
     * NoSuchElementException if the element does not exists
     * @param item Item for which the priority would be changed
     * @param priority New priority for the item
     */
   @Override
   public void changePriority(T item, double priority) {
       if (!itemSet.contains(item)) throw new NoSuchElementException();
       for (int i = 1; i <= this.size; i += 1) {
           if (item.equals(items[i].getItem())) {
               PriorityNode currentNode = items[i];
               double oldPriority = currentNode.getPriority();
               currentNode.setPriority(priority);
               if (priority < oldPriority) {
                   upwardHeapify(currentNode);
               }
               else {
                   downwardHeapify();
               }
               break;
           }
       }
   }

   /* Returns the number of items in the PQ */
   @Override
   public int size() {
      return this.size;
   }

    /*
    * Helper function to retrieve left child index of the parent
    */
   private int getLeftChildIndex(int parentIndex) {
       return 2 * parentIndex;    
   }

   /*
    * Helper function to retrieve right child index of the parent
    */
   private int getRightChildIndex(int parentIndex) {
       return 2 * parentIndex + 1;
   }

   /*
    * Helper function retrieve the parent index
    */
   private int getParentIndex(int childIndex) {
       return childIndex / 2;
   }

   /*
    * Helper method to heapify the queue upwards
    */
   private void upwardHeapify(PriorityNode last) {
       PriorityNode smallestNode = items[1];
       // the last node which was inserted in the array
       PriorityNode lastNode = last;
       int latestNodeIndex = size;
       // The max could be that last node will need to switch the smallest node
       while (!lastNode.equals(smallestNode)) {
           // Get the parent node
           int parentNodeIndex = getParentIndex(latestNodeIndex);
           PriorityNode parentNode = items[parentNodeIndex];

           // The function is working because the compareTo method is
           // comparing the priority and not the data in the item
           if (parentNode.compareTo(lastNode) > 0) {
               // Swap the last node with its parent node
               swap(parentNodeIndex, latestNodeIndex);

               // Update the method variables
               latestNodeIndex = parentNodeIndex;
               lastNode = items[latestNodeIndex];
           }
           // The priority of the parent is less than or equal to the parent
           else if (parentNode.compareTo(lastNode) <= 0) {
               break;
           }
       }
   }

   private void downwardHeapify() {
       // assumption is that the top node is the largest node
       int currentIndex = 1;
       while(hasLeftChild(currentIndex)) {
           int leftChildIndex = getLeftChildIndex(currentIndex);
           int smallerChildIndex = leftChildIndex;

           if (hasRightChild(currentIndex)) {
               int rightChildIndex = getRightChildIndex(currentIndex);
               double leftChildPriority = items[leftChildIndex].getPriority();
               double rightChildPriority = items[rightChildIndex].getPriority();

               if (leftChildPriority > rightChildPriority) {
                   smallerChildIndex = rightChildIndex;
               }
           }

           if (items[currentIndex].getPriority() <
                   items[smallerChildIndex].getPriority()) {
               break;
           }
           else {
               swap(currentIndex, smallerChildIndex);
           }
           currentIndex = smallerChildIndex;

       }
   }

   private boolean hasLeftChild(int index) {
       return getLeftChildIndex(index) < this.size + 1;
   }

    private boolean hasRightChild(int index) {
       return getRightChildIndex(index) < this.size + 1;
   }

    /* 
    * Helper function to the class to make sure that there is enough capacity
    * in the array for more elements
    */
   private void ensureCapacity() {
       // there are two conditions to take care of
       // 1. Double the size
       // 2. Make the size half if the array is 3/4 empty
       double currentLoad = (double) this.size / (double) this.capacity;
       int newCapacity = capacity;
       if(this.size > 1 && currentLoad < 0.25) {
           // Array is being downSized
           newCapacity = capacity / 2;
           items = Arrays.copyOf(items, newCapacity);
       }
       else if (currentLoad >= 0.5 ) {
           // Doubling the size of the array
           newCapacity = capacity * 2;
           items = Arrays.copyOf(items, newCapacity);
       }
       capacity = newCapacity;
   }

   /*
    * Helper method to swap two nodes
    */
   private void swap(int parentNodeIndex, int latestNodeIndex) {
       PriorityNode temp = items[parentNodeIndex];
       items[parentNodeIndex] = items[latestNodeIndex]; 
       items[latestNodeIndex] = temp;
   }

   public Integer[] toArray() {
       Integer[] toReturn = new Integer[items.length];
       for (int i = 1; i < items.length - 1; i++) {
           toReturn[i] = ((Double) items[i].getPriority()).intValue();
       }
       return toReturn;
   }

}

PriorityNode

代码语言:javascript
运行
复制
public class PriorityNode<T> implements Comparable<PriorityNode> {

    private T item;
    private double priority;

    PriorityNode(T item, double priority) {
        this.item = item;
        this.priority = priority;
    }

    protected T getItem() {
        return this.item;
    }

    protected double getPriority() {
        return this.priority;
    }

    protected void setPriority(double priority) {
        this.priority = priority;
    }

    @Override
    public int compareTo(PriorityNode other) {
        if (other == null) {
            return -1;
        }
        return Double.compare(this.getPriority(), other.getPriority());
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean equals(Object o) {
        if (o == null || o.getClass() != this.getClass()) {
            return false;
        }
        else {
            return ((PriorityNode) o).getItem().equals(this.getItem());
        }
    }

    @Override
    public int hashCode() {
        return item.hashCode();
    }
}

我必须实现一个接口,并且在代码中省略了这个部分。在我看来,更改优先级函数运行在O(n)上,我不知道如何提高它的性能。

我希望对代码和changePriority函数的性能进行讨论。

EN

回答 1

Code Review用户

回答已采纳

发布于 2019-08-18 19:12:06

总评

使所有从未重新分配的final实例字段。从注释中可以看出,这些字段中的一些将在代码后面重新分配。在这种情况下,不应将这些字段声明为最终字段。

代码语言:javascript
运行
复制
 private final PriorityNode<T>[] items;
 private final Set<T> itemSet;

使常量保持静态和只读,并使用下划线表示可读性。

代码语言:javascript
运行
复制
 private static final int INITIAL_CAPACITY = 4;
 private int capacity = INITIAL_CAPACITY;

不要引入不必要的新行。例如,类定义和实例变量之间。零个或一个新的行就够了。

公共类ArrayHeapMinPQ {私有PriorityNode[]项目;

代码语言:javascript
运行
复制
public class ArrayHeapMinPQ<T> {
   private PriorityNode<T>[] items;

不要写那些显而易见的评论。它污染了源代码。写评论什么时候才真正有意义。

// Declaring a construtor to intialize items as an array of PriorityNodes public ArrayHeapMinPQ() {

与公共API注释一样(这是一件好事):

/\* \* Adds an item with the given priority value. Throws an \* IllegalArgumentException if item is already present \*/ @Override public void add(T item, double priority) {

在更改实例状态之前执行参数检查。(并删除这些附加值为零的注释)

公共无效添加(T项,双优先级){ ensureCapacity();//以确保队列中不使用重复的密钥,如果(itemSet.contains(项目)){抛出新的IllegalArgumentException();}

代码语言:javascript
运行
复制
public void add(T item, double priority) {
       if (itemSet.contains(item)) {
           throw new IllegalArgumentException();
       }
       ensureCapacity();

在Java中,不仅提供add,还提供offer方法,这是自定义的。add抛出一个异常,而offer返回一个boolean。要容纳多个入口点,应该将实际的数据插入到私有方法中。

代码语言:javascript
运行
复制
private void insert(T item, double priority) {
    ensureCapacity();
    items[size + 1] = new PriorityNode(item, priority);
    size++;
    itemSet.add(item);
    upwardHeapify(items[size]);
}

然后重构add

代码语言:javascript
运行
复制
   /*
    * Adds an item with the given priority value. Throws an
    * IllegalArgumentException if item is already present
    */
   @Override
   public void add(T item, double priority) {
       if (itemSet.contains(item)) {
           throw new IllegalArgumentException();
       }
       insert(item, priority);
   }

并介绍offer

代码语言:javascript
运行
复制
   /*
    * Adds an item with the given priority value. Returns
    * False if item is already present
    */
   public boolean offer(T item, double priority) {
       if (itemSet.contains(item)) {
           return false;
       }
       insert(item, priority);
       return true;
   }
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/226387

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档