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
ListList
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)) { }