【问题标题】:Is it possible to create a linked list on the stack in C++?是否可以在 C++ 中的堆栈上创建链表?
【发布时间】:2010-12-06 02:36:11
【问题描述】:

我几周前才开始学习 C++。所以现在我有这个学校作业问题,要求我在不使用“new”或任何与动态分配内存有关的情况下实现一个链表(并且不能使用来自 STL 的任何 ADT)。教授说一切都可以在堆栈上完成,但是怎么做呢?自周五以来我一直在努力,但仍然坚持这一点,完全没有运气。

它说:保留一堆正在读取的文件名。对堆栈使用以下数据结构:

struct Node { 
string fileName; 
Node *link; 
}; 

我试图避免使用 new,但是当我将列表的头部传递给递归方法调用时,它总是给我“分段错误”或“BUS 错误”。关于如何解决这个问题的任何想法?

【问题讨论】:

  • 这里的人不会愿意从头开始为你写作业。既然你已经有了一些代码,你应该把它缩减为一个最小的例子并发布它,询问你哪里出错了。
  • 你能发布完整的作业文本吗?目前尚不清楚您在谈论什么文件名。查看代码也会很有用。另外,您确定不是简单地要求您保留一组预先分配的节点,然后在它们之间创建链接吗?
  • 你能发布一些代码吗?递归调用?
  • 你应该对链表进行哪些操作?仅使用堆栈是不可能删除任意列表成员的。
  • 在我看来,“保持堆栈”和“在堆栈上”之间存在很大差异。第一个是数据结构,第二个是特定的内存区域。

标签: c++ linked-list stack


【解决方案1】:

想想数组。如果需要,可能不止一个。

【讨论】:

    【解决方案2】:

    没有太多信息:

    递归实现是必需的吗?当你进行递归调用时,你会得到一个新的堆栈。 也许您可以使用迭代方法。

    【讨论】:

      【解决方案3】:

      调用函数后,该函数的堆栈分配是固定的。

      获得更多堆栈内存分配的唯一方法是调用另一个函数。然后可以调用另一个函数。然后可以调用另一个函数。或者也许它们都可以是相同的功能......

      每个函数调用都有自己的固定大小堆栈,但函数调用图本身是这些堆栈的可变大小堆栈。

      【讨论】:

      • “该函数的堆栈分配是固定的”是什么意思?
      • @Liran - 这意味着在调用函数时已经分配了在堆栈上为函数分配的所有内存。因此,您(通常)不能从函数本身内部在堆栈上分配更多内存 - 当然,除非通过调用另一个函数。
      【解决方案4】:

      如果您知道需要存储多少个文件名,您可以使用结构节点数组并从中构建您的列表。

      使用迭代,一种可能的替代方法是在函数中包含一个 struct Node 对象,并在递归调用中传递一个指向它的指针,您可以在该函数堆栈框架中使用指向 Node 对象的下一个链接的指针。

      请注意,在后一种情况下,列表仅在最深递归时有效,当递归调用返回其调用者时,列表会再次分解。

      【讨论】:

        【解决方案5】:

        我创建了一个小样本,您可能会觉得很有启发性。我在堆栈上创建了一个元素的单链表。请注意如何反向创建列表以及如何使用递归来“分配”您需要的项目数。还要注意列表是如何作为参数传递给的。希望这会有所帮助,祝你好运。

        #include <cstdio>
        
        using namespace std;
        
        struct Node {
            Node* next_;
            int value_;
        };
        
        // Creates a linked list of nodes containing raising values.
        void intList(Node* prevNode, int restValue) {
            if (restValue) {
               // A node on the stack, which is linked to list created so far.
               Node node;
               node.next_ = prevNode;
               node.value_ = restValue; 
               // Create a next node or print this list if rest runs to zero.
               intList(&node, restValue - 1);
            }
            else {
            // Depest recursion level, whole list is complete.
            for (Node* iter = prevNode; iter; iter = iter->next_)
                printf("item %d\n", iter->value_);
            }
        }
        
        int main() {
            intList(NULL, 10);
        }
        

        【讨论】:

        • 我认为你应该补充一点,一旦 intList 返回,它在堆栈上创建的节点就会被销毁。 main 第一行之后,不再有任何节点,链表被彻底销毁。
        【解决方案6】:

        堆和堆栈之间的区别主要是(不仅,而且主要是为了这个问题)内存的分配位置和释放方式。当你想在堆上分配一个节点时,你说new Node,系统会为你提供内存,跟踪哪些块被使用,哪些是空闲的,并为你提供一次释放块的方法你不再需要它了。

        但您也可以在堆栈上的数组中拥有一个节点池。 (自动变量是堆栈变量。)您可以从该池中“分配”,跟踪数组中的哪些节点被使用以及哪些是空闲的,并将未使用的节点标记为不再需要它们的空闲节点。但是,由于数组的大小在编译时是固定的,这意味着您的列表具有最大长度。

        【讨论】:

          【解决方案7】:

          要“在堆栈上创建一个链表”,通常您会使用像 alloca 这样的函数来获取更多堆栈内存。但是,这听起来不像您被要求做的事情。

          听起来你应该在堆栈上保留一个 stack,而不是一个任意的链表。作为提示,您想要执行的一般语法:

          void push(struct Node *oldHead, String elem) {
              struct Node newHead;
              head.fileName = elem;
              head.next = oldHead.
              struct Node *head = &newHead
              // then you need to continue what you're doing in this function, since
              // returning will effectively pop the stack.
          

          有一些(非平凡的)技术可以按照这些思路实现完整的垃圾收集列表,但这超出了您正在做的范围。

          【讨论】:

            【解决方案8】:

            你可能应该去和你的教授谈谈并澄清要求,因为从你的描述来看,这对于一个新的 c++ 程序员来说似乎是一个非常奇怪的任务。至少可以说,要求实现一个仅在堆栈上具有内存的链表是很奇怪的。

            【讨论】:

              【解决方案9】:

              可以使用 C++ address-of operator (&) 来检索指向堆栈上对象的指针,而不是使用 new 动态分配内存。 p>

              由于以这种方式生成链接列表除了作为家庭作业之外的用途是有问题的,我不确定这是否是实际需要的。如果没有代码示例,很难准确地说出问题出在哪里。

              【讨论】:

              • “有问题的使用” - 实际上,通过递归在堆栈上创建链表基本上是实现异常帧的“第一次尝试”方式。或者,甚至更简单,它基本上就是调用堆栈:一系列节点,每个节点都指向前一个节点(例如,通过堆栈槽,用于在下一个调用过程中保存链接寄存器)。因此,特别是如果课程稍后将涉及任何编译器理论,我会说很好的作业,介绍一个现实世界的概念。
              【解决方案10】:

              使用alloca()而不是malloc()函数在调用函数的栈帧而不是堆上动态分配内存。您不必担心释放内存,因为它会在函数返回时自动释放。

              link text

              【讨论】:

              • alloca() 据我所知,不是任何版本的 C 或 C++ 中的标准函数。这是一个常见的扩展。我建议询问教授 (a) alloca() 是否允许,如果允许 (b) 这是否是他想要的。
              猜你喜欢
              • 2019-09-22
              • 2017-06-21
              • 2014-10-23
              • 2021-08-01
              • 1970-01-01
              • 1970-01-01
              • 2010-09-30
              • 1970-01-01
              • 2014-01-06
              相关资源
              最近更新 更多