C++ 如何在c++;链表?

C++ 如何在c++;链表?,c++,templates,linked-list,C++,Templates,Linked List,我不完全理解模板的概念,我试图在下面的链接列表中获得一些关于如何实现模板的帮助。我正在尝试使我的代码能够支持以下类型:ListListList。我想知道除了解释正在发生的事情外,是否有人能给我一个如何将这些项目转换为模板的例子?我是新的C++,所以任何帮助我可以得到赞赏。 #include <string> #include <iostream> #include <cstddef> using Item = std::string; // TURN D

我不完全理解模板的概念,我试图在下面的链接列表中获得一些关于如何实现模板的帮助。我正在尝试使我的代码能够支持以下类型:
List
List
List
。我想知道除了解释正在发生的事情外,是否有人能给我一个如何将这些项目转换为模板的例子?我是新的C++,所以任何帮助我可以得到赞赏。
#include <string>
#include <iostream>
#include <cstddef>


using Item = std::string;

// TURN DList into a template!
class DList {
private:

  class DListNode {
  public:
    Item item;
    DListNode * next;
    DListNode * prev;
    DListNode(Item i, DListNode *n=nullptr, DListNode *p=nullptr) {
      item = i;      
      next = n;
      prev = p;
    }
  };

  DListNode * head;
  DListNode * tail;

public:
  class iterator {
    DListNode *node;
  public:
    iterator(DListNode *n = nullptr) {
      node = n;
    }

    Item& getItem() { return node->item; }
    void next() { node = node->next; }
    void prev() { node = node->prev; }
    bool end() { return node==nullptr; }

    friend class DList;
  };



public:
  DList() {
    // list is empty
    head = nullptr;
    tail = nullptr;
  }

  bool empty() {
    return head==nullptr;
  }

  void append(Item a) {
    DListNode *node = new DListNode(a,nullptr,tail);
    if ( head == nullptr ) {
      // empty list
      head = node;
      tail = node;
    } else {
      tail->next = node;
      tail = node;
    }
  }

  void insertAfter(iterator it, Item item)
  {
    if(head == nullptr || it.node == nullptr) { // NULL iterator means insert at head
      DListNode *node = new DListNode(item,head); // next=head, prev=NULL
      if ( head == nullptr) // same as zyBook
        head = tail = node;
      else { // if inserting before head, it.node==NULL
        head->prev = node;
        head = node;
      }
    } else if (it.node == tail) {
      DListNode *node = new DListNode(item,nullptr,tail); // next=NULL, prev=old tail
      tail->next = node;
      tail = node;
    } else {
      DListNode *node = new DListNode(item,it.node->next,it.node);
      it.node->next = node;
      node->next->prev = node;
    }
  }

  void erase (iterator it) {
    DListNode *succ = it.node->next; // successor node
    DListNode *pred = it.node->prev; // predecessor node

    if (succ != NULL)
      succ->prev = pred;
    if (pred != NULL)
      pred->next = succ;

    if (it.node == head)
      head = succ; // head is following node
    if (it.node == tail)
      tail = pred; // tail is previous node

    delete it.node; // delete the node; not shown in zyBook, but necessary in C/C++
    // iterator is now invalid, caller should not use it again
  }

  iterator begin() {
    return iterator(head);
  }

  iterator reverse_begin() {
    return iterator(tail);
  }
};

template <typename Item>
std::ostream& operator << (std::ostream& out, DList<Item> &l)
{
  out << "{";
  auto it = l.begin();
  out << it.getItem();
  it.next();
  for(; !it.end(); it.next())
    {
      out << ", " << it.getItem();
    }
  out << "}" << std::endl;
  return out;
}


