【问题标题】:Reverse-printing single-linked list反向打印单链表
【发布时间】:2012-04-08 13:22:35
【问题描述】:

任何人都知道如何以相反的顺序打印单链表(一次通过和固定且独立于 RAM 元素的数量)。

【问题讨论】:

  • 定义“一次通过”。展开时打印的递归实现是否算数?
  • 单链表的重点不就是他们只有前向引用吗?因此,据我所知,您必须通过才能到达最后一个元素,然后向后打印(通过 2)。我错了吗?
  • @OliCharlesworth:嘿,我认为技术上是“一次通过”。
  • 那我看不出它怎么可能。如果你不保存对元素的引用,那么当你到达最后一个时,你就不再知道以前的了。
  • 你的面试官都是混蛋。

标签: algorithm data-structures linked-list


【解决方案1】:

我的回答。没有答案可以解决您的规格问题。它不能是多遍的,它不能是递归的(我认为它被认为是单一的),它必须是恒定的记忆......

我认为您不会找到解决方案,并且说您可以做到的人显然对问题有某种形式的诡计。他们显然没有使用该社区正在使用的同一组定义。

【讨论】:

  • ...然后我去了电影学校。巴姆。哈哈
  • recursive 不是“恒定 RAM”,它会占用运行时堆栈上的 O(n) RAM。
  • @WillNess:我关于递归的评论不是指内存。它指的是“一次性”要求。常量内存是一个单独的要求。
  • 它仍然是要求之一,因此递归从来都不是一种选择。即它不是OP的额外任意限制。事实证明 使用文件 是一个答案。
  • @WillNess:我觉得你可能误解了我的回答。此外,OP 在主 cmets 中明确表示不允许递归,这使得在堆栈展开中可以做到这一点。我只是指出,限制的组合使我们大多数人都不清楚答案。这里的许多答案不断达到一些标准。如果使用文件是答案,那么我对该答案的评论是正确的,即面试官在问题范围内存在欺骗或缺乏定义的问题。
【解决方案2】:

我认为你可以在 O(n) 时间和 O(1) 空间内做到这一点,但从技术上讲,这不是“一次通过”。

  1. 反转链表:O(n)
  2. 打印:O(n)
  3. 将链表反向:O(n)

【讨论】:

  • 什么是reverce?一关怎么做?
  • 当它显然是另一个多通道解决方案时,提出这个答案的意义何在?
  • 2.和 3. 被简单地组合成 one pass:在重新链接列表时打印每个节点。 两次 次,恒定 RAM,sane 解决方案。 :)
【解决方案3】:

此选项假定您知道计数(如果不是已经过去了一次),或者如果您必须使用一次,则不知道计数,那么只需将计数设置为某个合理的较大最大上限价值。

long count = 10000; // set this to whatever the count is, or calcualte it
string filename = @"c:\foo.out";
using (StreamWriter writer = new StreamWriter(filename))
{
    int index = 0;
    long maxLength = 12; // set this to the max length of an item + 2 (for /r/n)
    while(values.Next())
    {
        writer.BaseStream.Seek(maxLength * (count - index - 1), SeekOrigin.Begin);
        writer.WriteLine(values[index].ToString().PadLeft(maxLength));
        writer.Flush();
        index++;
    }
}

输出将在c:\foo.out 文件中,由空格填充。由于问题没有说明您需要在哪里输出,或者输出应该采用什么格式(例如不预先包含空白行)。鉴于它是一个链表,其长度可能非常大 (>int.MaxValue),因此将输出写入文件是一种非常合理的传输格式。

这个答案既满足O(n) 写入性能(确实是一次通过),同时也没有使用比输出流额外的内存,而输出流总是必须成为O(n),因为否则您将如何将它们全部放在屏幕上..

对此答案的回应是您不能在输出流中向后seek,然后只需打印一个\r 返回字符并以这种方式向后搜索,未能回复面试官询问是否识别或见面不可能的要求是工作描述的一部分。

