Dequeue方法未正确删除队列内的元素。

huangapple go评论68阅读模式
英文:

Dequeue method not correctly deleting elements within queue

问题

以下是翻译好的内容:

public class QueueRA<T> implements QueueInterface<T> {

    protected T[] items;
    protected int front, back, numItems;

    @SuppressWarnings("unchecked")
    public QueueRA() {
        front = 0;
        numItems = 0;
        back = 0;
        items = (T[]) new Object[3];
    }

    @Override
    public boolean isEmpty() {
        return numItems == 0;
    }

    @Override
    public void enqueue(T newItem) throws QueueException {
        if (numItems == items.length) {
            resize();
            enqueue(newItem);
        } else {
            items[back] = newItem;
            back = (back + 1) % items.length;
            numItems++;
        }
    }

    @Override
    public T dequeue() throws QueueException {
        T result;
        if (numItems != 0) {
            result = items[front];
            items[front] = null;
            front = (front + 1) % items.length;
            numItems--;
        } else {
            throw new QueueException("The queue does not contain any elements.");
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void dequeueAll() {
        back = 0;
        front = 0;
        numItems = 0;
        items = (T[]) new Object[3];
    }

    @Override
    public T peek() throws QueueException {
        T result;
        if (numItems != 0) {
            result = items[front];
        } else {
            throw new QueueException("The queue does not contain any elements.");
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    protected void resize() {
        T[] newItems = (T[]) new Object[numItems + 4];

        for (int i = 0; i < numItems; i++) {
            newItems[i] = items[i];
        }

        this.front = 0;
        this.back = numItems;
        this.items = newItems;
    }

    public String toString() {
        String toReturn = "";
        for (int i = 0; i < numItems; i++) {
            if ((i + 1) == numItems) {
                toReturn = toReturn.concat(items[i] + " ");
            } else {
                toReturn = toReturn.concat(items[i] + ", ");
            }
        }
        return toReturn;
    }

}
英文:

My dequeue method currently does not delete the item I wish for it too, instead it deletes the last element from the collection. For example,

If I add in the elements: 1, 2, 3
My toString method will return 1, 2, 3 as expected.

Then when I use my driver to call dequeue, it should dequeue the 0th element, 1 in this case.

Although, the method says "Removed element 1 from the queue" prompting that the T result variable has embodied the correct value, although the method does not work as expected, as when calling the toString method after to print the contents, it will print: 1, 2

Then when I call the enqueue method again, on the same queue, if I enqueue the String 3, it will print this as the new queue: 3, 2, 3

I am confused as to where my logic error is, as I assume it is with the extreme case of the collection being filled, but I still run into errors with my dequeue method when the collection is not at max. I attached my code below.

public class QueueRA&lt;T&gt; implements QueueInterface&lt;T&gt; {
protected T[] items;
protected int front, back, numItems; 
@SuppressWarnings(&quot;unchecked&quot;)
public QueueRA() {
front = 0;
numItems = 0;
back = 0;
items = (T[]) new Object[3];	
}
@Override
public boolean isEmpty() {
return numItems == 0;
}
@Override
public void enqueue(T newItem) throws QueueException {
if(numItems == items.length) {
resize();
enqueue(newItem);
}
else {
items[back] = newItem;
back = (back + 1) % items.length;
numItems++;
}
}
@Override
public T dequeue() throws QueueException {
T result;
if(numItems != 0) {
result = items[front];
items[front] = null;
front = (front + 1) % items.length;
numItems--;
}
else {
throw new QueueException(&quot;The queue does not contain any elements.&quot;);
}
return result;
}
@SuppressWarnings(&quot;unchecked&quot;)
@Override
public void dequeueAll() {
back = 0;
front = 0;
numItems = 0;
items = (T[]) new Object[3];
}
@Override
public T peek() throws QueueException {
T result;
if(numItems != 0) {
result = items[front];
}
else {
throw new QueueException(&quot;The queue does not contain any elements.&quot;);
}
return result;
}
/**
* 
*/
@SuppressWarnings(&quot;unchecked&quot;)
protected void resize() {
T[] newItems = (T[]) new Object[numItems+4];
for(int i = 0; i &lt; numItems; i++) {
newItems[i] = items[i];
}
this.front = 0;
this.back = numItems;
this.items = newItems;
}
/**
* 
*/
public String toString() {
String toReturn = &quot;&quot;;
for(int i = 0; i &lt; numItems; i++) {
if( (i+1) == numItems) {
toReturn = toReturn.concat(items[i] + &quot; &quot;);
}
else {
toReturn = toReturn.concat(items[i] + &quot;, &quot;);
}
}
return toReturn;
}
}

答案1

得分: 1

你的 toString() 和 resize() 方法是错误的。

在你的示例代码中,你最初创建了一个 arraySize 为 3,然后添加了 1、2 和 3。这占据了数组中的所有 3 个槽位,你的 numItems 被设置为 3。front 被设置为 0,back 也被设置为 0,因为在添加 3 后,你的算法是:

back = (back+1)%items.length;

back 最初是 2。现在计算如下:

-> (2+1)%3
-> 3%3
-> 0

所以此时 back 为 0。

现在,当你调用 dequeue() 方法时,front 弹出了 1。所以现在你的数组看起来是这样的:
items[0] -> 空
items[1] -> 2
items[2] -> 3
back = 0
front = 1

因此,当你调用 enqueue() 方法并添加 3 时,enqueue() 方法会检查系统中的项数是否小于数组的大小(2 < 3),然后将 3 添加到由 back(现在是 0) 指向的位置,并将其增加到 1。因此,现在你的数组如下所示:
items[0] -> 3
items[1] -> 2
items[2] -> 3
back = 1
front = 1

现在,在你的 toString() 方法中,没有考虑 front 和 back 的值,你从 0 开始到末尾:

for(int i = 0; i < numItems; i++) {
.
.
.
}

你需要做的是从 i = front 开始。如果 front < back,这意味着你从 "front" 线性地遍历到 "back" 并打印所有内容。如果 front > back,那么你需要两个循环:

for(int i = front; i < arr.length; i++) {
// 打印 arr[i] 的代码
}
for(int i = 0; i < back; i++) {
// 打印 arr[i] 的代码
}

这样,它将从 front 打印到末尾,然后从 0 打印到 back。

另外,你的 resize 方法也是错误的,原因相同。你不能从 0 复制到 numItems,你需要从 "front" 开始复制,然后按照我在 toString() 方法中写的方式进行。这样做将确保在多次调整大小时保留队列的顺序。

英文:

Your toString() and resize() methods are wrong.

In your example code, you created an arraySize of 3 initially and then added 1, 2, and 3. This occupies all the 3 slots in the array and your numItems is set to 3. The front is set to 0 and back is also set to 0 because after adding 3, your algorithm is:

back = (back+1)%items.length;

back was initially 2. Now it is calculated as:

-&gt; (2+1)%3
-&gt; 3%3
-&gt; 0

So your back is 0 at this moment.

Now, when you call dequeue(), the front pops 1 out. So now your array looks like this:
<br>items[0] -> empty
<br>items[1] -> 2
<br>items[2] -> 3
<br>back = 0
<br>front = 1
<br><br>So, when you enque next and add 3, your enqueue() method checks that number of items in the system is less than size of the array (2 < 3) and adds 3 to the location pointed by back (which is 0 now) and increments it to 1. So, your array looks like this now:
<br>items[0] -> 3
<br>items[1] -> 2
<br>items[2] -> 3
<br>back = 1
<br>front = 1

Now, in your toString() method, without considering the values of front and back, you start from 0 to end:

for(int i = 0; i &lt; numItems; i++) {
.
.
.
}

What you need to be doing is start at i = front. if front < back, that means that you travel lineraly from "front" to "back" and print everything. If front > back then you do two loops:

for(int i=front; i &lt; arr.length; i++) {
// Code to print arr[i]
}
for(int i=0; i &lt; back; i++) {
// Code to print arr[i]
}

This way, it will print from front to end and then from 0 to back.

Also, your resize method is wrong for the same reason. You cannot copy from 0 to numItems, you need to start the copy at "front" and then progress like how I wrote for the toString(). Doing this will ensure that your queue's order is preserved across multiple resizes.

答案2

得分: 1

@Arun Subramanian的回答的基础上添加。

你的resize()方法只是将所有元素从items顺序复制到newItems,然后设置front = 0back = numItems。如果你是按顺序实现队列,那这样做就没问题。然而,你实现的队列不是顺序的,而是循环/环形实现。因此,你必须以循环方式复制元素。

一种方法在@ArunSubramanian的回答中提到,"如果front < back,这意味着你从frontback线性地遍历并打印所有内容。如果front > back,那么你要做两个循环。" 另一种方法是使用带有模算术的do-while循环,如下所示:

@SuppressWarnings("unchecked")
protected void resize() {
    T[] newItems = (T[]) new Object[numItems + 4];

    int i = 0; // 用于将项复制到newItems的索引
    // 使用do-while以防队列已满(即front == back)
    do {
        newItems[i] = items[front];

        // 使用模算术在项上回到循环
        front = (front + 1) % items.length;
        i += 1;
    } while(front != back);

    this.front = 0;
    this.back = numItems;
    this.items = newItems;
}

类似地,你的toString()方法可以以下面的方式实现:

@Override
public String toString() {
    String toReturn = "";

    // 需要这个检查,否则do-while会非法访问items[0]
    if(!isEmpty()) {
        int len = items.length;
        int i = front;

        // 使用do-while以防front == back
        do {
            String delim = ((i+1) % len == back) ? " " : ", ";

            toReturn += items[i] + delim;

            i = (i+1) % len; // 使用模算术循环回来
        } while(i != back);
    }
    return toReturn;
}
英文:

Adding to @Arun Subramanian's answer.

Your resize() method was simply copying all of the elements sequentially from items to newItems, then setting front = 0 and back = numItems. Which would have been fine if you had implemented the queue sequentially. However, your implementation of a queue is not sequential, it's a circular / ring implementation. Therefor you have to copy the elements in a circular way.

One way to do this is mentioned in @ArunSubramanian's answer, "If front &lt; back, that means that you travel linearly from front to back and print everything. If front &gt; back then you do two loops." Another way is to use a do-while loop with modular arithmetic, as in the following:

@SuppressWarnings(&quot;unchecked&quot;)
protected void resize() {
T[] newItems = (T[]) new Object[numItems + 4];
int i = 0; // index used to copy items to newItems
// do-while used in case the queue is full (i.e. front == back)
do {
newItems[i] = items[front];
// modular arithmetic used to circle back on items
front = (front + 1) % items.length;
i += 1;
} while(front != back);
this.front = 0;
this.back = numItems;
this.items = newItems;
}

Similarly your toString() method can be implemented in the following way:

@Override
public String toString() {
String toReturn = &quot;&quot;;
// need this check, otherwise do-while will illegally access items[0]
if(!isEmpty()) {
int len = items.length;
int i = front;
// do-while used in case front == back
do {
String delim = ((i+1) % len == back) ? &quot; &quot; : &quot;, &quot;;
toReturn += items[i] + delim;
i = (i+1) % len; // modular arithmetic used to circle back
} while(i != back);
}
return toReturn;
}

huangapple
  • 本文由 发表于 2020年10月13日 07:27:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/64326601.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定