int main()
{
  {
    DList<std::string> l;

    l.append("eggs");
    l.append("milk");
    l.append("bread");

    std::cout << l;
  }
  {
    DList<int> l;

    l.append(1);
    l.append(2);
    l.append(3);

    std::cout << l;
  }
  return 0;
}
#包括
#包括
#包括
使用Item=std::string;
//将DList转换为模板!
类列表{
私人:
类DListNode{
公众:
项目;
DListNode*下一步;
DListNode*prev;
DListNode(项目i,DListNode*n=nullptr,DListNode*p=nullptr){
项目=一;
next=n;
prev=p;
}
};
DListNode*头部;
DListNode*尾部;
公众:
类迭代器{
DListNode*节点;
公众:
迭代器(DListNode*n=nullptr){
节点=n;
}
Item&getItem(){return node->Item;}
void next(){node=node->next;}
void prev(){node=node->prev;}
bool end(){return node==nullptr;}
朋友类列表;
};
公众:
DList(){
//列表为空
水头=零PTR;
tail=nullptr;
}
bool empty(){
返回压头==nullptr;
}
作废附加(a项){
DListNode*node=新的DListNode(a,nullptr,tail);
if(head==nullptr){
//空列表
头部=节点;
尾=节点;
}否则{
tail->next=节点;
尾=节点;
}
}
void insertAfter(迭代器it,Item)
{
if(head==nullptr | | it.node==nullptr){//NULL迭代器表示在head插入
DListNode*node=新建DListNode(项,头);//下一个=头,上一个=空
if(head==nullptr)//与zyBook相同
头=尾=节点;
else{//如果在头之前插入,则it.node==NULL
head->prev=节点;
头部=节点;
}
}else if(it.node==tail){
DListNode*node=新的DListNode(项,nullptr,tail);//下一个=NULL,上一个=old tail
tail->next=节点;
尾=节点;
}否则{
DListNode*node=新建DListNode(item,it.node->next,it.node);
it.node->next=节点;
节点->下一步->上一步=节点;
}
}
无效擦除(迭代器){
DListNode*succ=it.node->next;//后续节点
DListNode*pred=it.node->prev;//前置节点
如果(成功!=NULL)
succ->prev=pred;
如果(pred!=NULL)
pred->next=succ;
if(it.node==头)
head=succ;//head在节点后面
if(it.node==tail)
tail=pred;//tail是上一个节点
delete it.node;//删除节点;zyBook中未显示,但C/C中需要++
//迭代器现在无效,调用方不应再次使用它
}
迭代器begin(){
返回迭代器(head);
}
迭代器反向_begin(){
返回迭代器(tail);
}
};
模板

std::ostream&operator实际上,您几乎已经拥有了所需的所有内容,但仍然使用带有具体类型的Regular类

using Item = std::string;

class DList { ... };
因此,首先我们放弃混凝土类型:

// using Item = std::string;

class DList { ... }; // sure Item is now undefined...
然后我们告诉类作为模板

template <typename Item>
class DList { ... };
您创建了一个全新的独立数据类型(这特别意味着,您不能将
DList
分配给指向
DList
的指针,就像您不能将int分配给指向double的指针一样)

实例化模板时,模板参数的每次出现都将替换为实例化模板时使用的类型,例如。G在
DList
中,每次出现
都将替换为
int

好的,所有这些都只是一个非常简短的介绍,还有很多事情要做,但这要在书中处理,而不是在stackoverflow的答案中处理

不过,节点构造函数的一些注释如下:

DListNode(Item i /* , ... */) { item = i; }
首先,您应该习惯使用构造函数的初始化器列表(不要与
std::initializer\u list
)混淆:

您避免了默认初始化+赋值,而是通过值直接初始化。此外,某些类型(非默认可构造类型、常量成员和引用)只能以这种方式初始化

那么您正在生成一个不必要的副本:

DListNode(Item i /* , ... */) : item(i) { }
//             ^ temporary copy   ^ final copy, created from temporary
如果您通过引用接受项目,则可以避免该副本:

DListNode(Item const& i /* , ... */) : item(i) { }
// now copies from reference, one copy less
您还可以提供移动语义:

DListNode(Item&& i /* , ... */) : item(std::move(i)) { }
这样就可以将不再需要在列表之外的对象移动到列表中(实际上是它们的内容)。在某些情况下,这可能比完整副本便宜得多

所有关于构造函数的描述(除了初始化器列表)也适用于
append
insertAfter
函数


初始化器列出并避免复制是一般建议,与模板无关…

模板是一个高级主题。如果你对它们是新手,一般来说C++,你最好从更简单的方式开始。如果你的代码没有超过10页的解释,而你想把它变成模板代码作为答案,那你就不会有什么收获。也许你可以把你的问题变成问一个更具体更集中的问题?
DListNode(Item const& i /* , ... */) : item(i) { }
// now copies from reference, one copy less
DListNode(Item&& i /* , ... */) : item(std::move(i)) { }