【讨论】:

  • 看,这是我建议面试官知道他们问题的某种技巧定义的一个例子。虽然实时输出正按正序“打印”到文件中,但从技术上讲,生成的文件将以相反的顺序排列。但话又说回来,有人可能会争辩说该文件尚未“打印”。也许面试官并不像您建议的那样表示标准输出。也许输出需要在被访问时打印到终端,而您的需要最终打印文件(通过 2)。没有办法真正确定。
  • 所以你欺骗了骗子,你使用文件而不是 RAM。关于文件什么都没有说,所以为什么还要用空行来打扰 - 只需使用 两个 文件,即使使用 system 调用,也可以在行前添加。
【解决方案4】:
String s ="";
for(each element el in list)
     s=el.data+", "+s;
 println(s);

这是一张。

【讨论】:

  • 再次保存..“与 RAM 的元素数量无关”
【解决方案5】:

这是一个使用 java.util.LinkedList 的解决方案 由于您将元素删除并添加到同一列表中,因此内存保持不变。 我认为可以合理地假设任何体面的单链表实现都会跟踪其大小、头部和尾部。

import java.util.Arrays;
import java.util.LinkedList;

class PrintReverse {
    public static void main(String[] args) {
        Integer[] array = {1, 2, 3, 4};
        LinkedList<Integer> list = new LinkedList<Integer>(Arrays.asList(array));
        System.out.println(list);
        printListBackward(list);
    }

    public static void printListBackward(LinkedList<Integer> list) {
        int size = list.size();

        for (int i = 0; i < size; i++) {
            Integer n = list.removeLast();
            list.push(n);
            System.out.println(n.toString());
        }
        System.out.println(list);

    }
}

这会产生以下输出...

[1, 2, 3, 4]
4
3
2
1
[1, 2, 3, 4]

你怎么看?

【讨论】:

  • 嗨 Luis,我扩展了您的代码以使其完整,并显示了生成的输出。我认为这个答案实际上满足了 OP 的规定要求。我觉得很好。
  • 错误。每个removeLast() 本身就是一个通行证,n 通行证总数。正常的重新链接解决方案是 2 遍,而 OP 想要 1 遍 - 具有恒定的 RAM。
【解决方案6】:

嗯,你没有说它必须高效。 (另外,可能没有更高效的常量内存实现。)此外,正如评论者所指出的,这仅在 length(list) == 1 时是一次性的。

void printReversedLinkedList(listptr root) {
    listptr lastPrinted = null;
    while (lastPrinted != root) {
        listptr ptr = root;  // start from the beginning of the list
        // follow until next is EoL or already printed
        while (ptr->next != null && ptr->next != lastPrinted)
            ptr = ptr->next;
        // print current node & update last printed
        printf("%s", ptr->data);
        lastPrinted = ptr;
    }

恒定内存,O(n^2) 效率。

【讨论】:

  • 我不会称之为“一次性”。
  • 这在技术上不被认为是“两次通过”吗?
  • 这里的问题是它可能满足 OP 的一些给定标准,但不是全部
  • @jdi 2 过得怎么样?这是 n/2 次传球,平均。两遍是O(n),n遍是O(n^2)。
【解决方案7】:
void printList(listItem node) {
    if (node.next != null) {
        printList(node.next);
    }

    echoOrSystemOutPrintlnOrPrintfOrWhatever(node.data);
}

printList(rootNode);

【讨论】:

  • OP 说它不能递归。否则这已经是一个答案了:-/
  • 啊,在 cmets 中错过了:s
【解决方案8】:

导入数组,逆序打印数组。

【讨论】:

  • "与RAM的元素数量无关"
【解决方案9】:

遍历单链表并将每个项目压入堆栈。弹出堆栈直到它为空,同时打印出每个弹出的元素。

node  = head of node list
stack = new Stack()

while ( node is not NULL )
{
    stack.push( node.data )
    node = node.next
}

while ( !stack.empty() )
{
    print( stack.pop() )
}

【讨论】:

  • "与RAM的元素数量无关"
【解决方案10】:

我真的很想知道如何反向遍历单链表。

【讨论】:

  • @StanleyZ : 这是一个双向链表
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-19
  • 1970-01-01
  • 1970-01-01
  • 2020-09-29
  • 2020-09-05
  • 2021-11-30
相关资源
最近更新 更多