【问题标题】:How to use template for implementing STACK using LINKEDLIST in cpp如何使用模板在 cpp 中使用 LINKED LIST 实现堆栈
【发布时间】:2021-07-13 01:12:31
【问题描述】:

所以我正在尝试创建一个实现堆栈及其所有功能(push、pop、getTop 等)的 c++ 文件。我想使用模板,这样我就可以为多种数据类型创建这个 Stack 类。我正在使用链表来存储数据。这是我使用链表实现的一些堆栈示例。

#include<iostream>
using namespace std;

template <class T>

class Node{
public:
      T data;
      Node *next;
      Node()
      {
            next = NULL;
      }
};

class Stack
{
      Node *top;
public:
      Stack();
      int isEmpty();
      int isFull();
      void push(T data);
      T pop();
      void display();
};

Stack :: Stack()
{
      top = NULL;
}

int Stack :: isEmpty()
{
      if(top == NULL)
      {
            return 1;
      }
      else
      {
            return 0;
      }
}

int Stack :: isFull()
{
      int temp;
      Node *t = new Node;

      if(t==NULL)
      {
            temp = 1;
      }
      else
      {
            temp = 0;
      }

      delete t;
      return temp;
}

void Stack :: push(T data)
{
      Node *n;

      if(isFull())
      {
            cout<<"\nStack overflow";
      }
      else
      {
            n = new Node;
            n->data = data;
            n->next = top;
            top = n;
      }

}

int Stack :: pop()
{
      Node *t;
      T temp;

      if(isEmpty())
      {
            return temp;
      }
      else
      {
            t = top;
            top = top->next;
            temp = t->data;
            delete t;
            return temp;
      }
}

void Stack :: display()
{
      Node *p = top;
      while(p != NULL)
      {
            cout<<"\n"<<p->data;
            p = p->next;
      }
}

所以这是我正在尝试做的事情的预览,但我不想为不同的数据类型创建不同的节点和堆栈类。我如何使用模板来实现这一点。我自己尝试过,但我遇到了很多错误,似乎无法理解为什么。 谢谢。

【问题讨论】:

  • 提供你尝试过的代码(即使失败了),这样你会得到更好的输入。
  • isFull 内部到底发生了什么?
  • 试图弄清楚你的理解水平是什么:为什么你在定义Node之前有一行template &lt;class T&gt;?为什么您在定义Stack 之前没有有同一行? (除了这种差异之外,您的其他错误可能归结为了解您收到的错误消息。您确定不想询问编译器报告的第一个错误吗?)

标签: c++ templates linked-list stack


【解决方案1】:

我建议将Node 变成Stack 的内部类。用户无需看到它。

#include<iostream>
#include<utility>

template<class T>
class Stack {
    struct Node {  // inner class
        T data;
        Node *next;
    };

    Node* top = nullptr;
    size_t m_size = 0;

public:
    Stack() = default;

    // rule of five - no copying, only moving allowed
    Stack(const Stack&) = delete;
    Stack(Stack&& rhs) noexcept :
        top(std::exchange(rhs.top, nullptr)), m_size(rhs.m_size) 
    {}
    Stack& operator=(const Stack&) = delete;
    Stack& operator=(Stack&& rhs) noexcept {
        std::swap(top, rhs.top);
        m_size = rhs.m_size;
        return *this;
    }
    ~Stack() {
        while(top) {
            delete std::exchange(top, top->next);
        }
    }

    bool empty() const { return m_size == 0; }
    size_t size() const { return m_size; }

    void push(const T& data) {
        top = new Node{data, top};
        ++m_size;
    }

    T pop() {
        T rv = std::move(top->data);
        delete std::exchange(top, top->next);
        --m_size;
        return rv;
    }
};

Demo

【讨论】:

    【解决方案2】:

    你可以像下面这样实现:

    #include<iostream>
    using namespace std;
    
    template <typename Type>
    class Node
    {
    public:
        Type data;
        Node<Type> *next;
    };
    
    template <typename Type>
    class Stack
    {
    public:
        Node<Type> *top;
        void push(Type data);
        Type pop();
    };
    
    
    int main()
    {
    
    }
    

    【讨论】:

    • 我不认为你会模板 Stack 而不是 typename Node 而是 template&lt;typename Type&gt; 然后你会有一个 Node&lt;Type&gt; 数据成员。这也意味着调用代码不必知道Node 类的实现细节,您可以只使用Stack&lt;int&gt; 而不是Stack&lt;Node&lt;int&gt;&gt;
    【解决方案3】:

    用链表实现栈只需要私有地存储一个链表,并用栈的接口约束它。约束是关键。模板参数是您存储在堆栈中的类型。

    最简单的* 方法是花时间实现一个链表好吧,这样你只需要担心将它限制在你的堆栈类中而不是编写一个链表来表现得像堆栈类中的堆栈。这里起作用的原则称为关注点分离。

    为简单起见,下面是一个使用std::list 的简单示例:

    template <typename T>
    class Stack {
     public:
      Stack() = default;
      Stack(T val) : m_stack(val) {}
      void push(T val) { m_stack.push_front(val); }
      T& top() { return m_stack.front(); }
      void pop() {
        if (!m_stack.empty()) m_stack.pop_front();
      }
      bool empty() const { return m_stack.empty(); }
    
     private:
      std::list<T> m_stack{};
    };
    

    如果您希望在堆栈中抛出异常,则pop() 函数中可能不需要if 语句。

    这是一个测试堆栈的main()

    int main() {
      Stack<int> s1;
      for (int i = 1; i < 11; ++i) s1.push(i);
      while (!s1.empty()) {
        std::cout << s1.top() << ' ';
        s1.pop();
      }
      std::cout << '\n';
    
      Stack<char> s2('A');
      for (char l = 'B'; l != 'K'; ++l) s2.push(l);
      while (!s2.empty()) {
        std::cout << s2.top() << ' ';
        s2.pop();
      }
      std::cout << '\n';
    }
    

    我只包括&lt;iostream&gt;&lt;list&gt;。输出:

    10 9 8 7 6 5 4 3 2 1 
    J I H G F E D C B
    

    因为std::list 为我处理了这一切,所以我能够避免很多不必要的工作,例如 5 规则。所以我对编译器提供的复制和移动构造函数和析构函数很好。

    * 这说起来容易做起来难。我为这些特定问题保留了一个简单的链接列表,它仍然是大约 130 行代码,并且没有像我在 std::list 中演示的那样被适当地限制为像堆栈一样运行所需的所有功能。

    如果您已经编写过链表,堆栈应该非常简单,因为成功编写链表需要展示极其广泛的 C++ 知识和编程原理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-29
      • 2019-05-09
      相关资源
      最近更新 更多