【发布时间】:2015-02-26 04:11:47
【问题描述】:
我一直在研究我最近买的一本书中的一些标准编码面试问题,我遇到了以下问题和答案:
实现一个算法来查找链表中倒数第 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 中获取?
更新:我认为我的部分困惑来自于在 main 方法中放入什么。我需要创建 ListNode 的 LinkedList 吗?如果我这样做,我将如何将 ListNodes 相互连接?在不使用 LinkedList 集合对象的情况下如何连接它们?如果有人可以向我展示他们将如何编写 main 方法,我认为这将使我有足够的视角来解决我的问题。这是我对 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 类的一部分。然后它将能够访问(假定为私有的)字段头。
-
我看到你已经继承了 java.util.LinkedList。子类化然后实现自己的节点类没有多大意义。 LinkedList 已经有一个名为 Entry 的私有类用于此目的。正如您提到的,您无权访问它,因此您无法使用 LinkedList 子类实现您展示的算法。正如我在回答中指出的那样,您必须创建自己的。
-
如果您有兴趣了解 LinkedList 的工作原理,您可以在 developer.classpath.org/doc/java/util/LinkedList-source.html 上查看 LinkedList 的源代码。您会看到它实际上是一个双链表(next 和 prev 引用)。这是允许从中间移除项目所必需的。
标签: java nodes singly-linked-list