在C++中,list是一个双向链表的容器,它提供了方便的插入、删除和访问元素的方法。其中,list迭代器是一个封装了指向链表节点的指针的对象,并提供了方便的操作链表的方法,与原生指针不同。
为了模拟list的实现,我们需要自己实现一个双向链表,并将其封装在一个类中,提供类似list的接口。
首先,我们定义链表节点的结构体:
template
struct Node {
T data;
Node prev;
Node next;
Node(const T& d) : data(d), prev(nullptr), next(nullptr) {}
};
该结构体表示链表的一个节点,包含元素的值、前后两个指针,我们为它定义了一个构造函数,使用给定的元素值初始化节点。
然后,我们定义链表类:
template
class List {
public:
List();
~List();
void push_front(const T& val);
void push_back(const T& val);
void pop_front();
void pop_back();
T& front();
T& back();
bool empty() const;
size_t size() const;
private:
Node head;
Node tail;
size_t list_size;
};
该类中包含了插入、删除、访问元素的方法,类似于list的接口。其中,head和tail分别指向链表的头、尾节点,list_size表示链表的大小。
下面是该类方法的实现:
template
List::List() : head(nullptr), tail(nullptr), list_size(0) {}
template
List::~List() {
while (head != nullptr) {
Node* tmp = head->next;
delete head;
head = tmp;
}
}
template
void List::push_front(const T& val) {
Node* new_node = new Node(val);
if (head == nullptr) {
head = tail = new_node;
} else {
new_node->next = head;
head->prev = new_node;
head = new_node;
}
++list_size;
}
template
void List::push_back(const T& val) {
Node* new_node = new Node(val);
if (head == nullptr) {
head = tail = new_node;
} else {
new_node->prev = tail;
tail->next = new_node;
tail = new_node;
}
++list_size;
}
template
void List::pop_front() {
if (head == nullptr) return;
if (head == tail) {
delete head;
head = tail = nullptr;
} else {
Node* tmp = head;
head = head->next;
head->prev = nullptr;
delete tmp;
}
--list_size;
}
template
void List::pop_back() {
if (head == nullptr) return;
if (head == tail) {
delete head;
head = tail = nullptr;
} else {
Node* tmp = tail;
tail = tail->prev;
tail->next = nullptr;
delete tmp;
}
--list_size;
}
template
T& List::front() {
return head->data;
}
template
T& List::back() {
return tail->data;
}
template
bool List::empty() const {
return head == nullptr;
}
template
size_t List::size() const {
return list_size;
}
注意到上述方法中,我们使用了封装了链表节点指针的Node*类型而不是原生指针,这样可以避免使用指针访问链表节点时的内存问题,提供了更安全的访问方式。
最后,使用类List就可以像list一样操作双向链表了:
List lst;
lst.push_back(1);
lst.push_back(2);
lst.push_back(3);
lst.pop_front();
lst.pop_back();
for (auto& x : lst) {
std::cout << x << " ";
}
如上述代码所示,我们可以通过调用push_back()和push_front()方法插入元素,通过pop_front()和pop_back()方法删除元素,通过front()和back()方法访问头尾元素,以及通过empty()和size()方法查看链表是否为空和大小等信息。