java 如何实现一个接受带有Comparable接口的对象的PriorityStack?

ndasle7k  于 2023-01-24  发布在  Java
关注(0)|答案(2)|浏览(117)

我看了一下这个线程中的代码:https://codereview.stackexchange.com/questions/98105/priority-stack-in-java
这使用对象和优先级实现了一个PriorityStack。我需要一个实现,其中您只将对象添加到PriorityStack,并使用Comparable接口定义哪个属性应该优先化。
例如:
我有一张狗的名单:

  • 姓名="跳过",年龄= 4
  • 姓名="格雷戈里",年龄= 3岁
  • 姓名="吉吉",年龄= 4岁

在Dog对象中,我将使用以下代码实现Comparable接口:

public int compareTo(Dog other) {
    if(other == null) {
        return -1;
    }
    return this.age - other.age;
}

我如何使用它来确定我的PriorityStack的优先级?
这样做的结果应该是最小的狗第一,然后其他2狗基于先进后出

ruyhziif

ruyhziif1#

我们可以把栈看作是一个优先级队列,它根据项目排队的时间来确定优先级,虽然它没有我们通常所说的栈那么高效,但它是LIFO。
PriorityQueue可以更容易地实现PriorityStack,而且可能效率更高。唯一的问题是,你要么需要在Dog类中添加一个time字段,要么将Dog对象 Package 在另一个具有time字段的类中。我倾向于后者:我们称之为PQDog,当然你需要一个自定义的比较器。
time字段不必是某个项目入队的实际时间。如果您确保为每个入队的项目递增它,它可以是一个整数。前提是您不打算在队列的生命周期中入队超过20亿个项目。请考虑一下,如果您从Integer.MinValue开始序列(或者不管它在Java中叫什么),你可以把这个范围扩展到40亿。
我们的想法是定义类:

class PQDog {
  int sequenceNumber;
  Dog dog;
}

我不是一个真正的Java程序员,所以不要指望下面的代码编译起来没有问题,但我认为它足以给你指明正确的方向。
当你想把一个Dog放到队列中时,你把它 Package 在一个PQDog对象中,并添加新的序列号,假设你有一个名为QueueSequence的静态变量,你每次排队前都会递增它。

PriorityQueue dogQueue = new PriorityQueue<PQDog>();
static int QueueSequence = 0;

// and to add something to the queue
PQDog newDog = new PQDog(QueueSequence++, Dog);
dogQueue.add(newDog);

当然,当您从队列中取出pop时,您必须打开Dog
看起来你的排序要求是“按年龄升序和时间降序”。所以你的比较器应该是这样的:

public int compareTo(PQDog other) {
    if(other == null) {
        return -1;
    }
    // sort younger dogs first
    if (this.Dog.age < other.Dog.age) return -1;
    if (this.Dog.age > other.Dog.age) return 1;

    // ages are the same, so compare enqueue time
    if (this.sequenceNumber > other.sequenceNumber) return -1;
    if (this.sequenceNumber < other.sequenceNumber) return 1;

    // Probably should raise an exception here
    // If you have two entries with the same sequence number,
    // something has gone horribly wrong.
    return 0;
}

或者,如果Dog类已经有了一个按年龄进行比较的CompareTo,则可以将上面的代码更改为:

if (this.Dog.CompareTo(other.Dog) == 0) return;

// and then compare the sequenceNumbers if the
// dogs' ages aren't equal.

在我看来,当您可以使用标准的Java PriorityQueue、一个定制比较器和几行接口代码来解决问题时,引入一个不完整且未经审查的定制PriorityStack数据结构似乎很愚蠢。
顺便说一句,通常不应该在Comparable中使用return a - b,想象一下当a等于最小整数时会发生什么(或者说是足够大的负数)并且b是一个足够大的正数。(实际上是下溢,但同样的事情)抬起它丑陋的头。结果将是一个正数,错误地指示a大于b
是的,我知道在这个特殊的案例中你不会遇到这个问题。至少,我不认为你有任何狗是负20亿岁。但我们作为程序员所做的很多事情都依赖于模式和惯例。一个人应该养成在可行的情况下编写防弹代码的习惯。谁也不知道别人会在你写完代码后用你的代码做什么。也许某个初学者正在寻找Comparable的实现,运行你的代码,把它复制到他的程序中,所有的单元测试和集成测试都通过了,代码进入了生产环境,四个月后有些东西坏了。
不是我凭经验说的......

ecbunoof

ecbunoof2#

(在评论中作出澄清后编辑的答复)
在链接的PriorityStack中,它获取两个值并将它们存储在TreeMap中。在您的示例中,一旦您使Dog类具有可比性(并且Dog对象包含.age属性),则可以将这些Dog对象存储在TreeSet中(这是一个排序的集合,根据Dog中的compareTo()方法排序)。
您可以将TreeSet示例化为TreeSet<Dog> stack = new TreeSet<>();

相关问题