从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语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
8天前
|
C++
C++(十八)Smart Pointer 智能指针简介
智能指针是C++中用于管理动态分配内存的一种机制,通过自动释放不再使用的内存来防止内存泄漏。`auto_ptr`是早期的一种实现,但已被`shared_ptr`和`weak_ptr`取代。这些智能指针基于RAII(Resource Acquisition Is Initialization)原则,即资源获取即初始化。RAII确保对象在其生命周期结束时自动释放资源。通过重载`*`和`-&gt;`运算符,可以方便地访问和操作智能指针所指向的对象。
|
8天前
|
存储 安全 C语言
C语言 二级指针应用场景
本文介绍了二级指针在 C 语言中的应用,
|
8天前
|
C++
C++(九)this指针
`this`指针是系统在创建对象时默认生成的,用于指向当前对象,便于使用。其特性包括:指向当前对象,适用于所有成员函数但不适用于初始化列表;作为隐含参数传递,不影响对象大小;类型为`ClassName* const`,指向不可变。`this`的作用在于避免参数与成员变量重名,并支持多重串联调用。例如,在`Stu`类中,通过`this-&gt;name`和`this-&gt;age`明确区分局部变量与成员变量,同时支持链式调用如`s.growUp().growUp()`。
|
20天前
|
存储 安全 C++
C++:指针引用普通变量适用场景
指针和引用都是C++提供的强大工具,它们在不同的场景下发挥着不可或缺的作用。了解两者的特点及适用场景,可以帮助开发者编写出更加高效、可读性更强的代码。在实际开发中,合理选择使用指针或引用是提高编程技巧的关键。
22 1
|
24天前
|
安全 NoSQL Redis
C++新特性-智能指针
C++新特性-智能指针
|
23天前
|
存储 编译器 C语言
【C语言篇】深入理解指针2
代码 const char* pstr = "hello world."; 特别容易让初学者以为是把字符串 hello world.放 到字符指针 pstr ⾥了,但是本质是把字符串 hello world. 首字符的地址放到了pstr中。
|
23天前
|
存储 程序员 编译器
【C语言篇】深入理解指针1
assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。这个宏常常被称为“断⾔”。
|
27天前
|
编译器 C++
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
|
27天前
|
存储 搜索推荐 C语言
C语言中的指针函数:深入探索与应用
C语言中的指针函数:深入探索与应用