竹_

双向链表List类模板的实现

双向链表List类模板的实现

1.考虑设计时需提供的类

  • List类本身,它包含连接到表两端的链、表的大小,以及一些方法。
  • Node类,可能是一个私有的内嵌类。一个节点包含数据和指向前后两个节点的两个指针,以及一些适当的构造函数。
  • const_iterator类,它抽象了位置的概念,是一个公有的内嵌类。该const_iterator存储一个指向“当前”节点的指针,并提供基本迭代器操作的实现,所有的操作,像=、==、!= 和 ++ 等,均以重载运算符的形式出现。
  • iterator类,它抽象了位置的概念,是一个公有的内嵌类。该iterator有着与const_iterator相同的功能,但operator* 返回的是所指项的引用,而不是对该项的常量引用。一个重要的技术问题是,iterator可以用在任何需要const_iterator的例程中,但反之不真。换句话说,iterator是一个const_iterator

2.List中的附加节点设计

头节点(header node): 在表的前端创建一个附加节点,逻辑上代表开始标志。
尾节点(tail node): 在表的终端创建一个终端标记(endmarker)。
使用这些附加节点的好处在于,它们通过排除一些特殊情况大大地简化了编码过程。例如,如果我们不使用头节点,那么删除第一个节点就变成了一种特殊情形,因为我们在删除期间必须重新安置链表对第一个节点的连接,还因为删除算法一般需要访问正在被删除的节点前面的节点(而没有头节点,则第一个节点就没有在它前面的节点)。

#pragma once
#include<algorithm>
template<typename Object>
class List {
private:
struct Node {
Object element;
Node* pre;
Node* next;
Node(const Object& e=Object{ }, Node* p = nullptr, Node* n = nullptr)
:element{e},pre{p},next{n}{}
Node(Object&& e, Node*& p = nullptr, Node*& n = nullptr)
:element{ std::move(e)}, pre{p}, next{n}{}
};
int theSize;
Node* head;
Node* tail;
void init() {
theSize = 0;
head = new Node;
tail = new Node;
head->next = tail;
tail->pre = head;
}
public:
//List类的内嵌const_iterator类
class const_iterator {
protected:
Node* current;
Object& retrieve()const { return current->element; };
const_iterator(Node*p):current{p}{}
friend class List<Object>; //赋予List类访问const_iterator的非公有成员的权力
public:
const_iterator():current{nullptr}{}
const Object& operator*()const {
return retrieve();
}
const_iterator& operator++() { //重载前缀自增运算符
current = current->next;
return *this;
}
/**
* C++规定,通过为前缀形式指定空参数表而为后缀形式指定(匿名的)单参数int来赋予他它们不同的
* 特征。即,++itr调用零参数的operator++,而itr++调用单参数operator++。可以看出,在存在选用
* 前缀或后缀operator++的许多场合下,前缀形式要比后缀形式更快。
*/
const_iterator& operator++(int) {
const_iterator old = *this;
++(*this);
return old;
}
bool operator==(const const_iterator& rhs)const {
return current == rhs.current;
}
bool operator!=(const const_iterator& rhs)const {
return !(*this == rhs);
}
};
//List类的嵌套iterator类
class iterator :public const_iterator {
protected:
iterator(Node*p):const_iterator{p}{}
friend class List<Object>;
public:
iterator(){}
Object& operator*() {
return const_iterator::retrieve();
}
const Object& operator*()const {
return const_iterator::operator*();
}
iterator& operator++() {
this->current = this->current->next;
return *this;
}
iterator& operator++(int) {
iterator old = *this;
++(*this);
return old;
}
};
public:
List() { init();}
List(const List& rhs) {
init();
for (auto& x : rhs)
push_back(x);
}
List(List&& rhs) :theSize{ rhs.theSize }, head{ rhs.head }, tail{ rhs.tail }
{
rhs.theSize = 0;
rhs.head = rhs.tail = nullptr;
}
~List() {
clear();
delete head;
delete tail;
}
List& operator=(const List& rhs) {
List copy = rhs;
std::swap(*this, copy);
return *this;
}
List& operator=(List&& rhs) {
std::swap(theSize, rhs.theSize);
std::swap(head, rhs.head);
std::swap(tail, rhs.tail);
return *this;
}
iterator begin() {
return { head->next };
}
const_iterator begin()const {
return { head->next };
}
iterator end() {
return tail;
}
const_iterator end()const {
return tail;
}
int size()const { return theSize;}
bool empty()const { return theSize == 0;}
void clear() {
while (!empty())
pop_front();
}
Object& front() { return *begin();}
const Object& front()const { return *begin();}
Object& back() { return *--end();}
const Object& back()const { return *--end();}
void push_front(const Object& x) {
insert(begin(), x);
}
void push_front(Object&& x) {
insert(begin(), std::move(x));
}
void push_back(const Object& x) {
insert(end(), x);
}
void push_back(Object&& x) {
insert(end(), std::move(x));
}
void pop_front() {
erase(begin());
}
void pop_back() {
erase(--end());
}
//获取一个新节点,按顺序修改指针再将新节点插入双向链表
//在itr前插入x
iterator insert(iterator itr, const Object& x) {
Node* p = itr.current;
theSize++;
return { p->pre = p->pre->next = new Node{x,p->pre,p} };
}
iterator insert(iterator itr, Object&& x) {
Node* p = itr.current;
theSize++;
return { p->pre = p->pre->next = new Node{std::move(x),p->pre,p}};
}
//从双向链表中删除由itr处的项
iterator erase(iterator itr) {
Node* p = itr.current;
iterator retVal{ p->next }; //返回删除后指向该位置的迭代器,原来的itr失效
p->pre->next = p->next;
p->next->pre = p->pre;
delete p;
theSize--;
return retVal;
}
iterator erase(iterator from, iterator to) {
for (iterator itr = from; itr != to;)
itr = erase(itr);
return to;
}
};
posted @   aw11  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示