두 std::vector
s를 어떻게 연결 합니까?
a + b
또는 a.concat(b)
표준 라이브러리 로 구현되지 않은 이유가 궁금한 유일한 사람 입니까? 기본 구현은 차선책 일 수 있지만 모든 배열 연결을 미세 최적화 할 필요는 없습니다.
두 std::vector
s를 어떻게 연결 합니까?
a + b
또는 a.concat(b)
표준 라이브러리 로 구현되지 않은 이유가 궁금한 유일한 사람 입니까? 기본 구현은 차선책 일 수 있지만 모든 배열 연결을 미세 최적화 할 필요는 없습니다.
답변:
vector1.insert( vector1.end(), vector2.begin(), vector2.end() );
reserve
먼저 대상 벡터 를 호출 하는 것이 도움이 됩니까?
vector1.capacity() >= 2 * vector1.size()
. 전화하지 않으면 비정형 std::vector::reserve()
입니다. 그렇지 않으면 벡터 매개 변수 2, 3로 전달 된 반복자 무효화, 재 할당됩니다
.concat
또는+=
C ++ 11을 사용 중이고 단순히 요소를 복사하지 않고 요소를 이동하려면 std::move_iterator
insert (또는 copy)와 함께 사용할 수 있습니다 .
#include <vector>
#include <iostream>
#include <iterator>
int main(int argc, char** argv) {
std::vector<int> dest{1,2,3,4,5};
std::vector<int> src{6,7,8,9,10};
// Move elements from src to dest.
// src is left in undefined but safe-to-destruct state.
dest.insert(
dest.end(),
std::make_move_iterator(src.begin()),
std::make_move_iterator(src.end())
);
// Print out concatenated vector.
std::copy(
dest.begin(),
dest.end(),
std::ostream_iterator<int>(std::cout, "\n")
);
return 0;
}
int를 사용하는 예는 복사하는 것보다 효율적이지 않기 때문에 int가있는 예에서는 더 효율적이지 않지만 이동이 최적화 된 데이터 구조의 경우 불필요한 상태를 복사하지 않아도됩니다.
#include <vector>
#include <iostream>
#include <iterator>
int main(int argc, char** argv) {
std::vector<std::vector<int>> dest{{1,2,3,4,5}, {3,4}};
std::vector<std::vector<int>> src{{6,7,8,9,10}};
// Move elements from src to dest.
// src is left in undefined but safe-to-destruct state.
dest.insert(
dest.end(),
std::make_move_iterator(src.begin()),
std::make_move_iterator(src.end())
);
return 0;
}
이동 후 src의 요소는 정의되지 않았지만 파괴하기에 안전한 상태로 유지되며 이전 요소는 마지막에 dest의 새 요소로 직접 전송되었습니다.
std::move(src.begin(), src.end(), back_inserter(dest))
?
또는 다음을 사용할 수 있습니다.
std::copy(source.begin(), source.end(), std::back_inserter(destination));
이 패턴은 두 벡터가 정확히 같은 유형의 것을 포함하지 않는 경우 유용합니다. std :: back_inserter 대신 무언가를 사용하여 한 유형에서 다른 유형으로 변환 할 수 있기 때문입니다.
reserve
먼저 전화를 멈추는 것은 아무것도 없습니다 . 그 이유는 std::copy
당신이 아닌 다른 뭔가를 사용하고자하는 경우에 유용는 때로는 back_inserter
.
C ++ 11에서는 벡터 b를 a에 추가하는 것이 좋습니다.
std::move(b.begin(), b.end(), std::back_inserter(a));
때 a
와 b
중복되지 않고, b
더 이상 사용하지 않을.
insert
더 안전한 옛날 방식으로 돌아 가야 할 것 입니다.
insert()
와 다른가요 move_iterator
? 그렇다면 어떻게?
std::move
대부분의 사람들이이 과부하를 모르기 때문에 여기서 말하는 내용에 대한 메모를 추가했습니다 . 그것이 개선되기를 바랍니다.
나는 이미 언급 한 것을 선호합니다 :
a.insert(a.end(), b.begin(), b.end());
그러나 C ++ 11을 사용하는 경우 일반적인 방법이 하나 더 있습니다.
a.insert(std::end(a), std::begin(b), std::end(b));
또한 질문의 일부는 아니지만 reserve
더 나은 성능을 위해 추가하기 전에 사용하는 것이 좋습니다 . 그리고 벡터를 예약하지 않고 자체와 연결하면 실패하므로 항상해야합니다 reserve
.
기본적으로 필요한 것 :
template <typename T>
void Append(std::vector<T>& a, const std::vector<T>& b)
{
a.reserve(a.size() + b.size());
a.insert(a.end(), b.begin(), b.end());
}
std::
유형 a
이에서 오는 경우 에만 추가 std
하여 일반적인 측면을 무시 합니다.
vector :: insert를 사용해야합니다
v1.insert(v1.end(), v2.begin(), v2.end());
연결 의 일반적인 성능 향상 은 벡터 크기를 확인하는 것입니다. 작은 것을 큰 것을 합치거나 삽입하십시오.
//vector<int> v1,v2;
if(v1.size()>v2.size()) {
v1.insert(v1.end(),v2.begin(),v2.end());
} else {
v2.insert(v2.end(),v1.begin(),v1.end());
}
v1.insert(v2.end()...
에서 반복자 v2
를 사용하여의 위치를 지정하고 v1
있습니다.
강력한 예외 보장에 관심이있는 경우 (복사 생성자가 예외를 throw 할 수있는 경우) :
template<typename T>
inline void append_copy(std::vector<T>& v1, const std::vector<T>& v2)
{
const auto orig_v1_size = v1.size();
v1.reserve(orig_v1_size + v2.size());
try
{
v1.insert(v1.end(), v2.begin(), v2.end());
}
catch(...)
{
v1.erase(v1.begin() + orig_v1_size, v1.end());
throw;
}
}
append_move
벡터 요소의 이동 생성자가 던질 수있는 경우 (일반적으로는 아니지만) 일반적으로 강력한 보장과 마찬가지로 구현할 수 없습니다.
v1.erase(...
너무 던져?
insert
이미 이것을 처리합니다. 또한이 호출 erase
은에 해당합니다 resize
.
이것을 헤더 파일에 추가하십시오 :
template <typename T> vector<T> concat(vector<T> &a, vector<T> &b) {
vector<T> ret = vector<T>();
copy(a.begin(), a.end(), back_inserter(ret));
copy(b.begin(), b.end(), back_inserter(ret));
return ret;
}
이 방법으로 사용하십시오 :
vector<int> a = vector<int>();
vector<int> b = vector<int>();
a.push_back(1);
a.push_back(2);
b.push_back(62);
vector<int> r = concat(a, b);
r은 [1,2,62]를 포함합니다
C ++ 11 이동 시맨틱을 사용하는 범용 솔루션은 다음과 같습니다.
template <typename T>
std::vector<T> concat(const std::vector<T>& lhs, const std::vector<T>& rhs)
{
if (lhs.empty()) return rhs;
if (rhs.empty()) return lhs;
std::vector<T> result {};
result.reserve(lhs.size() + rhs.size());
result.insert(result.cend(), lhs.cbegin(), lhs.cend());
result.insert(result.cend(), rhs.cbegin(), rhs.cend());
return result;
}
template <typename T>
std::vector<T> concat(std::vector<T>&& lhs, const std::vector<T>& rhs)
{
lhs.insert(lhs.cend(), rhs.cbegin(), rhs.cend());
return std::move(lhs);
}
template <typename T>
std::vector<T> concat(const std::vector<T>& lhs, std::vector<T>&& rhs)
{
rhs.insert(rhs.cbegin(), lhs.cbegin(), lhs.cend());
return std::move(rhs);
}
template <typename T>
std::vector<T> concat(std::vector<T>&& lhs, std::vector<T>&& rhs)
{
if (lhs.empty()) return std::move(rhs);
lhs.insert(lhs.cend(), std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end()));
return std::move(lhs);
}
이것이 append
ing 과 어떻게 다른지 주목하십시오 vector
.
+ 연산자를위한 고유 한 템플릿을 준비 할 수 있습니다.
template <typename T>
inline T operator+(const T & a, const T & b)
{
T res = a;
res.insert(res.end(), b.begin(), b.end());
return res;
}
다음으로 + 만 사용하십시오 :
vector<int> a{1, 2, 3, 4};
vector<int> b{5, 6, 7, 8};
for (auto x: a + b)
cout << x << " ";
cout << endl;
이 예제는 출력을 제공합니다.
12 34 5678 9
T operator+(const T & a, const T & b)
것은 위험하므로 사용 하는 것이 좋습니다 vector<T> operator+(const vector<T> & a, const vector<T> & b)
.
알고리즘이 std::merge
에서 C ++ (17) 매우 쉽게 사용할 수,
아래는 예입니다.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
//DATA
std::vector<int> v1{2,4,6,8};
std::vector<int> v2{12,14,16,18};
//MERGE
std::vector<int> dst;
std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst));
//PRINT
for(auto item:dst)
std::cout<<item<<" ";
return 0;
}
std::vector::insert
다른 것 : 두 범위를 새로운 범위로 병합하는 것과 다른 벡터의 끝에 다른 벡터를 삽입하는 것. 답에서 언급 할 가치가 있습니까?
목표가 단순히 읽기 전용 목적으로 값의 범위를 반복하는 것이라면 대안은 두 벡터를 복사하지 않고 프록시 (O (1)) 주위로 감싸는 것입니다 (O (n)). 하나의 연속적인 것으로
std::vector<int> A{ 1, 2, 3, 4, 5};
std::vector<int> B{ 10, 20, 30 };
VecProxy<int> AB(A, B); // ----> O(1)!
for (size_t i = 0; i < AB.size(); i++)
std::cout << AB[i] << " "; // ----> 1 2 3 4 5 10 20 30
'VecProxy'구현 및 장단점을 포함한 자세한 내용 은 https://stackoverflow.com/a/55838758/2379625 를 참조하십시오 .
vector<int> v1 = {1, 2, 3, 4, 5};
vector<int> v2 = {11, 12, 13, 14, 15};
copy(v2.begin(), v2.end(), back_inserter(v1));
나는 rvalue-references에서 이동하고 그렇지 않으면 복사하여 많은 수의 컨테이너를 연결하는이 기능을 구현했습니다.
namespace internal {
// Implementation detail of Concatenate, appends to a pre-reserved vector, copying or moving if
// appropriate
template<typename Target, typename Head, typename... Tail>
void AppendNoReserve(Target* target, Head&& head, Tail&&... tail) {
// Currently, require each homogenous inputs. If there is demand, we could probably implement a
// version that outputs a vector whose value_type is the common_type of all the containers
// passed to it, and call it ConvertingConcatenate.
static_assert(
std::is_same_v<
typename std::decay_t<Target>::value_type,
typename std::decay_t<Head>::value_type>,
"Concatenate requires each container passed to it to have the same value_type");
if constexpr (std::is_lvalue_reference_v<Head>) {
std::copy(head.begin(), head.end(), std::back_inserter(*target));
} else {
std::move(head.begin(), head.end(), std::back_inserter(*target));
}
if constexpr (sizeof...(Tail) > 0) {
AppendNoReserve(target, std::forward<Tail>(tail)...);
}
}
template<typename Head, typename... Tail>
size_t TotalSize(const Head& head, const Tail&... tail) {
if constexpr (sizeof...(Tail) > 0) {
return head.size() + TotalSize(tail...);
} else {
return head.size();
}
}
} // namespace internal
/// Concatenate the provided containers into a single vector. Moves from rvalue references, copies
/// otherwise.
template<typename Head, typename... Tail>
auto Concatenate(Head&& head, Tail&&... tail) {
size_t totalSize = internal::TotalSize(head, tail...);
std::vector<typename std::decay_t<Head>::value_type> result;
result.reserve(totalSize);
internal::AppendNoReserve(&result, std::forward<Head>(head), std::forward<Tail>(tail)...);
return result;
}
찾고있는 것이 벡터를 생성 한 후 다른 벡터에 추가하는 방법이라면 vector::insert
여러 번 답변 된 것처럼 가장 좋은 방법입니다.
vector<int> first = {13};
const vector<int> second = {42};
first.insert(first.end(), second.cbegin(), second.cend());
슬프게도 const vector<int>
위와 같이 구성 한 다음을 구성해야합니다 insert
.
실제로 찾고있는 것이이 두 개의 연결을 유지하는 컨테이너 vector<int>
인 경우 다음과 같은 경우 더 나은 것을 사용할 수 있습니다.
vector
은 프리미티브를 포함const
컨테이너를 원한다위의 내용이 모두 사실이라면 귀하의에 포함 된 프리미티브의 크기와 일치하는 basic_string
사람을 사용하는 것이 좋습니다 . 이러한 크기가 일정하게 유지되도록하려면 코드에를 포함시켜야합니다 .char_type
vector
static_assert
static_assert(sizeof(char32_t) == sizeof(int));
이 사실을 유지하면 다음과 같이 할 수 있습니다.
const u32string concatenation = u32string(first.cbegin(), first.cend()) + u32string(second.cbegin(), second.cend());
차이점 string
과 차이점에 대한 자세한 내용은 https://stackoverflow.com/a/35558008/2642059를 참조vector
하십시오.
이 코드의 실제 예를 보려면 여기를 참조하십시오. http://ideone.com/7Iww3I
이 솔루션은 약간 복잡하지만 제공 할 수있는 boost-range
다른 멋진 기능도 있습니다.
#include <iostream>
#include <vector>
#include <boost/range/algorithm/copy.hpp>
int main(int, char**) {
std::vector<int> a = { 1,2,3 };
std::vector<int> b = { 4,5,6 };
boost::copy(b, std::back_inserter(a));
for (auto& iter : a) {
std::cout << iter << " ";
}
return EXIT_SUCCESS;
}
종종 의도는 벡터를 결합 하고 일부 작업을 수행하면서 벡터 a
를 b
반복하는 것입니다. 이 경우 말도 안되는 간단한 join
기능이 있습니다.
#include <iostream>
#include <vector>
#include <boost/range/join.hpp>
#include <boost/range/algorithm/copy.hpp>
int main(int, char**) {
std::vector<int> a = { 1,2,3 };
std::vector<int> b = { 4,5,6 };
std::vector<int> c = { 7,8,9 };
// Just creates an iterator
for (auto& iter : boost::join(a, boost::join(b, c))) {
std::cout << iter << " ";
}
std::cout << "\n";
// Can also be used to create a copy
std::vector<int> d;
boost::copy(boost::join(a, boost::join(b, c)), std::back_inserter(d));
for (auto& iter : d) {
std::cout << iter << " ";
}
return EXIT_SUCCESS;
}
큰 벡터의 경우 복사가 없으므로 이점이 될 수 있습니다. 또한 일반화를 둘 이상의 컨테이너로 쉽게 복사하는 데 사용할 수 있습니다.
어떤 이유로 boost::join(a,b,c)
합리적인 것은 없습니다 .
다형성 유형 사용을위한 템플릿을 사용하여 사전 구현 된 STL 알고리즘으로이를 수행 할 수 있습니다.
#include <iostream>
#include <vector>
#include <algorithm>
template<typename T>
void concat(std::vector<T>& valuesa, std::vector<T>& valuesb){
for_each(valuesb.begin(), valuesb.end(), [&](int value){ valuesa.push_back(value);});
}
int main()
{
std::vector<int> values_p={1,2,3,4,5};
std::vector<int> values_s={6,7};
concat(values_p, values_s);
for(auto& it : values_p){
std::cout<<it<<std::endl;
}
return 0;
}
더 이상 사용하지 않으려면 두 번째 벡터를 지울 수 있습니다 ( clear()
메서드).
하나의 루프로 2 std::vector-s
를 연결하십시오 .for
std::vector
예:
std::vector <int> v1 {1, 2, 3};//declare vector1
std::vector <int> v2 {4, 5};//declare vector2
std::vector <int> suma;//declare vector suma
for(int i = 0; i < v1.size()-1;i++)//for loop 1
{
suma.push_back(v1[i]);
}
for(int i = 0; i< v2.size()-1;i++)/for loop 2
{
suma.push_back(v2[i]);
}
for(int i = 0; i < suma.size(); i++)//for loop 3-output
{
std::cout<<suma[i];
}
에이 코드를 작성하십시오 main()
.
for
루프는 잘못이다. 벡터의 유효한 인덱스는 0 ~ size()-1
입니다. 당신 루프 종료 조건이 있어야합니다 i < v1.size()
사용 <
하지 <=
. 잘못된 조건을 사용하면 컨테이너 외부의 메모리에 액세스합니다.
auto
수동 인덱싱 대신 최소한 반복자를 사용해야 합니다. 어떤 인덱스를 순차적으로 수행하는 것만 연결하고 있는지는 신경 쓰지 않습니다.
size()-1
두 가지 루프 조건에서 왜 사용 하고 있는지 설명 할 수 있습니까 ? 마지막 벡터 요소를 건너 뜁니다. 세 번째 루프는 현재 유일한 루프입니다.
솔직히 말하면 두 벡터의 요소를 다른 벡터로 복사하거나 두 벡터 중 하나만 추가하여 두 벡터를 빠르게 연결할 수 있습니다. 그것은 당신의 목표에 달려 있습니다.
방법 1 : 크기가있는 새 벡터 할당은 두 원본 벡터 크기의 합입니다.
vector<int> concat_vector = vector<int>();
concat_vector.setcapacity(vector_A.size() + vector_B.size());
// Loop for copy elements in two vectors into concat_vector
방법 2 : 벡터 B의 요소를 추가 / 삽입하여 벡터 A를 추가
// Loop for insert elements of vector_B into vector_A with insert()
function: vector_A.insert(vector_A .end(), vector_B.cbegin(), vector_B.cend());
std::move_iterator
복사하는 대신 요소를 이동 하도록 사용하는 것이 좋습니다 . ( en.cppreference.com/w/cpp/iterator/move_iterator 참조 )
setcapacity
? 무엇입니까 function:
?
resize
방법 에 대해 이야기하고 있다고 생각합니다 .