这是关于一个普通双非本科大一学生的C++的学习记录贴
在此前,我学了一点点C语言还有简单的数据结构,如果有小伙伴想和我一起学习的,可以私信我交流分享学习资料
那么开启正题
今天分享的是关于list的模拟实现,今天收尾,明天开始stack和queue
1.insert函数
void insert(iterator pos, const T& x)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* newnode = new Node(x);
newnode->_next = cur;
newnode->_prev = prev;
prev->_next = newnode;
cur->_prev = newnode;
}
实现insert函数后,再实现push_back(),push_front(),直接复用即可
void push_front(const T& x)
{
insert(begin(), x);
}
void push_back(const T& x)
{
insert(end(),x);
/*Node* tail = _head->_prev;
Node* newnode = new Node(x);
newnode->_next = _head;
newnode->_prev = tail;
tail->_next = newnode;
_head->_prev = newnode;*/
}
2.erase函数
void erase(iterator pos)
{
assert(pos != end());
Node* prev = pos._node->_prev;
Node* next = pos._node->_next;
delete pos._node;
prev->_next = next;
next->_prev = prev;
}
erase函数实现时要注意释放空间,否则会导致内存泄漏
同样的,pop_back(),pop_front(),都复用实现
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
3.clear函数与析构函数
实现erase函数后clear与析构函数复用实现就很便捷快速了
~list()
{
clear();
delete[] _head;
_head = nullptr;
}
void clear()
{
iterator it = begin();
while (it != end())
{
erase(it++);
}
}
注意这里的erase(it++)不能分开写,会导师迭代器失效
4.拷贝构造函数
list(const list<T>& l)
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
/*const_iterator it = l.begin();
while (it != l.end())
{
push_back(*it);
++it;
}*/
for (auto e : l)
{
push_back(e);
}
}
由于涉及到内存管理,拷贝构造函数必须是深拷贝,这里我们用了两种写法,一种是迭代器,一种是范围for
5.赋值运算符重载
list<T>& operator=(const list<T>& l)
{
if (this != &l)
{
clear();
for (auto e : l)
push_back(e);
}
return *this;
}
上面是一般写法,当然也有现代写法,如下
list<T>& operator=(list<T> l)
{
/*if (this != &l)
{
clear();
for (auto e : l)
push_back(e);
}
return *this;*/
swap(_head, l._head);
return *this;
}
相比之下,现代写法要简洁得多
6.迭代器失效
list的insert不会使迭代器失效,而erase会,迭代器失效的本质是迭代器空间被释放无法访问,所以vector的某些函数造成迭代器失效与list并无太大关联
7.比较vector与list
vector是一个可动态增长的数组
优点:随机访问,很好的支持了排序,二分查找,堆算法等
缺点:头部或中间的插入删除效率低,空间不够增容代价大
lsit是一个带头双向循环的链表
优点:任意位置插入删除数据效率高
缺点:不支持随机访问
总结:vector和list是两个相辅相成,互补的容器
新手写博客,有不对的位置希望大佬们能够指出,也谢谢大家能看到这里,让我们一起学习进步吧!!