diff --git a/src/MyTinySTL-master/MyTinySTL/list.h b/src/MyTinySTL-master/MyTinySTL/list.h index e6bfc1c..61e187d 100644 --- a/src/MyTinySTL-master/MyTinySTL/list.h +++ b/src/MyTinySTL-master/MyTinySTL/list.h @@ -610,36 +610,66 @@ list::erase(const_iterator first, const_iterator last) } // 清空 list +/** + * 清除列表中的所有元素。 + * 这个函数用于移除列表中的所有元素,并将列表的大小设置为0。 + * 它遍历列表,销毁每个节点,然后断开节点之间的链接。 + * 这个过程确保了所有动态分配的内存都被释放,并且列表被重置为初始状态。 + * + * 注意:调用此函数后,列表将变为空,所有指向列表元素的迭代器、引用和指针都将失效。 + */ template void list::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 void list::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::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 void list::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'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 void list::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'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 template @@ -745,24 +811,40 @@ void list::unique(BinaryPredicate pred) } // 与另一个 list 合并,按照 comp 为 true 的顺序 +/** + * 合并两个列表,使它们有序。 + * 这个函数用于将另一个列表x合并到当前列表中,合并后的列表将按照comp指定的比较函数排序。 + * 在合并之前,它会检查合并后的列表大小是否会超过最大限制。 + * 然后,它遍历两个列表,将x中的元素按照排序顺序插入到当前列表中。 + * 如果x中的元素在比较函数comp下小于当前列表的元素,它将x中的元素区间移动到当前列表的相应位置。 + * 最后,如果x中还有剩余的元素,它们将被连接到当前列表的末尾。 + * + * @param x 要合并的列表。 + * @param comp 比较函数对象,用于确定元素的排序顺序。 + */ template template void list::merge(list& x, Compare comp) { + // 确保合并的两个列表不是同一个对象 if (this != &x) { + // 检查合并后的列表大小是否会超过最大限制 THROW_LENGTH_ERROR_IF(size_ > max_size() - x.size_, "list'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::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::merge(list& x, Compare comp) ++f1; } } - // 连接剩余部分 + // 如果x中还有剩余的元素,将它们连接到当前列表的末尾 if (f2 != l2) { auto f = f2.node_; @@ -790,26 +872,41 @@ void list::merge(list& x, Compare comp) link_nodes(l1.node_, f, l); } + // 更新当前列表的大小,x列表的大小设置为0 size_ += x.size_; x.size_ = 0; } } // 将 list 反转 +/** + * 反转列表中的元素顺序。 + * 这个函数用于将列表中的元素顺序颠倒。它遍历列表,交换每个节点的前后指针, + * 从而实现元素顺序的反转。在遍历过程中,头节点的前后指针也会被适当地调整。 + * + * 注意:此函数不会改变列表中元素的物理存储顺序,只是调整了节点之间的链接关系。 + */ template void list::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::reverse() // helper function // 创建结点 +/** + * 创建一个新的列表节点,并将给定的参数转发给节点值的构造函数。 + * 这个函数用于分配一个新的节点并初始化其值。它使用完美转发来允许创建节点时传递任意参数。 + * 分配节点后,它尝试构造节点中的值。如果构造过程中发生异常,它会释放已分配的节点并重新抛出异常。 + * + * @param args 可变参数,用于节点值的构造函数。 + * @return 指向新创建节点的指针。 + */ template template typename list::node_ptr list::create_node(Args&& ...args) { + // 分配一个新的节点 node_ptr p = node_allocator::allocate(1); try { + // 使用完美转发构造节点中的值 data_allocator::construct(mystl::address_of(p->value), mystl::forward(args)...); + // 初始化节点的prev和next指针 p->prev = nullptr; p->next = nullptr; } catch (...) { + // 如果构造过程中发生异常,释放已分配的节点 node_allocator::deallocate(p); + // 重新抛出异常 throw; } + // 返回指向新创建节点的指针 return p; } - // 销毁结点 template void list::destroy_node(node_ptr p) @@ -846,75 +956,125 @@ void list::destroy_node(node_ptr p) } // 用 n 个元素初始化容器 +/** + * 初始化列表,填充n个指定值value的元素。 + * 这个函数用于创建一个具有n个元素的列表,每个元素都被初始化为value。 + * 它首先分配一个头节点,然后尝试创建n个新节点,每个节点都包含value,并将它们链接到列表的末尾。 + * 如果在创建或链接节点的过程中发生异常,函数会清理已分配的资源,并重新抛出异常,以确保列表对象处于一致的状态。 + */ template void list::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 template void list::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 typename list::iterator list::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 void list::link_nodes(base_ptr pos, base_ptr first, base_ptr last) @@ -954,19 +1114,34 @@ void list::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 void list::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::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 template void list::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::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 typename list::iterator list::fill_insert(const_iterator pos, size_type n, const value_type& value) @@ -1016,10 +1218,12 @@ list::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::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 template typename list::iterator @@ -1052,16 +1270,19 @@ list::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::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 template typename list::iterator @@ -1102,8 +1337,8 @@ list::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::list_sort(iterator f1, iterator l2, size_type n, Compared comp) } return result; } - // 重载比较操作符 template bool operator==(const list& lhs, const list& rhs)