这是我在网上找到的一项任务的一部分,并试图自己解决。
目标是使用Min堆实现一个优先级队列,并使用Array作为底层数据结构来存储数据。
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
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函数的性能进行讨论。
发布于 2019-08-18 19:12:06
使所有从未重新分配的final实例字段。从注释中可以看出,这些字段中的一些将在代码后面重新分配。在这种情况下,不应将这些字段声明为最终字段。
private final PriorityNode<T>[] items;
private final Set<T> itemSet;使常量保持静态和只读,并使用下划线表示可读性。
private static final int INITIAL_CAPACITY = 4;
private int capacity = INITIAL_CAPACITY;不要引入不必要的新行。例如,类定义和实例变量之间。零个或一个新的行就够了。
公共类ArrayHeapMinPQ {私有PriorityNode[]项目;
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();}
public void add(T item, double priority) {
if (itemSet.contains(item)) {
throw new IllegalArgumentException();
}
ensureCapacity();在Java中,不仅提供add,还提供offer方法,这是自定义的。add抛出一个异常,而offer返回一个boolean。要容纳多个入口点,应该将实际的数据插入到私有方法中。
private void insert(T item, double priority) {
ensureCapacity();
items[size + 1] = new PriorityNode(item, priority);
size++;
itemSet.add(item);
upwardHeapify(items[size]);
}然后重构add:
/*
* 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:
/*
* 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;
}https://codereview.stackexchange.com/questions/226387
复制相似问题