【问题标题】:How to implement a PriorityQueue without using the Java class?如何在不使用 Java 类的情况下实现 PriorityQueue?
【发布时间】:2019-11-05 17:45:41
【问题描述】:

我正在尝试在不使用 Java 提供的 PriorityQueue 类的情况下制作 PriorityQueue。为此,我有一些必须填写的给定方法。我不确定我在哪里犯了错误。看来我的 put 和 get 函数都是错误的,我不确定如何按照代码中给出的方式制作新的 PQ。我有以下内容:

class Element {

private int priority;
private String data;

Element(int priority, String data) { 
    // Ihr Code
    this.priority = priority;
    this.data = data;

 }

public String getData() { 
    // Ihr Code
    return data;
}


public int getPriority() { 
    // Ihr Code
    return priority;
 }

/**
 * Return data and priority as string 
 * Format: Data (Priority)
 * e.g: abc (7)
 */
public String toString()        {
    String str = data + " " + Integer.toString(priority) + ")";  
    return str;
}
}


public class PriorityQueue {


static final int SIZE = 32;


private Element[] data = null;

// actual number of entries
private int len = 0;


/**
 * Creates a new PriorityQueue
 */
public PriorityQueue() {
    // Ihr Code      
}

/** 
 * Adds a new element into the queue as long as there is space
 * Returns true if element could be added, otherwise false 
 */
boolean put(Element element) {
    // Ihr Code
    if(len == SIZE){
        return false;
    }else{
        int i = len-1;
        while (i>=0 && element.getPriority() > data[i].getPriority()){
            data[i+1] = data[i];
            i--;
        }
        data[i+1] = element;
        len++;
        return true;
    }

}

/**
 * Returns element with the highest priority 
 * and removes it from the queue. Otherwise returns null
 * 
 */
Element get() {
    // Ihr Code
    if (len > 0){
        Element x = q[0];
        for(int i = 1; i < len; i++){
            data[i-1] = data[i];
        }
        len--;
        return x;
        }else{
             return null;
        }
    }

/**
 * Number of entries 
 */
int length() {
    // Ihr Code
    return len;
 }

/**
 * Returns contents of the queue as a String
 * Format: data1 (priority1), data2 (priority2)
 * e.g: abc (7), cde (8)
 * Attention: There should be no comma at the end of the String 
 */
public String toString() {
    //  Code
    String res = new String();
    //res = "(" + data + "," + ")";

    if(data.length>0){
        StringBuilder sb = new StringBuilder();

        for(String s: data){
            sb.append(s).append(",");
        }
        res = sb.deleteCharAt(sb.length()-1).toString;
    }

    return res;
 }

我也在努力使用最终的 toString 方法,以给定格式将队列作为字符串返回,我尝试了使用 StringBuilder 的方法,但这不能正确编译。或者,我可以使用普通的 for 循环来实现它,但我又在为确切的语法苦苦挣扎。

我在网上找到了使用堆结构(我还没有)和一个我无法理解的名为 Comparator 的类来构建这个 PQ 的资源。任何帮助将不胜感激!

我主要是在挣扎

public PriorityQueue(){
      //what code?}

功能。我应该如何在这里制作“新”PQ?应该是

PriorityQueue pq = new PriorityQueue(); 

我很迷茫!非常感谢帮忙。

【问题讨论】:

  • 你看过最大堆数据结构吗?这对于这个实现很有用。

标签: java class queue priority-queue


【解决方案1】:

您的PriorityQueue 构造函数必须初始化数组并设置当前的项目数。那就是:

public PriorityQueue() {
    data = /* initialize array */
    len = 0;
}

您确实不需要按顺序保持队列中的元素。只需让您的 put 方法将该项目添加为数组中的下一个元素:

public put(Element e) {
    if (len == SIZE) {
        return false;
    }
    data[len++] = e;
    return true;
}

然后您的 get 方法在数组中搜索最高优先级的项目,将其保存,将其替换为数组末尾的项目,然后返回:

Element get() {
    if (len == 0) {
        return null;
    }
    int p = 0;
    for (int i = 1; i < len; ++i) {
        if (data[i].getPriority() < data[p].getPriority()]) {
            p = i;
        }
    }
    Element e = data[p];
    // replace with the last item
    data[p] = data[len-1];
    --len;
    return e;
}

所以put 是 O(1) 操作,get 是 O(n)。在您的代码中,两者都是 O(n)。

【讨论】:

