【问题标题】:Trouble implementing a proper (underflow protected) pop/peek method in the stack using liked lists使用喜欢的列表在堆栈中实现正确的(下溢保护)pop/peek 方法时遇到问题
【发布时间】:2012-10-25 16:59:49
【问题描述】:

好的,我正在尝试使用链表为我的 C++ 作业编写堆栈弹出方法。 让我先告诉你节点和列表类,然后告诉你问题:

class Node
{
public:
    int data;
    Node* next;

    Node(int data, Node* next = 0)
    {
        this->data = data;
        this->next = next;
    }
};
class List
{
private:
  Node* head; // no need for the tail when using the list for implementing a stack

public:
    List()
    {
        head = 0;
    }
    void add_to_head(int  data)
    {
        if(head == 0)
        {
            head = new Node(data);
        }
        else 
        {
            head = new Node(data, head);
        }
    }

    Node* get_head()
    {
        return head;
    }

    // this deletes the head element and makes 'head' points to the node after it.
    void delete_head()
    {
        // storing the head so that we could delete it afterwards.
        Node* temp = head;

        // making the head point to the next element.
        head = temp->next;

        // freeing memory from the deleted head.
        delete(temp);
    }
};

现在是堆栈:

class stack
{
private: 
    List* list;

public:
  stack()
  {
      list = new List();
      flush();
  }
  void push(int value)
  {
      list->add_to_head(value);
  }
  bool pop(int& value_to_fill)
  {
      if(is_empty())
      {
        return false; // underflow...
      }

      value_to_fill = list->get_head()->data;

     // deleting the head. NOTE that head will automatically point to the next element after deletion 
     // (check out the delete_head definition)
     list->delete_head();

     return true; // popping succeed.
  }
  bool peek(int& value_to_fill)
  {
    if(is_empty())
    {
       return false;
    }
    value_to_fill = list->get_head()->data;
    return true;
  }
 // other stuff...
};

现在问题在于 pop 和 peek,我只是觉得它们不方便。 不应为 pop 和 peek 提供任何参数,但如果我这样做:

int peek()
{
  if(is_empty())
    // what should I do here?
  return list->get_head()->data;
}
int pop()
{
  if(is_empty())
    // same thing here.

  // deleting the tos then returning it.
  // I know this is not what the pop in the STL stack does, but I like it this way
    int tos = list->get_head()->data;
    list->delete_head();
    return tos;
}

发生下溢时我不知道该怎么办。 我不能只返回 -1 或 0 或类似的东西,因为这看起来好像我弹出了 -1 或 0(tos == -1 或 0) 有没有一种方法可以编写防下溢 pop/peek 而无需通过引用传递任何内容?

【问题讨论】:

  • 他们说例外很好。
  • 您不想使用讨厌的列表吗?
  • @doublep:嗯,据我所知(来自 C#)你不能这样做: int peek() { try { return list->get_head()->data; } catch(...) {} } 你会得到一个错误,说所有路径都必须返回一些东西。但我只是在 C++ 中尝试过,它成功了!它编译没有任何错误。它不应该给我那个错误吗?
  • @Vexe 如果代码实际上采用了该路径,这只是 C++ 中的错误。编译器很难确定这一点,因此不需要错误消息。 (这称为未定义行为。)

标签: c++ stack stackunderflow


【解决方案1】:

这是规范的问题。有几种可能的解决方案:

  • 将堆栈不为空作为pop 的前提条件。它是 客户有责任确保这一点(可能通过调用 is_empty() 在弹出之前),并且违反了先决条件 导致断言失败。

  • 如果堆栈为空,则引发异常。这是最明显的 解决方案,但可能是最不普遍适用的。

  • 不要让 pop 返回值(或让它返回您的 bool)。到 获取顶部元素,您有一个单独的函数 tos() 和一个客户端 谁想要两者都需要两个函数调用:x = s.tos(); s.pop();。 例如,这就是标准所做的。在实践中,往往 首选方法,因为对于复制可以抛出的类型(例如 std::string),不可能实现 pop 来返回值和 给予强有力的异常保证。 (无论这是否有问题 是另一个问题,但在特定情况下可能是一个问题,而且它是 标准中选择背后的动机,其中没有流行 函数返回一个值。)

最后,重要的是你定义了接口,所以 你的用户知道会发生什么。

顺便说一句,您不需要add_to_head 中的if。如果head == NULL,您将使用第二个参数调用构造函数 NULL,所以你不妨在这两种情况下都传递head

(我将跳过使用链表效率非常低的事实 实现堆栈的方法,因为代码显然是一个学习 锻炼。)

【讨论】:

  • 再好不过了。但是实现堆栈的最佳方式是什么?使用数组?是的,正如你猜到的,我只是在训练链表。
  • @VeXe 我一般用std::vector,用push_backpop_backback来实现push、pop和tos。
猜你喜欢
  • 2021-10-27
  • 2017-05-23
  • 1970-01-01
  • 2020-06-29
  • 2021-11-19
  • 2019-06-22
  • 2021-01-20
  • 2015-02-27
  • 2013-01-28
相关资源
最近更新 更多