C++ 模板 - 链表

标签 c++ templates linked-list

编辑——在下面回答,错过了斜括号。谢谢大家。

我一直在尝试编写一个基本的单链表,我可以在其他程序中使用它。我希望它能够使用内置和用户定义的类型,这意味着它必须是模板化的。

因此我的节点也必须被模板化,因为我不知道它要存储的信息。我写了一个节点类如下 -

template <class T> class Node
{
    T data; //the object information
    Node* next; //pointer to the next node element

public:
    //Methods omitted for brevity
};

我的链表类是在一个单独的类中实现的,需要在将新节点添加到列表末尾时实例化一个节点。我已经实现了如下 -

#include <iostream>
#include "Node.h"
using namespace std;

template <class T> class CustomLinkedList
{
    Node<T> *head, *tail;

public:

    CustomLinkedList()
    {
        head = NULL;
        tail = NULL;
    }

    ~CustomLinkedList()
    {

    }

    //Method adds info to the end of the list
    void add(T info)
    {
        if(head == NULL) //if our list is currently empty
        {
            head = new Node<T>; //Create new node of type T
            head->setData(info);
            tail = head;
        }
        else //if not empty add to the end and move the tail
        {
            Node* temp = new Node<T>;
            temp->setData(info);
            temp->setNextNull();
            tail->setNext(temp);
            tail = tail->getNext();
        }
    }

    //print method omitted
};

我已经设置了一个驱动/测试类如下 -

#include "CustomLinkedList.h"
using namespace std;

int main()
{
    CustomLinkedList<int> firstList;

    firstList.add(32);
    firstList.printlist();
    //Pause the program until input is received
    int i;
    cin >> i;

    return 0;
}

但是我在编译时遇到错误 - error C2955: 'Node' : use of class template requires template argument list - 这指向我添加方法中的以下代码行 -

Node* temp = new Node<T>;

我不明白为什么它没有关于类型的信息,因为它是在我的驱动程序类中创建时传递给链表的。 我应该怎么做才能将类型信息传递给 Node?

我应该创建一个私有(private)节点结构而不是一个单独的类,并将两个类的方法组合在一个文件中吗?我不确定这是否会解决问题,但我认为可能会。如果可能的话,我宁愿有单独的类(class)。

谢谢,安德鲁。

最佳答案

虽然已经提供了答案,但我想我会加一点盐。

在设计模板类时,最好不要在几乎所有地方重复模板参数,以防万一您希望(有一天)更改特定细节。通常,这是通过使用 typedef 来完成的。

template <class T>
class Node
{
public:
  // bunch of types
  typedef T value_type;
  typedef T& reference_type;
  typedef T const& const_reference_type;
  typedef T* pointer_type;
  typedef T const* const_pointer_type;

  // From now on, T should never appear
private:
  value_type m_value;
  Node* m_next;
};


template <class T>
class List
{
  // private, no need to expose implementation
  typedef Node<T> node_type;

  // From now on, T should never appear
  typedef node_type* node_pointer;

public:
  typedef typename node_type::value_type value_type;
  typedef typename node_type::reference_type reference_type;
  typedef typename node_type::const_reference_type const_reference_type;
  // ...

  void add(value_type info);

private:
  node_pointer m_head, m_tail;
};

最好在类声明之外定义方法,这样更容易阅读接口(interface)。

template <class T>
void List<T>::add(value_type info)
{
  if(head == NULL) //if our list is currently empty
  {
    head = new node_type;
    head->setData(info);
    tail = head;
  }
  else //if not empty add to the end and move the tail
  {
    Node* temp = new node_type;
    temp->setData(info);
    temp->setNextNull();
    tail->setNext(temp);
    tail = tail->getNext();
  }
}

现在,几点说明:

  • 如果 List<T>::add 会更友好正在向新添加的对象返回迭代器,例如 insert STL 中的方法(您也可以将其重命名为 insert)
  • 在执行List<T>::add您将内存分配给 temp然后执行一堆操作,如果有抛出,你已经泄漏了内存
  • setNextNull不需要调用:Node 的构造函数应该将所有数据成员初始化为有意义的值,包括 m_next

所以这里是修改后的版本:

template <class T>
Node<T>::Node(value_type info): m_value(info), m_next(NULL) {}

template <class T>
typename List<T>::iterator insert(value_type info)
{
  if (m_head == NULL)
  {
    m_head = new node_type(info);
    m_tail = m_head;
    return iterator(m_tail);
  }
  else
  {
    m_tail.setNext(new node_type(info));
    node_pointer temp = m_tail;
    m_tail = temp.getNext();
    return iterator(temp);
  }
}

请注意使用适当的构造函数这一简单事实如何提高我们的异常安全性:如果在构造函数期间抛出任何东西,new要求不分配任何内存,因此没有泄漏,我们还没有执行任何操作。我们的List<T>::insert方法现在具有弹性。

最后一个问题:

通常insert单链表的方法在开头插入,因为这样更容易:

template <class T>
typename List<T>::iterator insert(value_type info)
{
  m_head = new node_type(info, m_head); // if this throws, m_head is left unmodified
  return iterator(m_head);
}

您确定要在末尾添加插入内容吗?或者你这样做是因为 push_back传统 vector 和列表的方法?

关于C++ 模板 - 链表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2079296/

相关文章:

c++ - 我是否必须阻塞主线程上的信号以处理另一个线程上的取消点?

c++ - 有没有办法根据模板参数的类型在不同的类实现之间进行选择?

ios - 当数据为 NULL 时,访问链表的数据元素时应用程序崩溃

c - 在链表上应用冒泡排序会在 c 中给出错误的输出

c - 链接列表添加功能未按预期工作

c++ - 无法删除对象数组C++

c++ - 使用邻接矩阵进行图形着色

c++ - 对参数包中的每个元素应用函数

用于删除和重置指针的 C++ 模板函数

c++ - 显式特化不能是友元声明