    【解决方案2】:

    构造函数只需要初始化Element[]

    public PriorityQueue() {
        data = new Element[SIZE];
    }
    

    现在到put()。此方法将在while 循环中抛出ArrayOutOfBoundsException,因为您以i = len - 1 开头,这是data 的最后一个字段。然后你访问不存在的data[i+1],就会抛出异常(当然,除非你用data = new Element[SIZE + 1]初始化它)。

    解决方案:改用ii-1

    boolean put(Element element) {
        if (len == SIZE) {
            return false;
        } else {
            // EDIT: I changed i = len - 1 to i = len since, otherwise,
            // the last element would always be overwritten. Now, the
            // last element gets copied to the first "free" element and
            // so on.
            i = len;
            while (i > 0 && element.getPriority() > data[i-1].getPriority()) {
                data[i] = data[i - 1];
                i--;
            }
            data[i] = element;
            len++;
            return true;
        }
    }
    

    编辑:我之前说过将返回具有最小优先级的元素。实际上,它是最大的

    get() 方法的行为符合预期(除了它应该在开头说 Element x = data[0] 而不是 q[0])。它返回数组的第一个元素(具有最大getPriority() 值的元素)并将其余的索引向下移动。但是,如果您希望返回具有 最小 值的元素,只需在 put() 方法的 while 循环中将 &gt; 切换为 &lt;

    while (i > 0 && element.getPriority() < data[i-1].getPriority()) {
        ...
    }
    

    最后但同样重要的是toString() 方法。它看起来基本正确,除了 for-each 循环。这个总是迭代整个数组,它应该只迭代到data[len - 1]。因此,只需使用索引就可以了:

    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < len; i++) {
            sb.append(data[i]).append(",");
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
    
        return sb.toString();
    }
    

    或者,如果您至少安装了 Java 8,则可以在此方法中使用流:

    public String toString() {
        return Arrays.asList(data).stream()
            .limit(len)
            .map(Element::toString)
            .collect(Collectors.joining(","));
    }
    

    【讨论】:

    • 嘿,非常感谢您的回答。您的解释完全有道理,我自己也注意到了 toString() 错误。至于其余的代码,我将其更改为您解释的方式,但不幸的是,它似乎没有通过该分配的测试。 org.junit.ComparisonFailure用于getput 测试。 toString() 方法是正确的,但只有我在 put 方法中将 data[i] = element 更改为 data[i+1] = element。我认为索引存在某种问题。任何进一步的帮助将不胜感激!谢谢。
    • 好的,所以我必须更改 if 语句才能使测试正常工作,但现在可以了。不幸的是,我更改 if 语句使 toString 测试不再像我更改语句之前那样通过。我无法在此处粘贴代码,因为我超过了字符数限制,但我将 put 方法中的 else 更改为 else if (len &gt; 0 &amp;&amp; len &lt; 32) 并且它有效。你知道为什么toString 方法不再起作用了吗?我什至无法从我的主要方法中打印字符串。非常感谢你的帮忙! ```
    • 呃,昨天好像已经很晚了,哈哈。我在代码中犯了一些错误。我将更新我的答案并输入正确的代码(这一次,我测试了)。另外,当我说 get() 返回较小的优先级值时,我错了。它返回最大的。
    • 感谢编辑!根据我的测试用例,getput 方法是正确的,但不幸的是,toString 方法仍然失败。出于某种原因,我无法将数据数组打印到控制台或通过测试。它适用于以前版本的代码,其中 put 和 get 不起作用,但现在这两个工作,toStringdoesn't。极度困惑。您是否有可能再次查看 toString 方法并帮助我?我很困惑为什么什么都没有打印出来。
    • 嗯...我直接从 PowerShell 使用 javacjava 命令(使用额外的 main 方法)对其进行了测试,它就像一个魅力。你在什么上面运行它?也是控制台还是在 IDE(eclipse、NetBeans、IntelliJ、...)内部?另外,测试到底是什么样的? (我想这是一个 JUnit 测试?)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-07
    • 2010-12-29
    • 1970-01-01
    • 2021-09-18
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    相关资源
    最近更新 更多