Java 最后一圈:圆桌骑士团

Java 最后一圈:圆桌骑士团,java,initialization,final,circular-reference,circular-list,Java,Initialization,Final,Circular Reference,Circular List,我的一个朋友参加了一次工作面试。他被问到的问题听起来是这样的: 是否可以创建一个给定数量的类似类型的对象,这些对象虚拟地排列成一个圆圈,这样每个对象都包含对其左(顺时针)和右(逆时针)邻域的两个final引用 如果这对你来说太抽象了,有一个更具体的解释。想想这个问题。假设亚瑟王认为他们在谈判桌上的结合和安排是不变的、不可侵犯的。为了表达这一想法,他创建了以下简化的餐桌骑士模型: public class Knight { private final String name; pr

我的一个朋友参加了一次工作面试。他被问到的问题听起来是这样的:

是否可以创建一个给定数量的类似类型的对象,这些对象虚拟地排列成一个圆圈,这样每个对象都包含对其左(顺时针)和右(逆时针)邻域的两个final引用

如果这对你来说太抽象了,有一个更具体的解释。想想这个问题。假设亚瑟王认为他们在谈判桌上的结合和安排是不变的、不可侵犯的。为了表达这一想法,他创建了以下简化的餐桌骑士模型:

public class Knight {
    private final String name;
    private final Knight leftNeighbour;
    private final Knight rightNeighbour;

    public final Knight getLeft() {
        return leftNeighbour;
    }

    public final Knight getRight() {
        return rightNeighbour;
    }

    @Override
    public final String toString() {
        return name;
    }
}
请注意,所有字段都是最终字段。一旦设置,它们就无法更改。此处的
name
字段仅说明每个对象的各个属性(也可能有其他字段,final或not,但为了简单起见,省略了它们)。这里主要关注的是
leftneighbork
righneighbork
字段。最后,他们“固定”了圆圈,使其结构不变,但由单个对象组成

然而,有一个问题。正如您可能已经注意到的,上面的类大纲缺少非常重要的细节:构造函数。必须有一个指定最终字段的位置。要创建构造器——这正是采访者提出要解决的问题——给定所需的骑士数量和他们的姓名(按逆时针顺序),您应该创建相应的对象并填充他们的字段。您可以根据需要创建尽可能多的构造函数,也可以使用实例初始化块和静态工厂方法,如果您愿意,只需不触及上面的行即可。应该至少有一个公共构造函数或静态工厂方法返回所创建的骑士之一。例如,下面的验证代码依赖于

public Knight(int knightCount, IntFunction<String> nameGenerator)
输出应如下所示:

Knight#1
骑士2
骑士3
骑士4
骑士5
骑士6
骑士7
骑士8
骑士9
骑士10
骑士10
骑士9
骑士8
骑士7
骑士6
骑士5
骑士4
骑士3
骑士2
骑士1
创造了20000000名骑士
重要提示:

  • 反射被强烈禁止。它要么在亚瑟王时代不为人所知,要么被认为是亵渎神明
  • 您将被请求创建的骑士数量可能仅受可用内存的限制,因此请准备好创建非常大的表(例如,使用20000000骑士,如上所述),而不会导致堆栈溢出
以下是我针对两名骑士的解决方案:

public Knight(int knightCount, IntFunction<String> nameGenerator) {
    name = nameGenerator.apply(0);
    Knight other = new Knight(this, nameGenerator.apply(1));
    leftNeighbour = other;
    rightNeighbour = other;
}

private Knight(Knight mate, String name) {
    this.name = name;
    leftNeighbour = mate;
    rightNeighbour = mate;
}
public Knight(int knightCount,int函数名生成器){
name=nameGenerator.apply(0);
Knight other=新骑士(此名称为nameGenerator.apply(1));
左邻右舍=其他;
右邻=其他;
}
私人骑士(骑士伙伴,字符串名称){
this.name=名称;
左邻右舍=配偶;
右邻=配偶;
}
这个想法可以推广到三、四和任何其他少数骑士的情况。每个骑士负责创建下一个:

public Knight(int knightCount, IntFunction<String> nameGenerator) {
    name = nameGenerator.apply(0);
    Knight other = new Knight(1, knightCount, this, this, nameGenerator);
    rightNeighbour = other;
    for (int i = 1; i <= knightCount - 2; i++)
        other = other.rightNeighbour;
    leftNeighbour = other;
}

private Knight(int index, int knightCount, Knight first, Knight previous,
        IntFunction<String> nameGenerator) {
    name = nameGenerator.apply(index);
    leftNeighbour = previous;
    if (index == knightCount - 1)
        rightNeighbour = first;
    else
        rightNeighbour = new Knight(index + 1, knightCount, first, this, nameGenerator);
}
public Knight(int knightCount,int函数名生成器){
name=nameGenerator.apply(0);
Knight other=新骑士(1,knightCount,this,this,nameGenerator);
右邻=其他;

对于(int i=1;i@realponsum)来说,验证代码是否足以概括工作,以及“鸡还是蛋”这一段是否足以描述困难?验证代码不是工作摘要。它是检查工作是否正确的一种方法。实际工作正在提出一个建议的解决方案(你认为构造器应该是什么),并解释它失败的地方(例如,验证器的输出不是你显示的输出,存在错误等)。目前,您要求我们为您编写这些构造函数。您可能想将问题转移到。该网站更适合处理棘手的任务。@akuzminykh我已经考虑过了。但问题是特定于Java的。Java部分位于此处。我想,对于更广泛的Java读者来说,最后一个循环的习惯用法可能会很有趣(包括实际应用)。@realponsign我添加了一个适用于小数字的解决方案。
public Knight(int knightCount, IntFunction<String> nameGenerator) {
    name = nameGenerator.apply(0);
    Knight other = new Knight(1, knightCount, this, this, nameGenerator);
    rightNeighbour = other;
    for (int i = 1; i <= knightCount - 2; i++)
        other = other.rightNeighbour;
    leftNeighbour = other;
}

private Knight(int index, int knightCount, Knight first, Knight previous,
        IntFunction<String> nameGenerator) {
    name = nameGenerator.apply(index);
    leftNeighbour = previous;
    if (index == knightCount - 1)
        rightNeighbour = first;
    else
        rightNeighbour = new Knight(index + 1, knightCount, first, this, nameGenerator);
}