使用递归进行自定义链表

时间:2013-07-22 21:13:38

标签: java

对于家庭作业,我被告知要编写自定义链表的插入方法(按顺序)。我写了基本案例,但我仍然不理解递归案例。我知道我刚刚问过如何编写contains方法并且有人帮助了我,但在这种情况下,我没有像这种方法那样对列表进行任何修改。请帮助我了解导致我的链表重写的原因以及是否有更简单的方法来简化我的代码。

这是我的代码:

public class OrderedList {

private Node first;

//Constructor
public OrderedList() {
    this.first = null;
}

//Return the number of items in the list
public int size() {
    int counter = 0;
    Node pointer = this.first;
    while (pointer != null) {
        counter++;
        pointer = pointer.next;
    }
    return counter;
}

//Return an array of copies of the stored elements
public Comparable[] getStore() {

    Comparable[] elements = new Comparable[size()];
    Node pointer = this.first;
    if (this.first == null) {
        return elements;
    } else {
        int i = 0;
        while (pointer != null) {
            elements[i] = pointer.data;
            pointer = pointer.next;
            i++;
        }
        return elements;
    }

}
//true iff item matches a stored element
//Recursive

public boolean contains(Comparable item) {

    return containsHelper(this.first, item);

}

private boolean containsHelper(Node node, Comparable item) {
    //base case
    if (node == null) {
        return false;
    } else {
        if (node.data.compareTo(item) == 0) {
            return true;
        }

        return containsHelper(node.next, item);
    }

}
//Add item preserving the order of the elements
//Recursive

public void insert(Comparable item) {

    insertHelper(this.first, item);

}

public void insertHelper(Node pointer, Comparable item) {
    //Base case
    Node store = new Node(item);

    if (pointer == null) {
        store.next = this.first;
        this.first = store;

        return;
    }
    if (pointer.data.compareTo(item) > 0 ) {
        store.next = pointer;


        return;
    }
    if (pointer.data.compareTo(item) < 0 && pointer.next == null) {
        store.next = pointer.next;
        pointer.next = store;

        return;

    } else {

        Node save = this.first;
        this.first = this.first.next;

        insertHelper(this.first, item);

        if (pointer.data.compareTo(item) > 0) {
            save.next = store;
            this.first = save;
        } else {
            save.next = pointer;
            this.first = save;
        }

    }

}

1 个答案:

答案 0 :(得分:1)

我一开始只给你部分答案。考虑一下这个线索。然后有更多的线索。看看你是否可以在到达答案的底部之前搞清楚。

线索1

这部分代码不能在递归方法中,因为它引用了链表的头部。您的递归向下移动到列表中,将其分解为头部和其余部分,决定是否插入头部并在插入必须在其余部分时进行递归。

if (pointer == null) {
    store.next = this.first;
    this.first = store;

    return;
}

这应该稍微修改一下,以便它可以进入insert()方法,该方法处理整个列表。

为什么?

因为此代码处理整个列表并询问问题,“此列表是否为空?”

线索2

现在,对于这部分代码:

if (pointer.data.compareTo(item) > 0 ) {
    store.next = pointer;
    return;
}

注意它是如何引用整个列表的。这是件坏事。

它问的问题是,“新项目(待插入)是否应该在当前头项目之前?”

如果答案是肯定的,则需要将其插入当前头部的前面,将当前头部与当前连接的链接列表保持一致,并返回一些内容,使调用代码附加新安排的其余部分。清单。

if (pointer.data.compareTo(item) > 0 ) {
    store.next = pointer; // new item goes in front of this part of list
    return store;
}

线索3

现在,让我们跳到代码的这一部分:

Node save = this.first;
this.first = this.first.next;

insertHelper(this.first, item);

if (pointer.data.compareTo(item) > 0) {
    save.next = store;
    this.first = save;
} else {
    save.next = pointer;
    this.first = save;
}

此代码不会提出任何问题。它只是递归,因为我们知道不需要对当前链表的头部进行任何更改。当我们递归时,我们将链接列表的其余部分传递给它并告诉它解决这个问题。我们不关心如何,因为我们相信它通过在正确的位置插入新项目来修复列表的其余部分。

以下是我们的工作:

Node rest = insertHelper(pointer.next, item);
pointer.next = rest;
return pointer;

线索4

这部分代码是最后要考虑的部分:

if (pointer.data.compareTo(item) < 0 && pointer.next == null) {
    store.next = pointer.next;
    pointer.next = store;

    return;

} 

现在,想想你为什么要再次比较它。之前的代码测试了该项是否需要在链表的其余部分之前。答案是否定的。

这意味着只剩下两种可能的情况。

列表中没有任何内容......我们必须将新项目放在最后。

或者列表中有一些东西......并且线索3通过递归处理它。

所以这部分变得更简单了:

if (pointer.next == null) {
    return store;
} 

我们所要做的就是返回新节点,这将是新的“列表的其余部分”,而不是列表的其余部分。

再补充一点

请记住,方法签名必须更改为:

/**
 * Insert the 'item' into the linked list beginning with the supplied node, 'pointer'
 * @returns the new, modified linked list, with the new item in it.
 */
public Node insertHelper(Node pointer, Comparable item) {

整件事

这包括对'insert'方法的更改:

public void insert(Comparable item) {
   // if there isn't anything in the list, the new item becomes the whole list
   if (first == null) {
        Node store = new Node(item);
        store.next = null;
        this.first = store;
        return;
    }

    // Otherwise let the helper fix up the list for us to store away
    this.first = insertHelper(this.first, item);
}

public Node insertHelper(Node pointer, Comparable item) {
    Node store = new Node(item);

    if (pointer.data.compareTo(item) > 0 ) {
        store.next = pointer; // new item goes in front of this part of list
        return store;
    }

    if (pointer.next == null) {
        return store; // new item becomes this part of the list
    }

    // The head of this part of the list is ok, fix the rest of the list

    pointer.next = insertHelper(pointer.next, item);
    return pointer;
}

进一步评论

还有另一种方法可以将第一个节点存储在其他类中,每个Node只存储一个指向列表其余部分的指针(next)。

然后你有一个insert的方法知道它何时被调用它不能为null,因为如果它为null则你不能调用它。

由于这个原因,insert内没有第一个为空的测试。但这意味着调用者必须执行以下操作:

Node item = new Node(data);
if (list != null) {
    list.insert(item);
} else {
    list = item;
}

并且insert方法如下所示:

if (this.next == null || this.data > item.data) { // pseudo code for greater than
    item.next = this.next;
    this.next = item;
    return;
}
this.next.insert(item);

就是这样。