簡體   English   中英

Java使用帶有LinkedList的節點

[英]Java Using Nodes with LinkedList

我一直在研究我最近購買的一本書中的一些標准編碼面試問題,並且遇到以下問題和答案:

實現一種算法,以找到鏈表中的第n個元素。

這是提供的答案:

public static LinkedListNode findNtoLast(LinkedListNode head, int n) { //changing LinkedListNode to ListNode<String>
        if(head == null || n < 1) {
            return null;
        }
        LinkedListNode p1 = head;
        LinkedListNode p2 = head;
        for(int j = 0; j < n-1; ++j) {
            if(p2 == null) {
                return null;
            }
            p2 = p2.next;
        }
        if(p2 == null) {
            return null;
        }
        while(p2.next != null) {
            p1 = p1.next;
            p2 = p2.next;
        }
        return p1;
    }

我了解該算法,其工作原理以及為什么書將其列出為答案,但我對如何訪問LinkedListNodes作為方法的參數發送感到困惑。 我知道我必須創建一個LinkedListNode類(因為Java還沒有一個類),但是我似乎無法弄清楚該怎么做。 這令人沮喪,因為我覺得我應該知道該怎么做。 這是我一直在努力的事情。 如有任何澄清,我將不勝感激。 您可以擴展/評論我的代碼,也可以提供自己的選擇。 謝謝。

class ListNode<E> {
    ListNode<E> next;
    E data;

    public ListNode(E value) {
        data = value;
        next = null;
    }

    public ListNode(E value, ListNode<E> n) {
        data = value;
        next = n;
    }

    public void setNext(ListNode<E> n) {
        next = n;
    }
}

public class MyLinkedList<E> extends LinkedList {
    LinkedList<ListNode<E>> list;
    ListNode<E> head;
    ListNode<E> tail;
    ListNode<E> current;
    ListNode<E> prev;

    public MyLinkedList() {
        list = null;
        head = null;
        tail = null;
        current = null;
        prev = null;
    }

    public MyLinkedList(LinkedList<E> paramList) {
        list = (LinkedList<ListNode<E>>) paramList; //or maybe create a loop assigning each ListNode a value and next ptr
        head = list.getFirst();
        tail = list.getLast(); //will need to update tail every time add new node
        current = null;
        prev = null;
    }

    public void addNode(E value) {
        super.add(value);
        //ListNode<E> temp = tail;
        current = new ListNode<E>(value);
        tail.setNext(current);
        tail = current;
    }

    public LinkedList<ListNode<E>> getList() {
        return list;
    }

    public ListNode<E> getHead() {
        return head;
    }

    public ListNode<E> getTail() {
        return tail;
    }

    public ListNode<E> getCurrent() {
        return current;
    }

    public ListNode<E> getPrev() {
        return prev;
    }


}

LinkedListNode如何從LinkedList前進?

更新:我認為我的部分困惑來自主要方法中的內容。 我是否需要創建ListNode的LinkedList? 如果這樣做,我將如何將ListNode彼此連接? 在不使用LinkedList集合對象的情況下如何連接它們? 如果有人可以告訴我他們如何編寫主要方法,那么我認為這將使我有足夠的視角來解決問題。 這是我對main方法的最新嘗試:

public static void main(String args[]) {
        LinkedList<ListNode<String>> list = new LinkedList<ListNode<String>>();
        //MyLinkedList<ListNode<String>> list = new MyLinkedList(linkedList);
        list.add(new ListNode<String>("Jeff"));
        list.add(new ListNode<String>("Brian"));
        list.add(new ListNode<String>("Negin"));
        list.add(new ListNode<String>("Alex"));
        list.add(new ListNode<String>("Alaina"));
        int n = 3;
        //ListIterator<String> itr1 = list.listIterator();
        //ListIterator<String> itr2 = list.listIterator();
        LinkedListNode<String> head = new LinkedListNode(list.getFirst(), null);
        //String result = findNtoLast(itr1, itr2, n);
        //System.out.println("The " + n + "th to the last value: " + result);
        //LinkedListNode<String> nth = findNtoLast(list.getFirst(), n);
        ListNode<String> nth = findNtoLast(list.getFirst(), n);
        System.out.println("The " + n + "th to the last value: " + nth);
    }

