简体   繁体   English

递归地从链接列表中删除节点

[英]Remove node from linked list recursively

Given the head of a linked list and the int to search for as parameters, I need a method that will remove the first occurrence of this number in the list, and return the modified list. 给定链接列表的头和要搜索的int作为参数,我需要一个方法,该方法将删除列表中该数字的第一个匹配项,并返回修改后的列表。 however i cannot modify the original list. 但是我不能修改原始列表。 I know how to remove the node from the list, but im not sure how i would keep the original list intact since this has to be done recursively. 我知道如何从列表中删除该节点,但是我不确定如何将原始列表保持完整,因为这必须递归进行。 below is the method ** initially M is the original list. 下面是方法**最初,M是原始列表。 I dont know that it will still be the same list after calling the method again...? 我不知道再次调用该方法后它仍然是相同列表...?

MyList removeNumber(MyList m, int removee){
//This function will always return a new list with 'remove' removed
MyList removeNumber(MyList m, int remove){
//if m is empty List, return an empty list

//if head is not the int to remove, return a New list from 
//   head concat removeNumber(m.next,remove)
//else return removeNumber(m.next,remove)
}

I think it lacks information. 我认为它缺乏信息。 I'm assuming however a very traditional implementation for linked list, for instance: 但是,我假设是链表的非常传统的实现,例如:

class MyList {

  MyList prev;
  MyList next;
  int data;

  static MyList removeNumber(MyList m,int removee) {

    if(m == null) return null; // already empty

    if(m.data == removee) { // m already is the node to throw away

      if(m.prev != null)// relink
        m.prev.next = m.next;

      if(m.next != null)// relink
        m.next.prev = m.prev;

      return m.prev;
    }
    // if this node isn't the one yet, keep looking for
    return removeNumber(m.next,removee); 
  }
}

There are plenty different ways to do that, but you have to provide more info in order to allow us to point you the correct literature. 有很多不同的方法可以做到这一点,但是您必须提供更多的信息,以便我们为您指出正确的文献。

The idea is that the resulting structure will be a "Y": a two-headed list (actually a simple graph). 这个想法是,结果结构将是“ Y”:一个双向列表(实际上是一个简单的图形)。

One branch of the Y is the original list. Y的一个分支是原始列表。 The other is your new list with removed node. 另一个是已删除节点的新列表。 The vertical stalk of the Y is what's after the element you remove. Y的垂直杆是删除元素之后的位置。 It's common to both lists. 这是两个列表的共同点。 Here's some ascii art with the Y turned on its side showing a list of 1 to 5 with 3 removed. 这是一些带有Y字样的ascii艺术,显示了从1到5的列表,其中删除了3。

     new -> 1 -> 2 ------\
                          v
original -> 1 -> 2 -> 3 -> 4 -> 5 -> null

Thinking recursively is all about defining a problem in terms of a smaller version of itself plus a fixed bit of work. 递归思考就是根据较小的自身版本和固定的工作量来定义问题。 And you need a base case (or maybe several). 您需要一个基本案例(或几个案例)。

A linked list is itself a recursive structure: 链表本身就是一个递归结构:

A list is either empty or it's an element linked by its "next" reference to a list. 列表为空,或者是通过其对列表的“下一个”引用链接的元素。

Note this defines a list using a smaller list. 请注意,这使用较小的列表定义了一个列表。 The base case is the empty list. 基本情况是空列表。 The fixed bit is the element. 固定位是元素。

Read this definition a few times, then see how it translates the code: 多次阅读此定义,然后查看其如何翻译代码:

class MyList {
  int value;    // the element at the head of this list
  MyList next;  // the rest of the list

  MyList(int value, MyList next) {
    this.value = value;
    this.next = next;
  }
}

The base case "empty list" is just a null reference. 基本情况“空列表”只是一个null引用。 The element removal problem expressed recursively using the same pattern becomes: 使用相同模式递归表示的元素删除问题变为:

A copy of a list with an element removed is either a) the rest of the list following the head in the case that the element to be removed is the head or b) a copy of the current node followed by a copy the rest of the list with the desired element removed. 删除了元素的列表的副本是a)如果要删除的元素是head,则列表的其余部分在头部之后,或者b)当前节点的副本,然后是副本的其余部分删除所需元素的列表。

Here I'm defining a "copy of a list with one element removed" using a smaller version of the same thing. 在这里,我使用相同版本的较小版本定义“删除一个元素的列表副本”。 Case a) is the base case. 情况a)是基本情况。 The fixed bit is copying the head when it's not the removee . 当固定位不是 removee时,它正在复制头部。

Of course there's another base case: if the list is empty, the removee can't be found. 当然,还有另一种基本情况:如果列表为空,则removeeremovee者。 That's an error. 那是一个错误。

Putting this in code: 将其放入代码中:

MyList removeNumber(MyList m, int removee) {
  if (m == null) throw new RuntimeException("removee not found");
  if (m.value == removee) return m.next;
  return new MyList(m.value, removeNumber(m.next, removee));
}

Putting the function to use would look something like this: 使用该函数将如下所示:

MyList originalList = ... // list of 1 to 5.
MyList newListWith3removed = removeNumber(originalList, 3);

System.out.println("Original list:");
for (MyList p : originalList) System.out.println(p.value); 
System.out.println("With 3 removed:");
for (MyList p : newListWith3removed) System.out.println(p.value);

The output will look as expected: 1 to 5 in the first list and 1,2,4,5 in the second. 输出将看起来像预期的那样:第一个列表中为1到5,第二个列表中为1,2,4,5。 Ie the first list is unchanged. 即第一个列表是不变的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM