簡體   English   中英

對自定義鏈表使用遞歸

[英]Using recursion for a custom linkedlist

對於家庭作業,我被告知要編寫自定義鏈接列表的插入方法(按順序)。 我寫了基本案例,但是我仍然不理解遞歸案例。 我知道我只是問過如何編寫contain方法,有人幫助了我,但是在那種情況下,我不必像這種方法那樣對列表做任何修改。 請幫助我了解導致鏈接列表被覆蓋的原因以及是否有更簡單的方法來簡化代碼。

這是我的代碼:

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

這部分代碼不能在遞歸方法中使用,因為它引用了鏈表的頭部。 您的遞歸在列表中向下移動,將其分解為頭部和其余部分,並決定是否在頭部插入,然后再次進行是否必須在其余部分插入的操作。

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) {

整個東西

這包括對“插入”方法的更改:

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內部第一個是否為null。 但這意味着呼叫者必須執行以下操作:

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

插入方法如下所示:

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);

就是這樣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM