【问题标题】:Iterating from the end to the beginning of a single-linked list without reversing it从单链表的末尾迭代到开头而不反转它
【发布时间】:2018-10-19 14:50:24
【问题描述】:

假设我有一个单链表,其中包含从文件中收集的单词,我希望能够从该文件中从头到尾以及从尾到头打印这些单词。第一个选项的执行被这样编码:

void writeWords(t_list *lp, FILE *fp, int total_num_words) {
    t_list *aux; 
    aux = lp;
    while(aux != NULL){
      writeOneWord((t_word*) getItemList(aux), fp, total_num_words);
      aux = getNextListElement(aux);
    }
}

即按正常顺序迭代列表,每个节点的内容由writeOneWord打印。

现在,我的疑问是:正如我所说,我也希望能够从头到尾遍历列表,同时保持列表不变,所以 没有反转时间>。我知道代码应该对应于某种递归实现,但直到现在我一直试图这样做无济于事。任何人都可以对此有所了解吗?

【问题讨论】:

  • 您当然意识到,虽然您可以这样做,但如果必须这样做,则表明单链表是选择的错误数据结构。
  • 您说要保留链表。临时修改可以吗?如果允许临时修改,则只需恒定的内存开销即可完成(与递归不同)。

标签: c list recursion


【解决方案1】:

你肯定想要一个递归函数。

让函数自己调用,传入列表中的下一项,然后在递归调用返回后打印该项。这样,列表的末尾会先打印出来。

void writeWords(t_list *lp, FILE *fp, int total_num_words) {
    if (lp != NULL) {
        writeWords(getNextListElement(lp), fp, total_num_words);
        writeOneWord((t_word*) getItemList(lp), fp, total_num_words);
    }
}

【讨论】:

  • 如果total_num_words 足够大,它很快就会崩溃。堆上有更多空间。
  • 它比我预期的更有效并且更直观。谢谢!
【解决方案2】:

您应该使用双向链表。但这里有一个解决方法:

void writeWordsBackwards(t_list *lp, FILE *fp, int total_num_words) {
    size_t i = 0;
    t_list words[total_num_words];
    for (size_t i = 0; lp && i < total_num_words; i += 1) {
        words[i] = lp;
        lp = getNextListElement(lp);
    }
    while (i >= 0) {
      writeOneWord((t_word*) getItemList(words[i]), fp, total_num_words);
      i -= 1;
    }
}

与递归方法不同,它使用的堆栈空间更少。但它仍然需要可能无限量的堆栈空间; malloc 可能更适合避免堆栈溢出。

【讨论】:

  • 您绝对应该为此使用堆。
  • 好吧,因为这个练习特别是关于学习如何递归地进行,所以我将使用 dbush 的答案。但是,我确实考虑过这一点,并且您的实现似乎功能强大且有用,因此您获得了荣誉奖。谢谢!
猜你喜欢
  • 2015-10-01
  • 2012-10-08
  • 1970-01-01
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-06
相关资源
最近更新 更多