从C语言到C++_17(list的模拟实现)list不是原生指针的迭代器

简介: 从C语言到C++_17(list的模拟实现)list不是原生指针的迭代器

在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()方法查看链表是否为空和大小等信息。

相关文章
|
2月前
|
安全 编译器 C语言
C++入门1——从C语言到C++的过渡
C++入门1——从C语言到C++的过渡
62 2
|
2月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
53 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
2月前
|
存储 算法 C++
【C++打怪之路Lv10】-- list
【C++打怪之路Lv10】-- list
21 1
|
2月前
|
C语言 C++
C 语言的关键字 static 和 C++ 的关键字 static 有什么区别
在C语言中,`static`关键字主要用于变量声明,使得该变量的作用域被限制在其被声明的函数内部,且在整个程序运行期间保留其值。而在C++中,除了继承了C的特性外,`static`还可以用于类成员,使该成员被所有类实例共享,同时在类外进行初始化。这使得C++中的`static`具有更广泛的应用场景,不仅限于控制变量的作用域和生存期。
59 10
|
2月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
55 5
|
2月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
59 2
|
2月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
29 0
|
2月前
|
存储 缓存 C++
C++番外篇——list与vector的比较
C++番外篇——list与vector的比较
22 0
|
2月前
|
C++
C++番外篇——list的实现
C++番外篇——list的实现
19 0
|
2月前
|
存储 C++ 容器
C++入门9——list的使用
C++入门9——list的使用
19 0