為了在不使用自定義鏈接列表類的情況下連接節點,我將ListNode類編輯為以下內容:

class ListNode<E> {
    ListNode<E> next;
    ListNode<E> prev; //only used for linking nodes in singly linked list
    ListNode<E> current; //also only used for linking nodes in singly linked list
    E data;
    private static int size = 0;

    public ListNode() {
        data = null;
        next = null;
        current = null;
        if(size > 0) { //changed from prev != null because no code to make prev not null
            prev.setNext(this);
        }
        size++;
    }
    public ListNode(E value) {
        data = value;
        next = null;
        current = this;
        System.out.println("current is " + current);
        if(size > 0) {
            prev.setNext(current);//this line causing npe
        }
        else
        {
            prev = current;
            System.out.println("prev now set to " + prev);
        }
        size++;
        System.out.println("after constructor, size is " + size);
    }

    public ListNode(E value, ListNode<E> n) {
        data = value;
        next = n;
        current = this;
        if(size > 0) {
            prev.setNext(this);
        }
        size++;
    }

    public void setNext(ListNode<E> n) {
        next = n;
    }
}

現在,程序將運行直到達到prev.setNext(current);。 在ListNode的單個參數構造函數中。 達到此行時,current和prev都不為空。 任何建議將不勝感激。 謝謝。

您實際上不需要單獨的LinkedList類; ListNode類一個鏈表。 或者,換句話說,對列表頭的引用是對列表的引用。

您發布的示例代碼中使用head,tail,current,prev來自雙重鏈接列表,該列表是一種雙向雙向鏈接的數據類型。 對於某些類型的應用程序(例如查找第n個最后一項),這更有效。

因此,我建議將您的ListNode類重命名為LinkedList並在tail next重命名。

要將新項目添加到列表中,您需要一個方法來創建一個新列表,其中新項目位於其頂部。 這是一個例子:

class LinkedList<E> {
    ...

    private LinkedList(E value, LinkedList<E> tail) {
        this.data = value;
        this.tail = tail;
    }

    public LinkedList<E> prependItem(E item) {
        return new LinkedList(item, this);
    }
}

然后,要添加新項ilist請使用list = list.prependItem(i);

如果出於某種原因您需要始終將項目添加到末尾,則:

private LinkedList(E value) {
    this.data = value;
    this.tail = null;
}

public void appendItem(E item) {
    LinkedList<E> list = this;
    while (list.tail != null)
        list = list.tail;
    list.tail = new LinkedList<>(item);
}

但是,對於長列表來說,這顯然效率很低。 如果需要執行此操作,則可以使用其他數據結構,也可以在添加完畢后反轉列表。

順便說一下,這樣做的一個有趣的副作用是,對列表中任何項目的引用都是對鏈接列表的引用。 這使得遞歸非常容易。 例如,這是一個用於查找列表長度的遞歸解決方案:

public int getLength(LinkedList list) {
    if (list == null) {
        return 0;
    } else {
        return 1 + getLength(list.getTail());
    }
}

並使用此簡單(但效率很低!)解決方案來解決您提供的問題-我將方法重命名為使其功能更加明顯:

public LinkedList getTailOfListOfLengthN(LinkedList list, int n) {
    int length = getLength(list);
    if (length < n) {
        return null;
    } else if (length == n) {
        return list;
    } else {
        return getTailOfLengthN(list.getTail(), n);
    }
}

並反轉列表:

public LinkedList<E> reverse() {
    if (tail == null) {
        return this;
    } else {
        LinkedList<E> list = reverse(tail);
        tail.tail = this;
        tail = null;
        return list;
    }
}

我希望您能看到,這使方法比分離節點列表類要優雅得多。

實際上,您已經使用ListNode類創建了一個鏈接列表。

鏈表由節點和對另一個鏈表的引用組成(請參閱遞歸?)。

暫無
暫無

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

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