【问题标题】:Code Review for Linked List add(i, x) Method链表 add(i, x) 方法的代码审查
【发布时间】:2023-03-12 10:24:01
【问题描述】:

我目前正在尝试复习 ADT 实现,特别是链接列表的实现(我正在使用 Java 5 来执行此操作)。

我有两个问题:

(1) 我为 add(i, x) 编写的这个实现是否正确且高效?

public void add(int i, Object x) {

    // Possible Cases:
    //
    //     1. The list is non-empty, but the requested index is out of
    //        range (it must be from 0 to size(), inclusive)
    //
    //     2. The list itself is empty, which will only work if i = 0
    //
    // This implementation of add(i, x) relies on finding the node just before
    // the requested index i.

    // These will be used to traverse the list
    Node currentNode = head;
    int indexCounter = 0;

    // This will be used to mark the node before the requested index node
    int targetIndex = i - 1;

    // This is the new node to be inserted in the list
    Node newNode = new Node(x);

    if (currentNode != null) {

        while (indexCounter < targetIndex && currentNode.getNext() != null) {

            indexCounter++;
            currentNode = currentNode.getNext();
        }

        if (indexCounter == targetIndex) {

            newNode.setNext(currentNode.getNext());
            currentNode.setNext(newNode);

        } else if (i == 0) {

            newNode.setNext(head);
            head = newNode;
        }

    } else if (i == 0) {

        head = newNode;
    }     
}

(2) 我发现这种方法很难实现。老实说,我花了好几天的时间。这很难承认,因为我喜欢编程,并且认为自己在几种语言和平台方面处于中级水平。我从 13 岁起就开始编程(Apple IIc 上的 Applesoft BASIC!),并获得了计算机科学学位。我目前是一名软件测试员,并计划在某个时候成为一名开发人员。所以我的问题的第二部分是:我是在自欺欺人地认为这是我擅长的工作类型,还是几乎每个人都觉得这种问题具有挑战性?有些事情告诉我,即使是经验丰富的开发人员,在面临实施这种方法时也会发现它具有挑战性。

感谢您对第二部分的反馈和建议。

【问题讨论】:

  • @dvanaria:我觉得这个问题更适合codereview.stackexchange.com
  • 好的,谢谢,我从未听说过 codereview.stackexchange,它听起来确实是一个更好的地方。我现在会考虑把它移过来。
  • 我的问题的第二部分仍然正确,还是对stackoverflow不够客观?

标签: java data-structures linked-list implementation abstract-data-type


【解决方案1】:

我认为这是一个好的开始...一些建议:

  • 我认为您的 currentNode == null 情况应该在一开始就处理好,然后返回。我不喜欢“if (currentNode != null)”中的所有内容
  • 您应该在某处跟踪链接列表的大小,以便您可以轻松地检查 i > list_size
  • 我不会费心将“i-1”重命名为 targetIndex
  • 在需要之前不要创建新节点
  • 编写单元测试,然后您就可以轻松地进行更改并知道您的实现仍然有效。
  • 不要简单地忽略非法参数。如果索引 i 大小,则抛出 IllegalArgumentException 或 IndexOutOfBoundsException(感谢 @JB Nizet)

【讨论】:

  • 好的,谢谢,我确实写了一个单元测试,试图达到所有的边界情况。我尝试在允许范围之外添加元素,将元素添加到空列表中,在非空列表的范围内添加元素,在位置零添加元素,并添加元素 i = size() (即在末尾添加当前列表)。
  • 另外,不要简单地忽略非法参数。如果索引 i 大小,则抛出 IllegalArgumentException。否则,调用者不知道列表中没有添加任何内容。
  • 我基本同意,但我不同意不将 i-1 重命名为 targetIndex。我会说将 targetIndex 更改为 priorIndex 或 priorToInsertionIndex,因为它使您的意图更加清晰。 targetIndex 具有误导性,i-1 根本不清楚。
  • @dvanaria:你的意思是你写了 1 个测试函数?还是 1 个具有许多测试功能的类?
【解决方案2】:

我建议您从编写一些单元测试开始。特别是,尝试在列表末尾添加一个节点,看看会发生什么。 ;)

我认为大多数开发人员会发现编写 LinkedList 很困难,因为 a) 有很多方法可以实现它,b) 通常你不会自己编写它。您通常会使用有效的现有实现之一。 ;)

作为一个练习,这同样是一个好主意。我建议您阅读内置 LinkedList 的代码,并考虑如何以不同的方式做事。例如如何简化它可能是一个开始。

【讨论】:

    【解决方案3】:

    这个实现效率不高,但这部分是因为操作 add(i, x) 在普通链表上效率不高。链表不适用于随机访问。我认为如果您创建了一个哈希表或其他东西,您可能会在列表中创建一个更有效的索引。例如考虑地图。然后你的 map.ContainsKey(i-1) map.get(i-1) 的插入例程(显然 i=0 有一个特殊情况),你立即有了先验索引。如果 i != 0 并且您没有该索引的密钥,那么您马上就会知道一个错误。如果没有太多的冲突,映射在理论上是 O(1),所以这比每次遍历列表更有效(但以一些磁盘空间为代价)。同样,这真的取决于,因为纯链表对于 add(i, x) 不是很有效。

    我不是特别喜欢这种方法,因为如果你说 add(32, x) 并且列表中只有 15 个项目,它会默默地失败。它至少应该抛出异常、返回 false 或其他内容以指示插入失败。

    您也可以合并这两种特殊情况。假设 newNode.setNext(NULL) 有效,您只需要检查 i==0 然后您就可以执行 newNode.setNext(head), head=newNode 因为列表是否为空这有效。如果列表为空,则将 next 指针设置为 NULL。这至少消除了重复代码。

    花一周时间确实看起来有点多,但是有些人首先要解决指针问题(以及 javaspeak 中的类引用......)。事实上,你最终得到了一些工作,这是朝着正确方向迈出的一大步。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多