尝试以不同的方式实现优先级队列

Posted

技术标签:

【中文标题】尝试以不同的方式实现优先级队列【英文标题】:Trying to Implement a priority queue in a different way 【发布时间】:2019-09-24 04:52:17 【问题描述】:

我正在尝试实现一个优先级队列,它的功能与普通优先级队列有点不同。这里的想法是支持快速插入,但对最高优先级项目的访问速度较慢。在这种情况下,Insert 方法将新项目放在方便的地方;因此,remove 和 peek 方法必须在整个队列中搜索最高优先级的项目。

public class MinPriorityQueue 

/** Constructs a new MinPriorityQueue with capacity cap and size 0.
 * 
 * @param cap Capacity of the new queue.
 */
public MinPriorityQueue(int cap)          

    this.queue = (Comparable []) new Comparable[cap];
    this.size = 0;
    this.cap = cap;


int size() 
   return this.size;


int capacity() 
   return this.cap;


 boolean isEmpty() 
   return this.size==0;


boolean isFull() 
    return this.size == cap;       


void insert(Comparable e) 
    if (this.size == cap) 
        throw new IllegalStateException();
    
    queue[size] = e;
    size++;



Comparable remove() 

    if (this.size == 0) 
        throw new IllegalStateException();
    
    int maxIndex = 0;
    for (int i=1; i<size; i++)  
        if (queue[i].compareTo (queue[maxIndex]) < 0)  
            maxIndex = i; 
         
     
    Comparable result = queue[maxIndex]; 
    size--; 
    queue[maxIndex] = queue[size]; 
    return result;
    


 /** Returns, but does not remove, the lowest-priority item in the
 * queue.
 * 
 * Complexity: O(n)
 * @return Lowest priority item.
 * @throws IllegalStateException if the queue is empty.
 */
Comparable top()  
           if (this.size == 0) 
        throw new IllegalStateException();
    
         /*  int i;
           for (i=0; i < size; i++) 
        if (queue[i].compareTo (size-1) < 0) 
            break;
        
    
           return queue[size - 1];*/
    return  queue[size-1]; 
  



Comparable[] queue; // Contents of the queue

private  int cap;
private int size;    


//// 测试文件

 /**
     * Test of remove method, of class MinPriorityQueue.
     */
    @Test
    public void testRemove() 
    System.out.println("remove");
    MinPriorityQueue q = new MinPriorityQueue(10);

    boolean throws_exception = false;
    try 
        q.remove();
     catch (IllegalStateException e) 
        throws_exception = true;
     catch (Throwable e) 

    
    assertTrue("remove throws an exception when empty", throws_exception);

    // Permutation of 0...9
    int[] input = 0, 5, 9, 2, 3, 1, 6, 8, 7, 4;

    for (int i : input) 
        q.insert(i);
    

    assertTrue(q.isFull());

    for (int i = 10; i > 0; --i) 
        assertEquals(q.size(), i);
        Integer x = (Integer) q.remove();
        assertEquals(x, new Integer(10 - i)); // Items are removed in correct order            
    

    assertTrue(q.isEmpty());


/**
 * Test of top method, of class MinPriorityQueue.
 */
@Test
public void testTop() 
    System.out.println("top");
    MinPriorityQueue q = new MinPriorityQueue(10);

    boolean throws_exception = false;
    try 
        q.top();
     catch (IllegalStateException x) 
        throws_exception = true;
     catch (Throwable x) 

    
    assertTrue("top throws an exception when empty", throws_exception);

    int[] input = 0, 5, 9, 2, 3, 1, 6, 8, 7, 4;
    int smallest = 10;
    for (int i : input) 
        q.insert(i);
        if (i < smallest) 
            smallest = i;
        

        assertEquals(q.top(), smallest);
    

    for (int i = 0; i < 10; ++i) 
        assertEquals(q.top(), i);
        q.remove();
    
    

我已经能够实现除 remove 和 peek 之外的所有方法,因为我无法获得实现这些方法的逻辑权。我无法弄清楚我们如何搜索整个队列以找到最高优先级的项目。对于这个,我相信应该使用 for 循环,但只是没有得到正确的逻辑

编辑:我能够为 remove() 方法获得正确的逻辑,只需要让 pop() 方法工作

【问题讨论】:

