线性链表是一组节点。这就是节点的定义方式(为了方便起见,我们不区分节点和列表):
class Node{
Object data;
Node link;
public Node(Object pData, Node pLink){
this.data = pData;
this.link = pLink;
}
public String toString(){
if(this.link != null){
return this.data.toString() + this.link.toString();
}else{
return this.data.toString() ;
}
}
public void inc(){
this.data = new Integer((Integer)this.data + 1);
}
public void lappend(Node list){
Node child = this.link;
while(child != null){
child = child.link;
}
child.link = list;
}
public Node copy(){
if(this.link != null){
return new Node(new Integer((Integer)this.data), this.link.copy());
}else{
return new Node(new Integer((Integer)this.data), null);
}
}
public Node invert(){
Node child = this.link;
while(child != null){
child = child.link;
}
child.link = this;....
}
}
我能够制作清单的深层副本。现在我想反转列表,以便第一个节点是最后一个节点,也是最后一个节点。倒置列表必须是深层复制。
我开始开发反转功能,但我不确定。任何想法?
更新:可能有一种递归方式,因为线性链表是递归数据结构。
我会接受第一个元素,遍历列表,直到我到达一个没有子节点的节点并附加第一个元素,我会重复第二个,第三个元素....
答案 0 :(得分:4)
我有时会在采访中提出这个问题......
我不建议使用递归解决方案或使用堆栈来解决此问题。为此类任务分配 O(n)内存毫无意义。
这是一个简单的 O(1)解决方案(我现在没有运行它,所以如果需要进行一些修正,我会道歉。)
Node reverse (Node current) {
Node prev = null;
while (current != null) {
Node nextNode = current.next;
current.next = prev;
prev = current;
current = nextNode;
}
return prev;
}
BTW:lappend
方法有效吗?似乎总会抛出一个NullReferenceException
。
答案 1 :(得分:3)
基于以下观察,这个问题有一个很好的递归解决方案:
因此,您可以使用伪代码实现反向函数:
void reverseList(Node node) {
if (node == null) return; // Reverse of empty list is itself.
if (node.next == null) return; // Reverse of singleton list is itself.
reverseList(node.next); // Reverse the rest of the list
appendNodeToList(node, node.next); // Append the new value.
}
此算法的简单实现在O(n 2 )中运行,因为每次反转都需要追加,这需要对列表的其余部分进行O(n)扫描。但是,你可以使用聪明的观察实际在O(n)中使用它。假设您有一个如下所示的链接列表:
n1 --> n2 --> [rest of the list]
如果您从n2开始反转列表,那么您最终会得到以下设置:
n1 [reverse of rest of the list] --> n2
| ^
+------------------------------------------+
因此,您可以通过设置n1.next.next = n1
来将n1追加到列表其余部分的反面,这会将n2
(反向列表的新结尾)更改为指向n1:
[reverse of the rest of the list] --> n2 --> n1
你是金色的!再次更多伪代码:
void reverseList(Node node) {
if (node == null) return; // Reverse of empty list is itself.
if (node.next == null) return; // Reverse of singleton list is itself.
reverseList(node.next); // Reverse the rest of the list
node.next.next = node; // Append the new value.
}
编辑:正如Ran指出的那样,这会将调用堆栈用于其存储空间,从而存在堆栈溢出的风险。如果你想使用显式堆栈,你可以这样做:
void reverseList(Node node) {
/* Make a stack of the reverse of the nodes. */
Stack<Node> s = new Stack<Node>();
for (Node curr = node; node != null; node = node.next)
s.push(curr);
/* Start unwinding it. */
Node curr = null;
while (!s.empty()) {
Node top = s.pop();
/* If there is no node in the list yet, set it to the current node. */
if (curr == null)
curr = top;
/* Otherwise, have the current node point to this next node. */
else
curr.next = top;
/* Update the current pointer to be this new node. */
curr = top;
}
}
我认为这类似地反转了链表元素。
答案 2 :(得分:2)
我会将当前列表视为堆栈(这是我的伪代码):
Node x = copyOf(list.head);
x.link = null;
foreach(node in list){
Node temp = copyOf(list.head);
temp.link = x;
x = temp;
}
最后x
将成为颠倒列表的头部。
答案 3 :(得分:1)
我对C更熟悉,但还是让我试试。 (我只是不确定它是否在Java中运行,但它应该)
node n = (well first one)
node prev = NULL;
node t;
while(n != NULL)
{
t = n.next;
n.next = prev;
prev = n;
n = t;
}
答案 4 :(得分:1)
反转单链表是一个经典问题。这里也回答了(并且得到了很好的回答),它不需要递归也不需要额外的内存,除了用于引用保持的寄存器(或2)。 然而对于OP,我想这是一个学校项目/家庭作业和一些建议,如果你曾经使用单链表进行一些真正的数据存储,也可以考虑使用尾节点。 (截至目前,单个链接列表几乎已经绝迹,但我想到了HashMap存储桶)。 除非你必须在'add'期间检查所有节点的某些条件,否则尾部是一个很大的改进。下面是一些代码,它们具有反向方法和尾节点。
package t1;
public class SList {
Node head = new Node();
Node tail = head;
private static class Node{
Node link;
int data;
}
void add(int i){
Node n = new Node();
n.data = i;
tail = tail.link =n;
}
void reverse(){
tail = head;
head = reverse(head);
tail.link = null;//former head still links back, so clear it
}
private static Node reverse(Node head){
for (Node n=head.link, link; n!=null; n=link){//essentially replace head w/ the next and relink
link = n.link;
n.link = head;
head = n;
}
return head;
}
void print(){
for (Node n=head; n!=null;n=n.link){
System.out.println(n.data);
}
}
public static void main(String[] args) {
SList l = new SList();
l.add(1);l.add(2);l.add(3);l.add(4);
l.print();
System.out.println("==");
l.reverse();
l.print();
}
}
答案 5 :(得分:0)
我想知道这样的事情(我没有测试过,所以):
invert(){
m(firstNode, null);
}
m(Node v, Node bef){
if(v.link != null)
m(v.link,v);
else
v.link=bef;
}
答案 6 :(得分:0)
没有太多测试,
Node head = this;
Node middle = null;
Node trail = null;
while (head != null) {
trail = middle;
middle = head;
head = head.link;
middle.link = trail;
}
head = middle;
return head;
答案 7 :(得分:0)
public ListNode Reverse(ListNode list)
{
if (list == null) return null;
if (list.next == null) return list;
ListNode secondElem = list.next;
ListNode reverseRest = Reverse(secondElem);
secondElem.Next = list;
return reverseRest;
}
希望这有帮助。