ฉันกำลังใช้มัลติเธรดและต้องการผสานผลลัพธ์ ตัวอย่างเช่น:
std::vector<int> A;
std::vector<int> B;
std::vector<int> AB;
ฉันต้องการให้ AB ต้องมีเนื้อหาของ A และเนื้อหาของ B ตามลำดับนั้น วิธีที่มีประสิทธิภาพมากที่สุดในการทำอะไรเช่นนี้คืออะไร?
ฉันกำลังใช้มัลติเธรดและต้องการผสานผลลัพธ์ ตัวอย่างเช่น:
std::vector<int> A;
std::vector<int> B;
std::vector<int> AB;
ฉันต้องการให้ AB ต้องมีเนื้อหาของ A และเนื้อหาของ B ตามลำดับนั้น วิธีที่มีประสิทธิภาพมากที่สุดในการทำอะไรเช่นนี้คืออะไร?
คำตอบ:
AB.reserve( A.size() + B.size() ); // preallocate memory
AB.insert( AB.end(), A.begin(), A.end() );
AB.insert( AB.end(), B.begin(), B.end() );
นี่คือสิ่งที่ฟังก์ชั่นสมาชิกstd::vector::insert
มีไว้เพื่อ
std::vector<int> AB = A;
AB.insert(AB.end(), B.begin(), B.end());
insert
ในการเข้าถึงแบบวนซ้ำและสงวนไว้ล่วงหน้า
distance
มีความซับซ้อน O (1)) ถึงกระนั้นการรับประกันประสิทธิภาพinsert
ก็เป็นสิ่งที่ควรคำนึงถึงเมื่อคุณสามารถทำได้ดีกว่าโดยการวางแผนล่วงหน้า
size < capacity
เวลาส่วนใหญ่การคาดคะเนสาขาจะทำให้คำสั่งของสาขาที่ไม่ได้ทำการจัดสรรใหม่อยู่ในขั้นตอนการสอนลดความล่าช้าของสาขาที่เกิดขึ้นยกเว้นการนับซ้ำต่ำ นี่ถือว่าเป็นการใช้เวกเตอร์ที่ดีรวมถึงขั้นตอนการสอนของ CPU & การคาดคะเนสาขา [ดี] แต่สิ่งเหล่านี้เป็นข้อสันนิษฐานที่น่าเชื่อถือสำหรับเครื่องมือที่ทันสมัยและเครื่องเดสก์ท็อป ไม่ทราบเกี่ยวกับสมาร์ทโฟน ..
ขึ้นอยู่กับว่าคุณต้องการให้เวกเตอร์สองตัวต่อกันจริง ๆ หรือคุณต้องการที่จะให้รูปลักษณ์ของการต่อกันของสาเหตซ้ำ ฟังก์ชั่นเพิ่ม :: เข้าร่วม
http://www.boost.org/doc/libs/1_43_0/libs/range/doc/html/range/reference/utilities/join.html
จะให้สิ่งนี้กับคุณ
std::vector<int> v0;
v0.push_back(1);
v0.push_back(2);
v0.push_back(3);
std::vector<int> v1;
v1.push_back(4);
v1.push_back(5);
v1.push_back(6);
...
BOOST_FOREACH(const int & i, boost::join(v0, v1)){
cout << i << endl;
}
ควรให้คุณ
1
2
3
4
5
6
Note boost :: join ไม่ได้คัดลอกสองเวกเตอร์ลงในคอนเทนเนอร์ใหม่ แต่สร้างคู่ของตัววนซ้ำ (ช่วง) ที่ครอบคลุมช่วงของคอนเทนเนอร์ทั้งสอง จะมีบางส่วนของค่าใช้จ่ายประสิทธิภาพ แต่อาจน้อยกว่าที่การคัดลอกข้อมูลทั้งหมดไปยังคอนเทนเนอร์ใหม่ก่อน
จากคำตอบของ Kiril V. Lyadvinskyฉันได้สร้างเวอร์ชั่นใหม่ ตัวอย่างนี้ใช้เทมเพลตและการโหลดมากเกินไป ด้วยคุณสามารถเขียนและvector3 = vector1 + vector2
vector4 += vector3
หวังว่ามันจะช่วยได้
template <typename T>
std::vector<T> operator+(const std::vector<T> &A, const std::vector<T> &B)
{
std::vector<T> AB;
AB.reserve(A.size() + B.size()); // preallocate memory
AB.insert(AB.end(), A.begin(), A.end()); // add A;
AB.insert(AB.end(), B.begin(), B.end()); // add B;
return AB;
}
template <typename T>
std::vector<T> &operator+=(std::vector<T> &A, const std::vector<T> &B)
{
A.reserve(A.size() + B.size()); // preallocate memory without erase original data
A.insert(A.end(), B.begin(), B.end()); // add B;
return A; // here A could be named AB
}
::
จะถูกนำไป;)
v1 + v2
ไม่ได้เป็นตัวแทนเพิ่มเติม
@
เหมือนใน F #
ในทิศทางของคำตอบ Bradgonesurfing ของหลายต่อหลายครั้งหนึ่งไม่ได้จริงๆต้องไปเชื่อมสองเวกเตอร์ (O (n)) แต่แทนที่จะเป็นเพียงแค่การทำงานกับพวกเขาราวกับว่าพวกเขาตัดแบ่ง (O (1)) หากเป็นกรณีของคุณก็สามารถทำได้โดยไม่ต้องใช้ห้องสมุด Boost
เคล็ดลับคือการสร้างพร็อกซีเวกเตอร์: คลาส wrapper ที่จัดการการอ้างอิงไปยังเวกเตอร์ทั้งสองซึ่งมองจากภายนอกเป็นหนึ่งเดียวที่ต่อเนื่องกัน
การใช้งาน
std::vector<int> A{ 1, 2, 3, 4, 5};
std::vector<int> B{ 10, 20, 30 };
VecProxy<int> AB(A, B); // ----> O(1). No copies performed.
for (size_t i = 0; i < AB.size(); ++i)
std::cout << AB[i] << " "; // 1 2 3 4 5 10 20 30
การดำเนินงาน
template <class T>
class VecProxy {
private:
std::vector<T>& v1, v2;
public:
VecProxy(std::vector<T>& ref1, std::vector<T>& ref2) : v1(ref1), v2(ref2) {}
const T& operator[](const size_t& i) const;
const size_t size() const;
};
template <class T>
const T& VecProxy<T>::operator[](const size_t& i) const{
return (i < v1.size()) ? v1[i] : v2[i - v1.size()];
};
template <class T>
const size_t VecProxy<T>::size() const { return v1.size() + v2.size(); };
ผลประโยชน์หลัก ๆ
มันเป็น O (1) (เวลาคงที่) เพื่อสร้างและมีการจัดสรรหน่วยความจำเพิ่มเติมน้อยที่สุด
บางสิ่งที่ควรพิจารณา
อีกหนึ่งตัวแปรที่เรียบง่ายซึ่งยังไม่ได้กล่าวถึง:
copy(A.begin(),A.end(),std::back_inserter(AB));
copy(B.begin(),B.end(),std::back_inserter(AB));
และการใช้อัลกอริทึมผสาน:
#include <algorithm>
#include <vector>
#include <iterator>
#include <iostream>
#include <sstream>
#include <string>
template<template<typename, typename...> class Container, class T>
std::string toString(const Container<T>& v)
{
std::stringstream ss;
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(ss, ""));
return ss.str();
};
int main()
{
std::vector<int> A(10);
std::vector<int> B(5); //zero filled
std::vector<int> AB(15);
std::for_each(A.begin(), A.end(),
[](int& f)->void
{
f = rand() % 100;
});
std::cout << "before merge: " << toString(A) << "\n";
std::cout << "before merge: " << toString(B) << "\n";
merge(B.begin(),B.end(), begin(A), end(A), AB.begin(), [](int&,int&)->bool {});
std::cout << "after merge: " << toString(AB) << "\n";
return 1;
}
หากเวกเตอร์ของคุณถูกจัดเรียง * ตรวจสอบset_unionจาก <algorithm>
set_union(A.begin(), A.end(), B.begin(), B.end(), AB.begin());
มีตัวอย่างที่ละเอียดกว่านี้ในลิงค์
* ขอบคุณ rlbond
โซลูชันทั้งหมดนั้นถูกต้อง แต่ฉันพบว่าง่ายขึ้นเพียงแค่เขียนฟังก์ชันเพื่อใช้สิ่งนี้ แบบนี้:
template <class T1, class T2>
void ContainerInsert(T1 t1, T2 t2)
{
t1->insert(t1->end(), t2->begin(), t2->end());
}
ด้วยวิธีนี้คุณสามารถหลีกเลี่ยงตำแหน่งชั่วคราวเช่นนี้:
ContainerInsert(vec, GetSomeVector());