使用 remove 你只是在减小数组的大小,即使要删除的项目不在数组的末尾 是的。我正在尝试不同的东西来使逻辑正确。你能指导我如何使它正确吗。谢谢 @Scary Wombat 。我想出了 remove 方法的逻辑并更新了我的帖子。只需要让 pop() 方法工作 旁注:演员(Comparable []) new Comparable[cap]; 是不必要的。 queue[maxIndex] = queue[size]; 应该在 size-- 之前发生,否则你会复制下一个元素并“删除”最后一个元素。 另一个:只使用Comparable 很危险,因为您可能会添加不兼容的类型(例如,尝试比较字符串和日期)。除此之外,这些元素没有 priority,因此您可能希望使用泛型来使用更具体的类型,或者与数据一起提供优先级并为元素使用专门的类. 【参考方案1】:

实现此目的的最简单方法是使用java.util.List 而不是array。所以List 会将元素保留在队列中并处理它们的定位而不对它们进行排序(因此它仍然使用快速插入)。如果您将实现java.util.ArrayList 用于List 接口,它会在内部使用array,所以这几乎正是您正在尝试的,但更容易,因为其他人已经完成了大部分工作......

所以你可以像这样实现类MinPriorityQueue

import java.util.ArrayList;
import java.util.List;

//use a generic type argument T here that extends comparable so you can only store objects of a specific type that are comparable to each other
public class MinPriorityQueue<T extends Comparable<T>> 

    private List<T> queue; // Contents of the queue

    private int cap;
    //private int size;

    /**
     * Constructs a new MinPriorityQueue with capacity cap and size 0.
     * 
     * @param cap
     *        Capacity of the new queue.
     */
    public MinPriorityQueue(int cap) 
        this.queue = new ArrayList<T>(cap);
        //this.size = 0;
        this.cap = cap;
    

    public int size() 
        //return this.size;
        return queue.size();
    

    public int capacity() 
        return this.cap;
    

    public boolean isEmpty() 
        //return this.size == 0;
        return queue.isEmpty();
    

    public boolean isFull() 
        //return this.size == cap;
        return queue.size() == cap;
    

    public void insert(T e) 
        if (queue.size() == cap) 
            throw new IllegalStateException();
        
        //queue[size] = e;
        //size++;
        queue.add(e);
    

    /**
     * Removes and returns the lowest-priority item from the queue.
     * 
     * Complexity: O(n)
     * 
     * @return Lowest priority item that was in the queue.
     * @throws IllegalStateException
     *         if the queue is empty.
     */
    public Comparable<T> remove() 
        if (queue.size() == 0) 
            throw new IllegalStateException();
        

        /*for (int i = 0; i < this.size; i++) 
            if (this.queue[i] == queue[size]) 
                return i;
            
        
        return queue[--size];*/

        //initialize the lowest priority item with the first one in the list
        int lowestPriorityIndex = 0;

        //search every other item in the list to see whether it has a lower priority than the current lowest priority 
        for (int i = 1; i < queue.size(); i++) 
            if (queue.get(i).compareTo(queue.get(lowestPriorityIndex)) < 0) 
                lowestPriorityIndex = i;
            
        

        //return and remove the lowest priority item
        return queue.remove(lowestPriorityIndex);
    

    /**
     * Returns, but does not remove, the lowest-priority item in the queue.
     * 
     * Complexity: O(n)
     * 
     * @return Lowest priority item.
     * @throws IllegalStateException
     *         if the queue is empty.
     */
    public Comparable<T> top() 
        if (queue.size() == 0) 
            throw new IllegalStateException();
        
        /*  int i;
          for (i=0; i < size; i++) 
        if (queue[i].compareTo (size-1) < 0) 
           break;
        
        
          return queue[size - 1];*/


        //initialize the lowest priority item with the first one in the list
        int lowestPriorityIndex = 0;

        //search every other item in the list to see whether it has a lower priority than the current lowest priority 
        for (int i = 1; i < queue.size(); i++) 
            if (queue.get(i).compareTo(queue.get(lowestPriorityIndex)) < 0) 
                lowestPriorityIndex = i;
            
        

        //return (but not remove) the lowest priority item
        return queue.get(lowestPriorityIndex);
    

此代码通过了您在问题中提供的所有测试用例。

我还在示例代码中添加了一个泛型类型参数(因此类声明现在是MinPriorityQueue&lt;T extends Comparable&lt;T&gt;&gt;),因为需要它来实际比较元素。你可以查看泛型类型here。

【讨论】:

不。我不能使用 List。但是我在数组中实现了你的方法并且它有效。谢谢

以上是关于尝试以不同的方式实现优先级队列的主要内容,如果未能解决你的问题,请参考以下文章

使用链表的优先队列

原来实现优先级队列如此简单

优先级队列中的不同元素

swift中的优先队列

延时队列常用实现详解

堆(Heap)和有优先队列(Priority Queue)