Java 为自定义链表实现插入方法?

Java 为自定义链表实现插入方法?,java,data-structures,linked-list,insert,nodes,Java,Data Structures,Linked List,Insert,Nodes,我想要一些关于我写的在链表中插入元素的方法的反馈。给出的链表类定义为: public class List { private Node head; private static class Node { public String data; public Node next; public Node(String data, Node next) { //Assign data and next here } //Optiona

我想要一些关于我写的在链表中插入元素的方法的反馈。给出的链表类定义为:

public class List {
  private Node head;

  private static class Node {
    public String data;
    public Node next;

    public Node(String data, Node next) {
      //Assign data and next here
    }
    //Optional Node helper methods are written here
}
//List methods and data go here
基于这个定义,我试图创建一个insert方法。我不确定给我的定义是否包含
size()
方法,但我假设没有,并尝试在我的insert方法中查找大小(基本上是列表中的节点数)。该方法具有签名
public void insert(String s,int psn)
当给出非法索引(psn)值(超出范围)时,该方法还应引发IllegalArgumentException。我猜,
psn
的值范围是从0到第一个空元素出现时的值(如果我不正确,请纠正我。这是我编写的方法:

public void insert(String s, int psn) {
  Node temp = head; //Save original head
  int c = 0;

  while (temp != null) { //Traverse linked list
   c++;
   temp = temp.next;
  }

  if (psn < 0 || psn >= c) { //Should throw exception when illegal value is used
    throw new IllegalArgumentException();
  } 

  if (psn == 0) { //Special case when inserting an element at the front of the list
    head = new Node(s, head);

  } else if (head != null) {
    Node current = head; //Save original head while traversing list

    while (current != null) {
      current = current.next;
      psn--;
    }

    if (current != null) { //We are at the position where we want to insert the element
      current.next = new Node(s, current.next);
    }
  }
}
public void插入(字符串s,int psn){
节点温度=头部;//保存原始头部
int c=0;
while(temp!=null){//遍历链表
C++;
温度=下一个温度;
}
如果(psn<0 | | psn>=c){//在使用非法值时应引发异常
抛出新的IllegalArgumentException();
} 
如果(psn==0){//在列表前面插入元素时的特殊情况
头部=新节点(多个,头部);
}else if(head!=null){
节点当前=头;//遍历列表时保存原始头
while(当前!=null){
当前=当前。下一步;
psn--;
}
如果(current!=null){//,则我们位于要插入元素的位置
current.next=新节点(s,current.next);
}
}
}

有没有人能告诉我,在查找链表长度时,我是否正确使用了第一个while循环,以及我是否正确地使用了它(除了例外)?这是我最关心的部分。提前非常感谢!

您可以通过在一些测试用例上运行它来测试代码。但下面是我对您的评论此代码:

  • 最后一个if语句
    if(current!=null)
    将始终返回false,因为之前的while循环将使
    current
    在结尾处为null
  • 在第一个while循环之前,我会检查psn是否
    0
    ,以减少浪费的计算
  • 我建议您在类中保留一个名为
    size
    的字段,它将处理列表的大小。首先它将设置为0,在每次
    insert
    和每次
    remove
    之后,您将更新此字段
然后代码会是这样的:

public void insert(String s, int psn) {     
    if(psn < 0 || psn > size)
        throw new IllegalArgumentException();
    Node temp = head; //Save original head
    for(int i=0;i<psn-1;i++)
        temp = temp.next;
    temp.next = new Node(s, temp.next);
    this.size++;
}
public void insert(字符串s,int psn){
如果(psn<0 | | psn>大小)
抛出新的IllegalArgumentException();
节点温度=头部;//保存原始头部
对于(int i=0;i
  • 是的,这是在不存储大小的情况下检索LinkedList中元素数量的正确方法

  • 这是链表的一个缺点,就是O(n)遍历,但如果存储“tail”元素,则插入1次

  • 参见Matan Kintzlinger的逻辑建议


目前,您的
insert
将遍历整个列表两次,一次用于查找大小,另一次用于查找节点。最基本的实现是,没有数据可以帮助您在每次写入时更新大小字段,只需遍历它一次,因为如果点击earli,您将知道所需的位置无效呃,比预期的要高。我将这样实施它:

public void insert(String item, int position) {
  if(position == 0) {
    head = new Node(item, head);
    return;
  }

  List.Node previousNode = head;

  for(int i = 1; i < position && previousNode != null; ++i) {
    previousNode = previousNode.next;
  }

  if(position < 0 || previousNode == null) {
    throw new IllegalArgumentException("index " + position + " is out of bounds");
  }

  previousNode.next = new Node(item, previousNode.next);
}
public void插入(字符串项,int位置){
如果(位置==0){
head=新节点(项目,head);
返回;
}
List.Node-previousNode=head;
对于(int i=1;i
其他考虑因素包括:

  • 尽量使用描述性变量名,而不是缩写词,如
    psn
    ,因为没有完整的上下文,它们可能很难阅读。在大多数真实场景中,优化人类可读性更为重要,因为调试和维护代码的人越容易理解代码,出现错误的可能性就越小很多时候,变量名实际上是你了解发生了什么事情的第一条线索,是一个真正的理智保护程序!我上一次试图理解外部库中的代码为什么会崩溃时,被一个给定的变量名保存是在几天前

  • 尝试使用和提前返回以避免。如果您在方法中避免,那么发现它们并不是问题。例如,在这种情况下,在零位置插入的特殊情况是一个提前返回机会,因为不需要检查,并且在完成后无需执行任何操作

  • 使您的异常尽可能有用。这意味着,当您因为捕获了另一个异常而抛出异常时,请按顺序将捕获的异常作为原因;在这种情况下,如果不存在早期异常,则提供一条帮助开发人员了解发生了什么的有用消息就足够了。在这种情况下,
    IllegalArgument异常
    并没有告诉我们很多导致抛出此异常的原因,因此是消息。几乎每个异常构造函数都允许一条消息和一个可丢弃的
原因