【问题标题】:How to do a non destructive queue examination in Java如何在 Java 中进行非破坏性队列检查
【发布时间】:2010-02-06 13:28:46
【问题描述】:

我正在帮助我儿子上大学编程课,我想我也需要这门课。他已经完成了任务,但我不相信他做得最好。不幸的是,我无法让它以更好的方式工作。它显然更好,因为它还没有工作。

他被要求为一个扩展另一个类的类实现一些方法。

他被告知他必须使用以下类定义,并且他不能更改 ListQueue 中的任何内容。

public class MyListQueue <AnyType extends Comparable<AnyType>> extends ListQueue<AnyType>

这是 ListQueue 中的内容

// Queue interface
//
// ******************PUBLIC OPERATIONS*********************
// void enqueue( x )      --> Insert x
// AnyType getFront( )    --> Return least recently inserted item
// AnyType dequeue( )     --> Return and remove least recent item
// boolean isEmpty( )     --> Return true if empty; else false 
// void makeEmpty( )      --> Remove all items
// ******************ERRORS********************************
// getFront or dequeue on empty queue

/**
 * Protocol for queues.
 */

好的,我对在 Pascal 或 C 中遍历链表感觉很好(显示我的年龄),但以前从未使用过 OOP 语言。

当我尝试这样的事情时

dummyQueue = this.front.next;

我收到以下错误。 * front 在 ListQueue 中具有私有访问权限 *

我同意,但除了使项目出队之外,我如何遍历列表,或者以其他方式访问 ListQueue 中的前、后、下一个和上一个。

教育将不胜感激。

谢谢, 大卫

【问题讨论】:

  • 您已经列出了公共接口。受保护的界面有什么帮助吗?
  • 你需要实现哪些新方法?
  • 要求打印队列中的值。 displayQueue() 从队列中删除第一个匹配的值。 removeFromQueue(string) 将队列的内容复制到另一个队列中。 copyQueue(q2) 就是这样。真的很简单。感谢大家的帮助、cmets 和编辑。
  • 有2个私有方法... private ListNode front;私有 ListNode 返回;

标签: java queue


【解决方案1】:

如果我理解正确的话,你正在做这样的事情:

MyListQueue<String> dummyQueue = new MyListQueue<String>();
dummyQueue = this.front.next;

如果是这样,OOP 的主要原则之一就是封装,即数据隐藏。这个想法是类外的用户无权访问类的内部状态。

如果您要确定队列的大小并且无法修改接口或实现,您可以做的一件事是创建一个delegate 队列,它会覆盖入队和出队以递增和递减计数器。

【讨论】:

  • 是的,你是正确的。数据隐藏是封装功能的一部分(我猜)。我们正在尝试打印队列的内容。我刚刚学到了一种叫做迭代器的东西。这显然是队列可能具有的一种方法。也许这就是我所追求的。
  • 迭代器模式(和 Java 中的 API)肯定会解决您的问题。我没有提到它,因为它不在您列出的 API 中。
【解决方案2】:

如果您决定使用队列,您通常只想将元素入队和出队。您想知道队列是否为空,并想在需要时查看前面的元素或将其留给其他人。队列是一种避免阻塞的缓冲区,如果发送者比接收者快。使用队列,接收者可以决定何时读取下一个条目。队列可以实现一些(基于优先级的)排序并决定哪个元素是最前面的元素。

如果您需要其他操作,例如遍历列表,那么队列可能不是最佳选择。看看其他集合类型,也许是 ArrayList。

虽然有些事情是可以完成的,但您可以继承 ListQueue 并覆盖一些方法。所以如果你想要一个额外的size() 方法,这可能是一个解决方案:

public class MyListQueue <T extends Comparable<T>> extends ListQueue<T> {

  private size = 0;

  public void enqueue(T element) {
    size++;
    super.enqueue(element);
  }

  public T dequeue() {
    if (isEmpty()) {
       return null; // that's a guess...
    }
    size--;
    super.dequeue(element);
  }

  public int size() {
    return size;
  }
}

我已将AnyType 替换为更常见的 T。

【讨论】:

  • 感谢您的提示。我将使用 T 重新编码。我同意该结构可能不适合应用程序。我认为教授。正试图向他们展示我不确定的东西。
【解决方案3】:

您问,“除了使一个项目出队外,我如何遍历列表,或者以其他方式访问 ListQueue 中的前、后、下一个和上一个。”

从最纯粹的意义上说,你应该做不到。

理想化的队列只承诺几件事:

  • 物品推到后面
  • 从前面弹出个项目
  • (可能)检查前面的项目,如果不是空的
  • (可能)popinspect定义空间谓词,判断队列是否为空

我暂时假设队列不适用于并发读取器(同时访问前端)或并发读取器和写入器(同时访问后端和前端)。

根据该定义,没有理由要查看队列“内部”。你把东西放在一边,从另一边拿出东西。如果考虑到队列大小的bounding,则可能需要为 push 操作添加额外的定义空间谓词来确定队列是否已满。 “满”只有在队列有界时才有意义。仅当调用 popinspect 的线程不想阻塞时,“为空”才有意义。

除此之外,还有一个实用的队列概念。我们可以假设它是一个项目序列——除了并发问题——具有可观察到的非负大小,甚至可能允许访问序列中的每个项目。一些队列甚至允许在序列前面以外的位置移除或重新排列项目。不过,到那时,我们不再真正讨论队列了。我们正在讨论队列中的序列。如果我们需要这种访问,我们不需要队列。我们需要一个序列,我们希望为程序的其他部分提供类似队列的视图

这就是为什么队列通常不是数据结构库中的具体类型。在 C++ 中,std::queue 类型是其他容器类型的装饰器。在 Java 中,java.util.Queue 是一个接口。 Scala 采用了不同的方法:scala.collection.mutable.Queue 类是MutableList 类型的扩展。这类似于您儿子作业中规定的方法,但尚不清楚您的ListQueue 是否曾打算允许外部人员(包括子类)利用其“列表性质”——穿透队列视图以使用其中的序列。

您是否需要能够访问除队列头之外的任何内容?这样做会限制您对消费函数可以容纳的队列类型的选择。看来我们在这项作业中吸取了错误的教训。

【讨论】:

  • 首先是很好的答案。我很感激。正如我刚刚在对 Kevin 的评论中提到的,我儿子提到(因为我发布了这个问题,你回答了)一个名为迭代器的类方法。在阅读完之后,我认为教授试图教授广义列表遍历方法的概念,而不是正确使用队列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-24
  • 1970-01-01
  • 2011-01-19
  • 1970-01-01
  • 1970-01-01
  • 2016-03-06
  • 1970-01-01
相关资源
最近更新 更多