|
|
|
@ -610,36 +610,66 @@ list<T>::erase(const_iterator first, const_iterator last)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 清空 list
|
|
|
|
|
/**
|
|
|
|
|
* 清除列表中的所有元素。
|
|
|
|
|
* 这个函数用于移除列表中的所有元素,并将列表的大小设置为0。
|
|
|
|
|
* 它遍历列表,销毁每个节点,然后断开节点之间的链接。
|
|
|
|
|
* 这个过程确保了所有动态分配的内存都被释放,并且列表被重置为初始状态。
|
|
|
|
|
*
|
|
|
|
|
* 注意:调用此函数后,列表将变为空,所有指向列表元素的迭代器、引用和指针都将失效。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
void list<T>::clear()
|
|
|
|
|
{
|
|
|
|
|
// 如果列表不为空,则执行清除操作
|
|
|
|
|
if (size_ != 0)
|
|
|
|
|
{
|
|
|
|
|
// 从第一个实际元素节点开始遍历(跳过头节点)
|
|
|
|
|
auto cur = node_->next;
|
|
|
|
|
// 用于临时存储下一个节点,以便在销毁当前节点后仍然可以访问它
|
|
|
|
|
for (base_ptr next = cur->next; cur != node_; cur = next, next = cur->next)
|
|
|
|
|
{
|
|
|
|
|
// 销毁当前节点,释放其内存
|
|
|
|
|
destroy_node(cur->as_node());
|
|
|
|
|
}
|
|
|
|
|
// 断开头节点的链接,使其成为一个孤立的节点
|
|
|
|
|
node_->unlink();
|
|
|
|
|
// 将列表的大小设置为0
|
|
|
|
|
size_ = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 重置容器大小
|
|
|
|
|
/**
|
|
|
|
|
* 调整列表的大小到new_size,如果需要,用value填充新元素或删除多余的元素。
|
|
|
|
|
* 这个函数用于改变列表中的元素数量。如果new_size小于当前列表的大小,
|
|
|
|
|
* 它将删除超出new_size的元素。如果new_size大于当前列表的大小,
|
|
|
|
|
* 它将在列表末尾插入足够数量的value元素以使列表大小达到new_size。
|
|
|
|
|
*
|
|
|
|
|
* @param new_size 列表的目标大小。
|
|
|
|
|
* @param value 用于填充新元素的值,如果new_size大于当前列表大小。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
void list<T>::resize(size_type new_size, const value_type& value)
|
|
|
|
|
{
|
|
|
|
|
// 获取列表的开始迭代器
|
|
|
|
|
auto i = begin();
|
|
|
|
|
// 初始化当前长度
|
|
|
|
|
size_type len = 0;
|
|
|
|
|
// 遍历列表,直到达到新的大小或列表末尾
|
|
|
|
|
while (i != end() && len < new_size)
|
|
|
|
|
{
|
|
|
|
|
// 移动到下一个元素
|
|
|
|
|
++i;
|
|
|
|
|
// 增加当前长度
|
|
|
|
|
++len;
|
|
|
|
|
}
|
|
|
|
|
// 如果当前长度等于新的大小,删除剩余的元素
|
|
|
|
|
if (len == new_size)
|
|
|
|
|
{
|
|
|
|
|
erase(i, node_);
|
|
|
|
|
}
|
|
|
|
|
// 如果当前长度小于新的大小,插入新元素
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
insert(node_, new_size - len, value);
|
|
|
|
@ -667,42 +697,78 @@ void list<T>::splice(const_iterator pos, list& x)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将 it 所指的节点接合于 pos 之前
|
|
|
|
|
/**
|
|
|
|
|
* 将另一个列表x中的单个元素移动到当前列表的pos位置。
|
|
|
|
|
* 这个函数用于将列表x中的单个元素it移动到当前列表的指定位置pos。
|
|
|
|
|
* 它首先检查元素it是否不在pos之前或pos位置,且两个列表不是同一个对象。
|
|
|
|
|
* 然后,它检查当前列表的大小是否会超过最大限制。
|
|
|
|
|
* 如果检查通过,它将元素it从列表x中解链,并将其链接到当前列表的pos位置。
|
|
|
|
|
* 最后,它更新两个列表的大小。
|
|
|
|
|
*
|
|
|
|
|
* @param pos 一个const_iterator,指定当前列表中的插入位置。
|
|
|
|
|
* @param x 要移动元素的源列表。
|
|
|
|
|
* @param it 一个const_iterator,指向要移动的元素。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
void list<T>::splice(const_iterator pos, list& x, const_iterator it)
|
|
|
|
|
{
|
|
|
|
|
// 检查元素it是否不在pos之前或pos位置,且两个列表不是同一个对象
|
|
|
|
|
if (pos.node_ != it.node_ && pos.node_ != it.node_->next)
|
|
|
|
|
{
|
|
|
|
|
// 检查当前列表的大小是否会超过最大限制
|
|
|
|
|
THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list<T>'s size too big");
|
|
|
|
|
|
|
|
|
|
// 获取要移动的节点
|
|
|
|
|
auto f = it.node_;
|
|
|
|
|
|
|
|
|
|
// 从列表x中解链节点f
|
|
|
|
|
x.unlink_nodes(f, f);
|
|
|
|
|
// 将节点f链接到当前列表的pos位置
|
|
|
|
|
link_nodes(pos.node_, f, f);
|
|
|
|
|
|
|
|
|
|
// 更新当前列表和列表x的大小
|
|
|
|
|
++size_;
|
|
|
|
|
--x.size_;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将 list x 的 [first, last) 内的节点接合于 pos 之前
|
|
|
|
|
/**
|
|
|
|
|
* 将另一个列表x中的一段区间[first, last)移动到当前列表的pos位置。
|
|
|
|
|
* 这个函数用于将列表x中的一段区间移动到当前列表的指定位置pos。
|
|
|
|
|
* 它首先检查区间是否有效且两个列表不是同一个对象。
|
|
|
|
|
* 然后,它计算区间中的元素数量,并检查当前列表的大小是否会超过最大限制。
|
|
|
|
|
* 如果检查通过,它将区间从列表x中解链,并将其链接到当前列表的pos位置。
|
|
|
|
|
* 最后,它更新两个列表的大小。
|
|
|
|
|
*
|
|
|
|
|
* @param pos 一个const_iterator,指定当前列表中的插入位置。
|
|
|
|
|
* @param x 要移动元素的源列表。
|
|
|
|
|
* @param first 一个const_iterator,指向要移动的元素区间的开始。
|
|
|
|
|
* @param last 一个const_iterator,指向要移动的元素区间的结束。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
void list<T>::splice(const_iterator pos, list& x, const_iterator first, const_iterator last)
|
|
|
|
|
{
|
|
|
|
|
// 检查区间是否有效且两个列表不是同一个对象
|
|
|
|
|
if (first != last && this != &x)
|
|
|
|
|
{
|
|
|
|
|
// 计算区间中的元素数量
|
|
|
|
|
size_type n = mystl::distance(first, last);
|
|
|
|
|
// 检查当前列表的大小是否会超过最大限制
|
|
|
|
|
THROW_LENGTH_ERROR_IF(size_ > max_size() - n, "list<T>'s size too big");
|
|
|
|
|
// 获取区间的头节点和尾节点的前一个节点
|
|
|
|
|
auto f = first.node_;
|
|
|
|
|
auto l = last.node_->prev;
|
|
|
|
|
|
|
|
|
|
// 从列表x中解链该区间
|
|
|
|
|
x.unlink_nodes(f, l);
|
|
|
|
|
// 将解链的区间链接到当前列表的pos位置
|
|
|
|
|
link_nodes(pos.node_, f, l);
|
|
|
|
|
|
|
|
|
|
// 更新当前列表和列表x的大小
|
|
|
|
|
size_ += n;
|
|
|
|
|
x.size_ -= n;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将另一元操作 pred 为 true 的所有元素移除
|
|
|
|
|
template <class T>
|
|
|
|
|
template <class UnaryPredicate>
|
|
|
|
@ -745,24 +811,40 @@ void list<T>::unique(BinaryPredicate pred)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 与另一个 list 合并,按照 comp 为 true 的顺序
|
|
|
|
|
/**
|
|
|
|
|
* 合并两个列表,使它们有序。
|
|
|
|
|
* 这个函数用于将另一个列表x合并到当前列表中,合并后的列表将按照comp指定的比较函数排序。
|
|
|
|
|
* 在合并之前,它会检查合并后的列表大小是否会超过最大限制。
|
|
|
|
|
* 然后,它遍历两个列表,将x中的元素按照排序顺序插入到当前列表中。
|
|
|
|
|
* 如果x中的元素在比较函数comp下小于当前列表的元素,它将x中的元素区间移动到当前列表的相应位置。
|
|
|
|
|
* 最后,如果x中还有剩余的元素,它们将被连接到当前列表的末尾。
|
|
|
|
|
*
|
|
|
|
|
* @param x 要合并的列表。
|
|
|
|
|
* @param comp 比较函数对象,用于确定元素的排序顺序。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
template <class Compare>
|
|
|
|
|
void list<T>::merge(list& x, Compare comp)
|
|
|
|
|
{
|
|
|
|
|
// 确保合并的两个列表不是同一个对象
|
|
|
|
|
if (this != &x)
|
|
|
|
|
{
|
|
|
|
|
// 检查合并后的列表大小是否会超过最大限制
|
|
|
|
|
THROW_LENGTH_ERROR_IF(size_ > max_size() - x.size_, "list<T>'s size too big");
|
|
|
|
|
|
|
|
|
|
// 获取当前列表的开始和结束迭代器
|
|
|
|
|
auto f1 = begin();
|
|
|
|
|
auto l1 = end();
|
|
|
|
|
// 获取要合并的列表的开始和结束迭代器
|
|
|
|
|
auto f2 = x.begin();
|
|
|
|
|
auto l2 = x.end();
|
|
|
|
|
|
|
|
|
|
// 遍历两个列表,合并元素
|
|
|
|
|
while (f1 != l1 && f2 != l2)
|
|
|
|
|
{
|
|
|
|
|
if (comp(*f2, *f1))
|
|
|
|
|
{
|
|
|
|
|
// 使 comp 为 true 的一段区间
|
|
|
|
|
// 找到x中第一个大于或等于f1的元素区间
|
|
|
|
|
auto next = f2;
|
|
|
|
|
++next;
|
|
|
|
|
for (; next != l2 && comp(*next, *f1); ++next)
|
|
|
|
@ -771,7 +853,7 @@ void list<T>::merge(list& x, Compare comp)
|
|
|
|
|
auto l = next.node_->prev;
|
|
|
|
|
f2 = next;
|
|
|
|
|
|
|
|
|
|
// link node
|
|
|
|
|
// 从x中解链该区间,并将其链接到当前列表的适当位置
|
|
|
|
|
x.unlink_nodes(f, l);
|
|
|
|
|
link_nodes(f1.node_, f, l);
|
|
|
|
|
++f1;
|
|
|
|
@ -781,7 +863,7 @@ void list<T>::merge(list& x, Compare comp)
|
|
|
|
|
++f1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 连接剩余部分
|
|
|
|
|
// 如果x中还有剩余的元素,将它们连接到当前列表的末尾
|
|
|
|
|
if (f2 != l2)
|
|
|
|
|
{
|
|
|
|
|
auto f = f2.node_;
|
|
|
|
@ -790,26 +872,41 @@ void list<T>::merge(list& x, Compare comp)
|
|
|
|
|
link_nodes(l1.node_, f, l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新当前列表的大小,x列表的大小设置为0
|
|
|
|
|
size_ += x.size_;
|
|
|
|
|
x.size_ = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将 list 反转
|
|
|
|
|
/**
|
|
|
|
|
* 反转列表中的元素顺序。
|
|
|
|
|
* 这个函数用于将列表中的元素顺序颠倒。它遍历列表,交换每个节点的前后指针,
|
|
|
|
|
* 从而实现元素顺序的反转。在遍历过程中,头节点的前后指针也会被适当地调整。
|
|
|
|
|
*
|
|
|
|
|
* 注意:此函数不会改变列表中元素的物理存储顺序,只是调整了节点之间的链接关系。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
void list<T>::reverse()
|
|
|
|
|
{
|
|
|
|
|
// 如果列表为空或只包含一个元素,则不需要反转
|
|
|
|
|
if (size_ <= 1)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// 获取列表的开始迭代器
|
|
|
|
|
auto i = begin();
|
|
|
|
|
// 获取列表的结束迭代器
|
|
|
|
|
auto e = end();
|
|
|
|
|
// 遍历列表,直到到达最后一个节点
|
|
|
|
|
while (i.node_ != e.node_)
|
|
|
|
|
{
|
|
|
|
|
// 交换当前节点的前后指针
|
|
|
|
|
mystl::swap(i.node_->prev, i.node_->next);
|
|
|
|
|
// 移动到下一个节点,即原前一个节点
|
|
|
|
|
i.node_ = i.node_->prev;
|
|
|
|
|
}
|
|
|
|
|
// 处理最后一个节点,将其前后指针交换
|
|
|
|
|
mystl::swap(e.node_->prev, e.node_->next);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -817,26 +914,39 @@ void list<T>::reverse()
|
|
|
|
|
// helper function
|
|
|
|
|
|
|
|
|
|
// 创建结点
|
|
|
|
|
/**
|
|
|
|
|
* 创建一个新的列表节点,并将给定的参数转发给节点值的构造函数。
|
|
|
|
|
* 这个函数用于分配一个新的节点并初始化其值。它使用完美转发来允许创建节点时传递任意参数。
|
|
|
|
|
* 分配节点后,它尝试构造节点中的值。如果构造过程中发生异常,它会释放已分配的节点并重新抛出异常。
|
|
|
|
|
*
|
|
|
|
|
* @param args 可变参数,用于节点值的构造函数。
|
|
|
|
|
* @return 指向新创建节点的指针。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
template <class ...Args>
|
|
|
|
|
typename list<T>::node_ptr
|
|
|
|
|
list<T>::create_node(Args&& ...args)
|
|
|
|
|
{
|
|
|
|
|
// 分配一个新的节点
|
|
|
|
|
node_ptr p = node_allocator::allocate(1);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 使用完美转发构造节点中的值
|
|
|
|
|
data_allocator::construct(mystl::address_of(p->value), mystl::forward<Args>(args)...);
|
|
|
|
|
// 初始化节点的prev和next指针
|
|
|
|
|
p->prev = nullptr;
|
|
|
|
|
p->next = nullptr;
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
// 如果构造过程中发生异常,释放已分配的节点
|
|
|
|
|
node_allocator::deallocate(p);
|
|
|
|
|
// 重新抛出异常
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
// 返回指向新创建节点的指针
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 销毁结点
|
|
|
|
|
template <class T>
|
|
|
|
|
void list<T>::destroy_node(node_ptr p)
|
|
|
|
@ -846,75 +956,125 @@ void list<T>::destroy_node(node_ptr p)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 用 n 个元素初始化容器
|
|
|
|
|
/**
|
|
|
|
|
* 初始化列表,填充n个指定值value的元素。
|
|
|
|
|
* 这个函数用于创建一个具有n个元素的列表,每个元素都被初始化为value。
|
|
|
|
|
* 它首先分配一个头节点,然后尝试创建n个新节点,每个节点都包含value,并将它们链接到列表的末尾。
|
|
|
|
|
* 如果在创建或链接节点的过程中发生异常,函数会清理已分配的资源,并重新抛出异常,以确保列表对象处于一致的状态。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
void list<T>::fill_init(size_type n, const value_type& value)
|
|
|
|
|
{
|
|
|
|
|
// 分配一个新的节点作为列表的头节点
|
|
|
|
|
node_ = base_allocator::allocate(1);
|
|
|
|
|
// 将头节点从链表中解链,使其成为一个独立的节点
|
|
|
|
|
node_->unlink();
|
|
|
|
|
// 设置列表的大小为n
|
|
|
|
|
size_ = n;
|
|
|
|
|
// 尝试创建n个新节点,并将它们链接到链表的末尾
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
for (; n > 0; --n)
|
|
|
|
|
{
|
|
|
|
|
// 创建一个新节点,包含给定的值value
|
|
|
|
|
auto node = create_node(value);
|
|
|
|
|
// 将新创建的节点链接到链表的末尾
|
|
|
|
|
link_nodes_at_back(node->as_base(), node->as_base());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
// 如果在创建节点或链接过程中发生异常,执行清理操作
|
|
|
|
|
clear();
|
|
|
|
|
// 释放之前分配的头节点
|
|
|
|
|
base_allocator::deallocate(node_);
|
|
|
|
|
// 将头节点指针设置为nullptr,表示链表为空
|
|
|
|
|
node_ = nullptr;
|
|
|
|
|
// 重新抛出捕获的异常
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 以 [first, last) 初始化容器
|
|
|
|
|
/**
|
|
|
|
|
* 初始化列表,拷贝给定迭代器范围内的元素。
|
|
|
|
|
* 这个函数用于创建一个列表,其元素是从指定的迭代器范围[first, last)拷贝而来的。
|
|
|
|
|
* 它首先分配一个头节点,然后计算迭代器范围内元素的数量,并尝试创建相应数量的节点,
|
|
|
|
|
* 每个节点都初始化为迭代器所指向的值,并将它们链接到列表的末尾。
|
|
|
|
|
* 如果在创建或链接节点的过程中发生异常,函数会清理已分配的资源,并重新抛出异常,以确保列表对象处于一致的状态。
|
|
|
|
|
*
|
|
|
|
|
* @param first 迭代器,指向要拷贝的元素范围的开始。
|
|
|
|
|
* @param last 迭代器,指向要拷贝的元素范围的结束。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
template <class Iter>
|
|
|
|
|
void list<T>::copy_init(Iter first, Iter last)
|
|
|
|
|
{
|
|
|
|
|
// 分配一个新的节点作为列表的头节点
|
|
|
|
|
node_ = base_allocator::allocate(1);
|
|
|
|
|
// 将头节点从链表中解链,使其成为一个独立的节点
|
|
|
|
|
node_->unlink();
|
|
|
|
|
// 计算迭代器范围内元素的数量
|
|
|
|
|
size_type n = mystl::distance(first, last);
|
|
|
|
|
// 设置列表的大小为计算出的元素数量
|
|
|
|
|
size_ = n;
|
|
|
|
|
// 尝试创建节点并链接到链表的末尾
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
for (; n > 0; --n, ++first)
|
|
|
|
|
{
|
|
|
|
|
// 创建一个新节点,包含迭代器指向的值
|
|
|
|
|
auto node = create_node(*first);
|
|
|
|
|
// 将新创建的节点链接到链表的末尾
|
|
|
|
|
link_nodes_at_back(node->as_base(), node->as_base());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
// 如果在创建节点或链接过程中发生异常,执行清理操作
|
|
|
|
|
clear();
|
|
|
|
|
// 释放之前分配的头节点
|
|
|
|
|
base_allocator::deallocate(node_);
|
|
|
|
|
// 将头节点指针设置为nullptr,表示链表为空
|
|
|
|
|
node_ = nullptr;
|
|
|
|
|
// 重新抛出捕获的异常
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在 pos 处连接一个节点
|
|
|
|
|
t/**
|
|
|
|
|
* 将新节点链接到迭代器pos指定的位置。
|
|
|
|
|
* 这个函数用于在列表中指定位置pos处插入一个新节点link_node。
|
|
|
|
|
* 如果pos是头节点node_,新节点将被链接在列表的末尾。
|
|
|
|
|
* 如果pos是头节点的下一个节点,新节点将被链接在列表的开头。
|
|
|
|
|
* 否则,新节点将被链接在pos指定的位置。
|
|
|
|
|
*
|
|
|
|
|
* @param pos 一个const_iterator,指定新节点插入的位置。
|
|
|
|
|
* @param link_node 一个base_ptr,指向要链接的新节点。
|
|
|
|
|
* @return 一个iterator,指向新链接的节点。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
typename list<T>::iterator
|
|
|
|
|
list<T>::link_iter_node(const_iterator pos, base_ptr link_node)
|
|
|
|
|
{
|
|
|
|
|
// 如果pos是头节点的下一个节点,将新节点链接在列表的开头
|
|
|
|
|
if (pos == node_->next)
|
|
|
|
|
{
|
|
|
|
|
link_nodes_at_front(link_node, link_node);
|
|
|
|
|
}
|
|
|
|
|
// 如果pos是头节点,将新节点链接在列表的末尾
|
|
|
|
|
else if (pos == node_)
|
|
|
|
|
{
|
|
|
|
|
link_nodes_at_back(link_node, link_node);
|
|
|
|
|
}
|
|
|
|
|
// 否则,将新节点链接在pos指定的位置
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
link_nodes(pos.node_, link_node, link_node);
|
|
|
|
|
}
|
|
|
|
|
// 返回一个迭代器,指向新链接的节点
|
|
|
|
|
return iterator(link_node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在 pos 处连接 [first, last] 的结点
|
|
|
|
|
template <class T>
|
|
|
|
|
void list<T>::link_nodes(base_ptr pos, base_ptr first, base_ptr last)
|
|
|
|
@ -954,19 +1114,34 @@ void list<T>::unlink_nodes(base_ptr first, base_ptr last)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 用 n 个元素为容器赋值
|
|
|
|
|
/**
|
|
|
|
|
* 列表赋值操作,用指定的值value填充列表或截断列表至指定大小n。
|
|
|
|
|
* 这个函数用于将列表中的元素数量调整为n,如果列表中的元素数量大于n,则截断列表;
|
|
|
|
|
* 如果列表中的元素数量小于n,则用value填充列表至n个元素。
|
|
|
|
|
* 它首先遍历列表,将现有元素赋值为value,直到达到n个元素或遍历完整个列表。
|
|
|
|
|
* 如果n大于当前列表大小,它将调用insert方法在列表末尾插入剩余的value元素;
|
|
|
|
|
* 如果n小于当前列表大小,它将调用erase方法删除多余的元素。
|
|
|
|
|
*
|
|
|
|
|
* @param n 列表的目标大小。
|
|
|
|
|
* @param value 用于填充或赋值的元素值。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
void list<T>::fill_assign(size_type n, const value_type& value)
|
|
|
|
|
{
|
|
|
|
|
// 获取列表的开始和结束迭代器
|
|
|
|
|
auto i = begin();
|
|
|
|
|
auto e = end();
|
|
|
|
|
// 遍历列表,将元素赋值为value,直到达到n个元素或遍历完整个列表
|
|
|
|
|
for (; n > 0 && i != e; --n, ++i)
|
|
|
|
|
{
|
|
|
|
|
*i = value;
|
|
|
|
|
}
|
|
|
|
|
// 如果n大于当前列表大小,需要在列表末尾插入剩余的value元素
|
|
|
|
|
if (n > 0)
|
|
|
|
|
{
|
|
|
|
|
insert(e, n, value);
|
|
|
|
|
}
|
|
|
|
|
// 如果n小于当前列表大小,需要删除多余的元素
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
erase(i, e);
|
|
|
|
@ -974,20 +1149,34 @@ void list<T>::fill_assign(size_type n, const value_type& value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 复制[f2, l2)为容器赋值
|
|
|
|
|
/**
|
|
|
|
|
* 列表赋值操作,通过拷贝指定迭代器范围内的元素来赋值。
|
|
|
|
|
* 这个函数用于将列表的内容替换为迭代器范围[f2, l2)内元素的拷贝。
|
|
|
|
|
* 它首先遍历列表,将现有元素赋值为迭代器f2指向的元素,直到f2到达l2或者列表遍历结束。
|
|
|
|
|
* 如果f2到达l2,说明新内容比原列表短,需要删除列表中剩余的元素。
|
|
|
|
|
* 如果f2没有到达l2,说明新内容比原列表长,需要在列表末尾插入剩余的元素。
|
|
|
|
|
*
|
|
|
|
|
* @param f2 迭代器,指向要拷贝的元素范围的开始。
|
|
|
|
|
* @param l2 迭代器,指向要拷贝的元素范围的结束。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
template <class Iter>
|
|
|
|
|
void list<T>::copy_assign(Iter f2, Iter l2)
|
|
|
|
|
{
|
|
|
|
|
// 获取列表的开始和结束迭代器
|
|
|
|
|
auto f1 = begin();
|
|
|
|
|
auto l1 = end();
|
|
|
|
|
// 遍历列表,将元素赋值为迭代器f2指向的元素
|
|
|
|
|
for (; f1 != l1 && f2 != l2; ++f1, ++f2)
|
|
|
|
|
{
|
|
|
|
|
*f1 = *f2;
|
|
|
|
|
}
|
|
|
|
|
// 如果f2到达l2,说明新内容比原列表短,删除列表中剩余的元素
|
|
|
|
|
if (f2 == l2)
|
|
|
|
|
{
|
|
|
|
|
erase(f1, l1);
|
|
|
|
|
}
|
|
|
|
|
// 如果f2没有到达l2,说明新内容比原列表长,在列表末尾插入剩余的元素
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
insert(l1, f2, l2);
|
|
|
|
@ -995,6 +1184,19 @@ void list<T>::copy_assign(Iter f2, Iter l2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在 pos 处插入 n 个元素
|
|
|
|
|
/**
|
|
|
|
|
* 在列表的指定位置插入n个相同值value的元素。
|
|
|
|
|
* 这个函数用于在列表的pos位置插入n个新元素,每个元素都被初始化为value。
|
|
|
|
|
* 它首先检查n是否为0,如果不是,则创建一个新节点并初始化为value。
|
|
|
|
|
* 然后,它尝试创建剩余的n-1个节点,并将它们链接起来。
|
|
|
|
|
* 如果在创建或链接节点的过程中发生异常,函数会清理已分配的资源,并重新抛出异常。
|
|
|
|
|
* 最后,它将新创建的节点序列链接到列表的pos位置。
|
|
|
|
|
*
|
|
|
|
|
* @param pos 一个const_iterator,指定插入位置。
|
|
|
|
|
* @param n 要插入的元素数量。
|
|
|
|
|
* @param value 用于初始化新元素的值。
|
|
|
|
|
* @return 一个iterator,指向第一个插入的节点。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
typename list<T>::iterator
|
|
|
|
|
list<T>::fill_insert(const_iterator pos, size_type n, const value_type& value)
|
|
|
|
@ -1016,10 +1218,12 @@ list<T>::fill_insert(const_iterator pos, size_type n, const value_type& value)
|
|
|
|
|
end.node_->next = next->as_base(); // link node
|
|
|
|
|
next->prev = end.node_;
|
|
|
|
|
}
|
|
|
|
|
// 更新列表的大小
|
|
|
|
|
size_ += add_size;
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
// 如果发生异常,清理已创建的节点
|
|
|
|
|
auto enode = end.node_;
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
@ -1029,14 +1233,28 @@ list<T>::fill_insert(const_iterator pos, size_type n, const value_type& value)
|
|
|
|
|
break;
|
|
|
|
|
enode = prev;
|
|
|
|
|
}
|
|
|
|
|
// 重新抛出异常
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
// 将新创建的节点序列链接到列表的pos位置
|
|
|
|
|
link_nodes(pos.node_, r.node_, end.node_);
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 在 pos 处插入 [first, last) 的元素
|
|
|
|
|
/**
|
|
|
|
|
* 在列表的指定位置插入n个从迭代器first开始的元素。
|
|
|
|
|
* 这个函数用于在列表的pos位置插入n个新元素,这些元素是从迭代器first开始的。
|
|
|
|
|
* 它首先检查n是否为0,如果不是,则创建一个新节点并初始化为*first的值。
|
|
|
|
|
* 然后,它尝试创建剩余的n-1个节点,并将它们链接起来。
|
|
|
|
|
* 如果在创建或链接节点的过程中发生异常,函数会清理已分配的资源,并重新抛出异常。
|
|
|
|
|
* 最后,它将新创建的节点序列链接到列表的pos位置。
|
|
|
|
|
*
|
|
|
|
|
* @param pos 一个const_iterator,指定插入位置。
|
|
|
|
|
* @param n 要插入的元素数量。
|
|
|
|
|
* @param first 迭代器,指向要插入的元素序列的开始。
|
|
|
|
|
* @return 一个iterator,指向第一个插入的节点。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
template <class Iter>
|
|
|
|
|
typename list<T>::iterator
|
|
|
|
@ -1052,16 +1270,19 @@ list<T>::copy_insert(const_iterator pos, size_type n, Iter first)
|
|
|
|
|
iterator end = r;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 从first开始,创建n个节点
|
|
|
|
|
for (--n, ++first; n > 0; --n, ++first, ++end)
|
|
|
|
|
{
|
|
|
|
|
auto next = create_node(*first);
|
|
|
|
|
end.node_->next = next->as_base(); // link node
|
|
|
|
|
next->prev = end.node_;
|
|
|
|
|
}
|
|
|
|
|
// 更新列表的大小
|
|
|
|
|
size_ += add_size;
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
// 如果发生异常,清理已创建的节点
|
|
|
|
|
auto enode = end.node_;
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
@ -1071,14 +1292,28 @@ list<T>::copy_insert(const_iterator pos, size_type n, Iter first)
|
|
|
|
|
break;
|
|
|
|
|
enode = prev;
|
|
|
|
|
}
|
|
|
|
|
// 重新抛出异常
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
// 将新创建的节点序列链接到列表的pos位置
|
|
|
|
|
link_nodes(pos.node_, r.node_, end.node_);
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 对 list 进行归并排序,返回一个迭代器指向区间最小元素的位置
|
|
|
|
|
/**
|
|
|
|
|
* 对列表的指定区间进行排序。
|
|
|
|
|
* 这个函数使用递归的方式实现列表的归并排序。
|
|
|
|
|
* 它首先检查区间内元素的数量,如果小于2,则直接返回。
|
|
|
|
|
* 如果元素数量为2,它将比较两个元素并交换它们以确保顺序。
|
|
|
|
|
* 如果元素数量大于2,它将区间分为两半,递归地对每一半进行排序,然后合并两个有序区间。
|
|
|
|
|
*
|
|
|
|
|
* @param f1 区间的开始迭代器。
|
|
|
|
|
* @param l2 区间的结束迭代器。
|
|
|
|
|
* @param n 区间内元素的数量。
|
|
|
|
|
* @param comp 比较函数对象,用于确定元素的排序顺序。
|
|
|
|
|
* @return 排序后的第一个元素的迭代器。
|
|
|
|
|
*/
|
|
|
|
|
template <class T>
|
|
|
|
|
template <class Compared>
|
|
|
|
|
typename list<T>::iterator
|
|
|
|
@ -1102,8 +1337,8 @@ list<T>::list_sort(iterator f1, iterator l2, size_type n, Compared comp)
|
|
|
|
|
auto n2 = n / 2;
|
|
|
|
|
auto l1 = f1;
|
|
|
|
|
mystl::advance(l1, n2);
|
|
|
|
|
auto result = f1 = list_sort(f1, l1, n2, comp); // 前半段的最小位置
|
|
|
|
|
auto f2 = l1 = list_sort(l1, l2, n - n2, comp); // 后半段的最小位置
|
|
|
|
|
auto result = f1 = list_sort(f1, l1, n2, comp); // 对前半段进行排序,找到最小元素的位置
|
|
|
|
|
auto f2 = l1 = list_sort(l1, l2, n - n2, comp); // 对后半段进行排序,找到最小元素的位置
|
|
|
|
|
|
|
|
|
|
// 把较小的一段区间移到前面
|
|
|
|
|
if (comp(*f2, *f1))
|
|
|
|
@ -1154,7 +1389,6 @@ list<T>::list_sort(iterator f1, iterator l2, size_type n, Compared comp)
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 重载比较操作符
|
|
|
|
|
template <class T>
|
|
|
|
|
bool operator==(const list<T>& lhs, const list<T>& rhs)
|
|
|
|
|