记录不会的方法操作(C++)——容器后面插入一个容器的值

发布于:2024-04-30 ⋅ 阅读:(26) ⋅ 点赞:(0)

1.将一个容器中的值全部追加在另一个容器后面

记录起因:我想要将一个vector中的值全部追加到另一个vector后面,于是我想到了push_back这个函数,但是好像它一次只能在vector末尾插入一个值。而我上网搜索,也只能发现在前面插入的方法,并没有讲该如何在后面插入,即使是在末尾插入,也只是列出push_back操作。兴许是我太笨,无法领略其中精髓。因此,我就很疑惑,这种操作该如何实现呢?于是,有了此篇。为了节约大家时间,我直接把我当下想出的实现列在这里,例子如下:

    std::vector<int> m1 = { 1, 3, 5, 7 };
	std::vector<int> m2 = { 2, 4, 6, 8 };
	m2.insert(m2.begin(), m1.begin(), m1.end());
	m1.assign(m2.begin(), m2.end());
	for (auto i : m1) {
		std::cout << i << " ";
	}
	std::cout << std::endl;

结果:1 3 5 7 2 4 6 8

以上是我当下的实现,但是我觉得这种实现兴许效率不会很高,但是足够用了,也并没有写的很复杂对吧。

这里解释一下这个例子:将m2中的元素全部插入m1末尾。首先根据记录不熟悉的函数用法(C++)——insert这篇文章对insert函数的详细讲解,我们可以知道insert操作只会在某个迭代器之前插入,不会在迭代器之后插入。所以,倘若直接将m1的全部元素用insert插入到m1的全部元素之前,是不是等价于将m2的元素全部插入到m1的全部元素之后呢。因此,这样就使得在m2中的元素是符合我的需求的。但是我需要的是,在m1中实现该过程,于是,便使用assign函数(记录不熟悉的函数用法(C++)——assign)将m2中的元素全部赋值给m1,因而实现将一个容器中的值全部追加在另一个容器后面的操作。

以上操作也算是将前面讲解的assign函数和insert函数的概念再过一遍。

但是,以上方法有个很明显的缺点,那就是改变了m2中的值,这是不好的。于是,在刚刚写以上内容的时候,突然想到了一个更简单的方式。例子如下:

	std::vector<int> m1 = { 1, 3, 5, 7 };
	std::vector<int> m2 = { 2, 4, 6, 8 };
	m1.insert(m1.end(), m2.begin(), m2.end());
	for (auto i : m1) {
		std::cout << i << " ";
	}
	std::cout << std::endl;

结果:1 3 5 7 2 4 6 8

解释:这里直接在m1的末尾之前插入即可,这种操作很简单便捷。

既然都写到这里了,会不会有人想知道书上是否有相关操作的记载呢?有的有的,在实现以上操作之前,我先翻看了书,觉得其操作甚是麻烦,这才自己琢磨。于是在《C++ Primer》第十章中“介绍back_inserter”这一节中找到了相应操作方式,描述如下:

一种保证算法有足够元素空间来容纳输出数据的方法是使用插入迭代器(insert iterator)。插入迭代器是一种向容器中添加元素的迭代器。

如果不能理解这句话,书上则继续对这句话进行了解释,如下:

通常情况下,当我们通过一个迭代器向容器元素赋值时,值被赋予迭代器指向的元素。而当我们通过一个插入迭代器赋值时,一个与赋值相等的元素被添加到容器中。

我的解释,就是这个insert iterator 它就是一个给你指位置的定位器,它指哪,你的值就得放置在哪个位置。

接下来,介绍了iterator头文件中的back_inserter,如下:

back_inserter接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器。当我们通过此迭代器赋值时,赋值运算符会调用push_back将一个具有给定值的元素添加到容器中:

vector<int> vec; //空向量

auto it = back_inserter(vec); //通过它赋值会将元素添加到vec中

*it = 42; //vec中现在有一个元素,值为42

上面这段是不是很像在描述指针的作用呢?那么继续,

我们常常使用back_inserter来创建一个迭代器,作为算法的目的位置来使用。例如:

vector<int> vec; //空向量

fill_n(back_inserter(vec), 10, 0); //添加10个元素到vec

以上fill_n(back_inserter(vec), 10, 0)就是我们想要的操作了,但是看起来不怎么贴合我上面的题意。继续看对fill_n函数的解释

在每步迭代中,fill_n向给定序列的一个元素赋值。由于我们传递的参数是back_inserter返回的迭代器,因此每次赋值都会在vec上调用push_back。最终,这条fill_n调用语句向vec的末尾添加了10个元素,每个元素的值都是0.

这里好像确实是不贴合题意的,后续我经过查找,发现确实没有可以通过fill_n函数将一个容器的值插入另一个容器的用法。我对此进行了测试,报错,代码如下:

    std::vector<int> m1 = { 1, 3, 5, 7 };
	std::vector<int> m2 = { 2, 4, 6, 8 };
	fill_n(back_inserter(m1), m2.size(), m2);
	for (auto i : m1) {
		std::cout << i << " ";
	}
	std::cout << std::endl;

报错提示:C2679 二元“=”:没有找到接受“const _Ty”类型的右操作数的运算符(或没有可接受的转换)

于是,我打开了源码,这里只展示一下,不做解释,因为我尚未涉及对此的研究,只是解释一下const _Ty的出处。如下:

template <class _OutIt, class _Diff, class _Ty>
_CONSTEXPR20 _OutIt fill_n(_OutIt _Dest, const _Diff _Count_raw, const _Ty& _Val) {
    // copy _Val _Count times through [_Dest, ...)
    _Algorithm_int_t<_Diff> _Count = _Count_raw;
    if (0 < _Count) {
        if constexpr (_Is_vb_iterator<_OutIt, true>) {
            const auto _Last = _Dest + static_cast<typename _OutIt::difference_type>(_Count);
            _Fill_vbool(_Dest, _Last, _Val);
            return _Last;
        } else {
            auto _UDest = _Get_unwrapped_n(_Dest, _Count);
#ifdef __cpp_lib_is_constant_evaluated
            if (!_STD is_constant_evaluated())
#endif // __cpp_lib_is_constant_evaluated
            {
                if constexpr (_Fill_memset_is_safe<decltype(_UDest), _Ty>) {
                    _Fill_memset(_UDest, _Val, static_cast<size_t>(_Count));
                    _Seek_wrapped(_Dest, _UDest + _Count);
                    return _Dest;
                } else if constexpr (_Fill_zero_memset_is_safe<decltype(_UDest), _Ty>) {
                    if (_Is_all_bits_zero(_Val)) {
                        _Fill_zero_memset(_UDest, static_cast<size_t>(_Count));
                        _Seek_wrapped(_Dest, _UDest + _Count);
                        return _Dest;
                    }
                }
            }

            for (; 0 < _Count; --_Count, (void) ++_UDest) {
                *_UDest = _Val;
            }

            _Seek_wrapped(_Dest, _UDest);
        }
    }
    return _Dest;
}

总结,如果想要实现将一个容器的值插入另一个容器就只用我上面写的方法就好,或者还有一个复杂一点的方法就是用for循环一个个赋值。


网站公告

今日签到

点亮在社区的每一天
去签到