C++
std :: वेक्टर
खोज…
परिचय
एक वेक्टर एक गतिशील सरणी है जिसमें स्वचालित रूप से संचित भंडारण होता है। एक वेक्टर में तत्वों को कुशलता से एक्सेस किया जा सकता है क्योंकि एक सरणी में उन लोगों को फायदा हो सकता है जो वैक्टर गतिशील रूप से आकार में बदल सकते हैं।
भंडारण के संदर्भ में वेक्टर डेटा (आमतौर पर) गतिशील रूप से आवंटित मेमोरी में रखा जाता है, इस प्रकार कुछ मामूली ओवरहेड की आवश्यकता होती है; इसके विपरीत C-arrays
और std::array
घोषित स्थान के सापेक्ष स्वचालित भंडारण का उपयोग करते हैं और इस प्रकार कोई ओवरहेड नहीं होता है।
टिप्पणियों
एक std::vector
का उपयोग करने के लिए #include <vector>
का उपयोग करके <vector>
हैडर को शामिल करने की आवश्यकता है।
एक std::vector
में तत्व std::vector
को मुफ्त स्टोर पर आकस्मिक रूप से संग्रहीत किया जाता है। यह ध्यान दिया जाना चाहिए कि जब वैक्टर std::vector<std::vector<int> >
रूप में नेस्टेड होते हैं std::vector<std::vector<int> >
, प्रत्येक वेक्टर के तत्व सन्निहित होते हैं, लेकिन प्रत्येक वेक्टर फ्री स्टोर पर अपना अंतर्निहित बफर आवंटित करता है।
एक एसटीडी :: वेक्टर की शुरुआत
एक std::vector
को घोषित करते समय कई तरीकों से आरंभीकृत किया जा सकता है:
std::vector<int> v{ 1, 2, 3 }; // v becomes {1, 2, 3}
// Different from std::vector<int> v(3, 6)
std::vector<int> v{ 3, 6 }; // v becomes {3, 6}
// Different from std::vector<int> v{3, 6} in C++11
std::vector<int> v(3, 6); // v becomes {6, 6, 6}
std::vector<int> v(4); // v becomes {0, 0, 0, 0}
एक वेक्टर को दूसरे कंटेनर से कई तरीकों से शुरू किया जा सकता है:
प्रतिलिपि निर्माण (केवल दूसरे वेक्टर से), जो v2
से डेटा की प्रतिलिपि बनाता है:
std::vector<int> v(v2);
std::vector<int> v = v2;
चाल निर्माण (केवल दूसरे वेक्टर से), जो v2
से डेटा ले जाता है:
std::vector<int> v(std::move(v2));
std::vector<int> v = std::move(v2);
Iterator (रेंज) कॉपी-कंस्ट्रक्शन, जो तत्वों को v
में कॉपी करता है:
// from another vector
std::vector<int> v(v2.begin(), v2.begin() + 3); // v becomes {v2[0], v2[1], v2[2]}
// from an array
int z[] = { 1, 2, 3, 4 };
std::vector<int> v(z, z + 3); // v becomes {1, 2, 3}
// from a list
std::list<int> list1{ 1, 2, 3 };
std::vector<int> v(list1.begin(), list1.end()); // v becomes {1, 2, 3}
Iterator चाल-निर्माण, std::make_move_iterator
का उपयोग करके std::make_move_iterator
, जो तत्वों को v
में ले जाता है:
// from another vector
std::vector<int> v(std::make_move_iterator(v2.begin()),
std::make_move_iterator(v2.end());
// from a list
std::list<int> list1{ 1, 2, 3 };
std::vector<int> v(std::make_move_iterator(list1.begin()),
std::make_move_iterator(list1.end()));
assign()
सदस्य फ़ंक्शन की सहायता से, एक std::vector
को इसके निर्माण के बाद पुनर्निमित किया जा सकता है:
v.assign(4, 100); // v becomes {100, 100, 100, 100}
v.assign(v2.begin(), v2.begin() + 3); // v becomes {v2[0], v2[1], v2[2]}
int z[] = { 1, 2, 3, 4 };
v.assign(z + 1, z + 4); // v becomes {2, 3, 4}
तत्वों को सम्मिलित करना
एक वेक्टर के अंत में एक तत्व लागू करना (कॉपी / मूविंग द्वारा):
struct Point {
double x, y;
Point(double x, double y) : x(x), y(y) {}
};
std::vector<Point> v;
Point p(10.0, 2.0);
v.push_back(p); // p is copied into the vector.
सदिश के अंत में एक तत्व को लागू करके तत्व का निर्माण किया जाता है:
std::vector<Point> v;
v.emplace_back(10.0, 2.0); // The arguments are passed to the constructor of the
// given type (here Point). The object is constructed
// in the vector, avoiding a copy.
ध्यान दें कि std::vector
एक नहीं है push_front()
प्रदर्शन के कारणों की वजह सदस्य कार्य करते हैं। शुरुआत में एक तत्व जोड़ने से वेक्टर के सभी मौजूदा तत्व चले जाते हैं। आप अक्सर अपने कंटेनर की शुरुआत में तत्व सम्मिलित करना चाहते हैं, तो आप उपयोग करना चाह सकते हैं std::list
या std::deque
बजाय।
वेक्टर की किसी भी स्थिति में एक तत्व सम्मिलित करना:
std::vector<int> v{ 1, 2, 3 };
v.insert(v.begin(), 9); // v now contains {9, 1, 2, 3}
सदिश के किसी भी स्थान पर किसी तत्व को जगह में रखकर एक तत्व सम्मिलित करना:
std::vector<int> v{ 1, 2, 3 };
v.emplace(v.begin()+1, 9); // v now contains {1, 9, 2, 3}
वेक्टर की किसी भी स्थिति में एक और वेक्टर सम्मिलित करना:
std::vector<int> v(4); // contains: 0, 0, 0, 0
std::vector<int> v2(2, 10); // contains: 10, 10
v.insert(v.begin()+2, v2.begin(), v2.end()); // contains: 0, 0, 10, 10, 0, 0
वेक्टर की किसी भी स्थिति में एक सरणी सम्मिलित करना:
std::vector<int> v(4); // contains: 0, 0, 0, 0
int a [] = {1, 2, 3}; // contains: 1, 2, 3
v.insert(v.begin()+1, a, a+sizeof(a)/sizeof(a[0])); // contains: 0, 1, 2, 3, 0, 0, 0
कई तत्वों को डालने से पहले reserve()
उपयोग करें यदि परिणामी वेक्टर आकार पहले से ही कई वास्तविकताओं से बचने के लिए जाना जाता है ( वेक्टर आकार और क्षमता देखें ):
std::vector<int> v;
v.reserve(100);
for(int i = 0; i < 100; ++i)
v.emplace_back(i);
इस मामले में कॉलिंग resize()
की गलती न करें, या आप अनजाने में 200 तत्वों के साथ एक वेक्टर बनाएंगे जहां केवल बाद वाले एक सौ में आपके इच्छित मूल्य होंगे।
एसटीडी ओवर वेक्टर: वेक्टर
आप एक std::vector
पर कई तरीकों से पुनरावृति कर सकते हैं। निम्न में से प्रत्येक अनुभाग के लिए, v
को निम्नानुसार परिभाषित किया गया है:
std::vector<int> v;
फॉरवर्ड डायरेक्शन में Iterating
// Range based for
for(const auto& value: v) {
std::cout << value << "\n";
}
// Using a for loop with iterator
for(auto it = std::begin(v); it != std::end(v); ++it) {
std::cout << *it << "\n";
}
// Using for_each algorithm, using a function or functor:
void fun(int const& value) {
std::cout << value << "\n";
}
std::for_each(std::begin(v), std::end(v), fun);
// Using for_each algorithm. Using a lambda:
std::for_each(std::begin(v), std::end(v), [](int const& value) {
std::cout << value << "\n";
});
// Using a for loop with iterator
for(std::vector<int>::iterator it = std::begin(v); it != std::end(v); ++it) {
std::cout << *it << "\n";
}
// Using a for loop with index
for(std::size_t i = 0; i < v.size(); ++i) {
std::cout << v[i] << "\n";
}
रिवर्स डायरेक्शन में Iterating
// There is no standard way to use range based for for this.
// See below for alternatives.
// Using for_each algorithm
// Note: Using a lambda for clarity. But a function or functor will work
std::for_each(std::rbegin(v), std::rend(v), [](auto const& value) {
std::cout << value << "\n";
});
// Using a for loop with iterator
for(auto rit = std::rbegin(v); rit != std::rend(v); ++rit) {
std::cout << *rit << "\n";
}
// Using a for loop with index
for(std::size_t i = 0; i < v.size(); ++i) {
std::cout << v[v.size() - 1 - i] << "\n";
}
हालांकि रिवर्स इटरेट के लिए सीमा के आधार पर उपयोग करने का कोई अंतर्निहित तरीका नहीं है; इसे ठीक करना अपेक्षाकृत सरल है। उपयोगों के लिए आधारित रेंज begin()
और end()
पुनरावृत्तियाँ प्राप्त करने के लिए है और इस प्रकार एक आवरण ऑब्जेक्ट के साथ इसका अनुकरण करके आपको अपेक्षित परिणाम प्राप्त हो सकते हैं।
template<class C>
struct ReverseRange {
C c; // could be a reference or a copy, if the original was a temporary
ReverseRange(C&& cin): c(std::forward<C>(cin)) {}
ReverseRange(ReverseRange&&)=default;
ReverseRange& operator=(ReverseRange&&)=delete;
auto begin() const {return std::rbegin(c);}
auto end() const {return std::rend(c);}
};
// C is meant to be deduced, and perfect forwarded into
template<class C>
ReverseRange<C> make_ReverseRange(C&& c) {return {std::forward<C>(c)};}
int main() {
std::vector<int> v { 1,2,3,4};
for(auto const& value: make_ReverseRange(v)) {
std::cout << value << "\n";
}
}
कांस्टेबल तत्वों को लागू करना
के बाद से सी ++ 11 cbegin()
और cend()
विधियों, आप एक वेक्टर के लिए एक निरंतर इटरेटर प्राप्त करने के लिए अनुमति देते हैं, भले ही वेक्टर गैर स्थिरांक है। एक निरंतर पुनरावृत्ति आपको पढ़ने की अनुमति देता है, लेकिन वेक्टर की सामग्री को संशोधित नहीं करता है जो कि कॉन्स्टिपेशन को सही करने के लिए उपयोगी है:
// forward iteration
for (auto pos = v.cbegin(); pos != v.cend(); ++pos) {
// type of pos is vector<T>::const_iterator
// *pos = 5; // Compile error - can't write via const iterator
}
// reverse iteration
for (auto pos = v.crbegin(); pos != v.crend(); ++pos) {
// type of pos is vector<T>::const_iterator
// *pos = 5; // Compile error - can't write via const iterator
}
// expects Functor::operand()(T&)
for_each(v.begin(), v.end(), Functor());
// expects Functor::operand()(const T&)
for_each(v.cbegin(), v.cend(), Functor())
as_const इसे विस्तृत करने के लिए पुनरावृति देता है:
for (auto const& e : std::as_const(v)) {
std::cout << e << '\n';
}
C ++ के पुराने संस्करणों में इसे लागू करना आसान है:
template <class T>
constexpr std::add_const_t<T>& as_const(T& t) noexcept {
return t;
}
दक्षता पर एक नोट
चूँकि वर्ग std::vector
मूल रूप से एक ऐसा वर्ग है जो गतिशील रूप से आवंटित सन्निहित सरणी का प्रबंधन करता है, वही सिद्धांत यहाँ समझाया गया है जो C ++ वैक्टर पर लागू होता है। अनुक्रमणिका-प्रमुख आदेश सिद्धांत का पालन करते समय सूचकांक द्वारा वेक्टर की सामग्री तक पहुंच बहुत अधिक कुशल है। बेशक, वेक्टर की प्रत्येक पहुंच अपनी प्रबंधन सामग्री को भी कैश में डालती है, लेकिन जैसा कि कई बार (विशेष रूप से यहां और यहां ) पर बहस की गई है, एक std::vector
पर पुनरावृत्ति के लिए प्रदर्शन में अंतर std::vector
एक कच्चे सरणी की तुलना में नगण्य है। तो C में कच्चे सरणियों के लिए दक्षता का एक ही सिद्धांत C ++ के std::vector
लिए भी लागू होता है।
एक्सेस करने वाले तत्व
एक std::vector
में तत्वों तक पहुँचने के दो प्राथमिक तरीके हैं
- सूचकांक आधारित पहुंच
- iterators
सूचकांक आधारित पहुंच:
यह सबस्क्रिप्ट ऑपरेटर []
, या सदस्य फ़ंक्शन at()
साथ किया जा सकता है।
दोनों std::vector
में संबंधित स्थिति में तत्व का संदर्भ देते हैं (जब तक कि यह एक vector<bool>
), ताकि इसे पढ़ा जा सके और साथ ही संशोधित किया जा सके (यदि वेक्टर const
नहीं है)।
[]
और at()
भिन्न है कि []
किसी भी सीमा जाँच करने की गारंटी नहीं है, जबकि at()
करता है। उन तत्वों तक पहुंच जहां index < 0
या index >= size
लिए अपरिभाषित व्यवहार है []
, जबकि at()
एक std::out_of_range
अपवाद को फेंकता है।
नोट: नीचे दिए गए उदाहरण स्पष्टता के लिए C ++ 11-शैली के प्रारंभ का उपयोग करते हैं, लेकिन ऑपरेटरों को सभी संस्करणों के साथ उपयोग किया जा सकता है (जब तक कि C11 11 को चिह्नित नहीं किया जाता)।
std::vector<int> v{ 1, 2, 3 };
// using []
int a = v[1]; // a is 2
v[1] = 4; // v now contains { 1, 4, 3 }
// using at()
int b = v.at(2); // b is 3
v.at(2) = 5; // v now contains { 1, 4, 5 }
int c = v.at(3); // throws std::out_of_range exception
क्योंकि at()
विधि सीमा जाँच करती है और अपवादों को फेंक सकती है, यह []
की तुलना में धीमा है। यह []
पसंदीदा कोड बनाता है जहां ऑपरेशन का शब्दार्थ यह गारंटी देता है कि सूचकांक सीमा में है। किसी भी मामले में, वैक्टर के तत्वों तक पहुंच निरंतर समय में की जाती है। इसका मतलब है कि वेक्टर के पहले तत्व तक पहुंचने में दूसरे तत्व, तीसरे तत्व और इतने पर पहुंचने की समान लागत (समय में) है।
उदाहरण के लिए, इस लूप पर विचार करें
for (std::size_t i = 0; i < v.size(); ++i) {
v[i] = 1;
}
यहाँ हम जानते हैं कि इंडेक्स वैरिएबल i
हमेशा सीमा में होता है, इसलिए यह सीपीयू चक्रों की बर्बादी होगी ताकि यह जांचा जा सके कि i
operator[]
लिए हर कॉल के लिए सीमा में है operator[]
।
front()
और back()
सदस्य फ़ंक्शन क्रमशः वेक्टर के पहले और अंतिम तत्व तक आसान संदर्भ पहुंच की अनुमति देते हैं। इन पदों का अक्सर उपयोग किया जाता है, और विशेष एक्सेसर्स []
का उपयोग करके अपने विकल्पों की तुलना में अधिक पठनीय हो सकते हैं:
std::vector<int> v{ 4, 5, 6 }; // In pre-C++11 this is more verbose
int a = v.front(); // a is 4, v.front() is equivalent to v[0]
v.front() = 3; // v now contains {3, 5, 6}
int b = v.back(); // b is 6, v.back() is equivalent to v[v.size() - 1]
v.back() = 7; // v now contains {3, 5, 7}
नोट : यह खाली वेक्टर पर front()
या back()
आह्वान करने के लिए अपरिभाषित व्यवहार है। आपको यह जांचने की आवश्यकता है कि front()
या back()
कॉल करने से पहले कंटेनर empty()
सदस्य फ़ंक्शन का उपयोग करके खाली नहीं है (जो यह जांचता है कि कंटेनर खाली है back()
। एक खाली वेक्टर के परीक्षण के लिए 'खाली ()' के उपयोग का एक सरल उदाहरण इस प्रकार है:
int main ()
{
std::vector<int> v;
int sum (0);
for (int i=1;i<=10;i++) v.push_back(i);//create and initialize the vector
while (!v.empty())//loop through until the vector tests to be empty
{
sum += v.back();//keep a running total
v.pop_back();//pop out the element which removes it from the vector
}
std::cout << "total: " << sum << '\n';//output the total to the user
return 0;
}
ऊपर दिया गया उदाहरण 1 से 10 तक की संख्या के अनुक्रम के साथ एक वेक्टर बनाता है। यह वेक्टर के तत्वों को तब तक बाहर करता है जब तक वेक्टर खाली नहीं होता है (अपरिभाषित व्यवहार को रोकने के लिए 'खाली' () का उपयोग करके)। फिर वेक्टर में संख्याओं का योग गणना और उपयोगकर्ता को प्रदर्शित किया जाता है।
data()
विधि std::vector
द्वारा आंतरिक रूप से अपने तत्वों को संग्रहीत करने के लिए उपयोग की जाने वाली कच्ची मेमोरी के लिए एक संकेतक लौटाता है। यह सबसे अधिक बार उपयोग किया जाता है जब वेक्टर डेटा को विरासत कोड को पास किया जाता है जो सी-स्टाइल सरणी की अपेक्षा करता है।
std::vector<int> v{ 1, 2, 3, 4 }; // v contains {1, 2, 3, 4}
int* p = v.data(); // p points to 1
*p = 4; // v now contains {4, 2, 3, 4}
++p; // p points to 2
*p = 3; // v now contains {4, 3, 3, 4}
p[1] = 2; // v now contains {4, 3, 2, 4}
*(p + 2) = 1; // v now contains {4, 3, 2, 1}
C ++ 11 से पहले, data()
विधि को फोन करके front()
लाया जा सकता है front()
और लौटे मूल्य का पता ले सकते हैं:
std::vector<int> v(4);
int* ptr = &(v.front()); // or &v[0]
यह काम करता है क्योंकि वैक्टर हमेशा अपने तत्वों को सन्निहित स्मृति स्थानों में संग्रहीत करने की गारंटी देते हैं, यह मानते हुए कि वेक्टर की सामग्री अनपेक्षित operator&
। यदि ऐसा होता है, तो आपको पूर्व-सी ++ 11 में std::addressof
को फिर से लागू करना होगा। यह भी मानता है कि वेक्टर खाली नहीं है।
iterators:
Iterators उदाहरण में और अधिक विस्तार से समझाया गया है " std::vector
पर Iterating" और लेख Iterators । संक्षेप में, वे वेक्टर के तत्वों के संकेत के समान कार्य करते हैं:
std::vector<int> v{ 4, 5, 6 };
auto it = v.begin();
int i = *it; // i is 4
++it;
i = *it; // i is 5
*it = 6; // v contains { 4, 6, 6 }
auto e = v.end(); // e points to the element after the end of v. It can be
// used to check whether an iterator reached the end of the vector:
++it;
it == v.end(); // false, it points to the element at position 2 (with value 6)
++it;
it == v.end(); // true
यह मानक के अनुरूप है कि एक std::vector<T>
के पुनरावृत्तियों वास्तव में T*
s हैं, लेकिन अधिकांश मानक पुस्तकालय ऐसा नहीं करते हैं। ऐसा नहीं करने से दोनों त्रुटि संदेश में सुधार होता है, गैर-पोर्टेबल कोड पकड़ता है, और इसका उपयोग गैर-रिलीज़ बिल्ड में डिबगिंग चेक के साथ पुनरावृत्तियों को लिखत करने के लिए किया जा सकता है। फिर, रिलीज़ बिल्ड में, अंतर्निहित सूचक के चारों ओर लपेटने वाला वर्ग दूर अनुकूलित होता है।
आप अप्रत्यक्ष पहुंच के लिए एक वेक्टर के एक तत्व के लिए एक संदर्भ या एक संकेतक जारी रख सकते हैं। vector
में तत्वों के ये संदर्भ या संकेत स्थिर रहते हैं और जब तक आप vector
में तत्व पर या उससे पहले तत्वों को जोड़ते / हटाते हैं, या आप vector
क्षमता को बदलने का कारण नहीं हैं, तब तक पहुंच परिभाषित रहती है। यह पुनरावृत्तियों को अमान्य करने के नियम के समान है।
std::vector<int> v{ 1, 2, 3 };
int* p = v.data() + 1; // p points to 2
v.insert(v.begin(), 0); // p is now invalid, accessing *p is a undefined behavior.
p = v.data() + 1; // p points to 1
v.reserve(10); // p is now invalid, accessing *p is a undefined behavior.
p = v.data() + 1; // p points to 1
v.erase(v.begin()); // p is now invalid, accessing *p is a undefined behavior.
Std का उपयोग करना :: C सरणी के रूप में वेक्टर
एक std::vector
का उपयोग करने के कई तरीके हैं std::vector
एक C सरणी के रूप में (उदाहरण के लिए, C पुस्तकालयों के साथ संगतता के लिए)। यह संभव है क्योंकि वेक्टर में तत्व संचित रूप से संग्रहीत होते हैं।
std::vector<int> v{ 1, 2, 3 };
int* p = v.data();
पिछले C ++ मानकों (नीचे देखें) पर आधारित समाधानों के विपरीत, सदस्य फ़ंक्शन .data()
को खाली वैक्टर पर भी लागू किया जा सकता है, क्योंकि यह इस मामले में अपरिभाषित व्यवहार का कारण नहीं बनता है।
C ++ 11 से पहले, आप वेक्टर के पहले तत्व का पता एक समतुल्य सूचक प्राप्त करने के लिए लेंगे, यदि वेक्टर खाली नहीं है, तो ये दोनों विधियाँ विनिमेय हैं:
int* p = &v[0]; // combine subscript operator and 0 literal
int* p = &v.front(); // explicitly reference the first element
नोट: यदि वेक्टर खाली है, तो v[0]
और v.front()
अपरिभाषित हैं और उनका उपयोग नहीं किया जा सकता है।
वेक्टर के डेटा के आधार पते को संग्रहीत करते समय, ध्यान दें कि कई ऑपरेशन (जैसे push_back
, resize
, आदि) वेक्टर के डेटा मेमोरी स्थान को बदल सकते हैं, इस प्रकार पिछले डेटा पॉइंटर्स को अमान्य कर सकते हैं । उदाहरण के लिए:
std::vector<int> v;
int* p = v.data();
v.resize(42); // internal memory location changed; value of p is now invalid
Iterator / सूचक अमान्य
Iterators और संकेत एक std::vector
में इंगित करते हैं std::vector
अमान्य हो सकता है, लेकिन केवल जब कुछ संचालन करते हैं। अमान्य पुनरावृत्तियों / पॉइंटर्स का उपयोग करने से अपरिभाषित व्यवहार होगा।
संचालन जो पुनरावृत्तियों / संकेत को अमान्य करते हैं, उनमें शामिल हैं:
vector
केcapacity
को बदलने वाला कोई भी सम्मिलन ऑपरेशन सभी पुनरावृत्तियों / संकेत को अमान्य कर देगा:vector<int> v(5); // Vector has a size of 5; capacity is unknown. int *p1 = &v[0]; v.push_back(2); // p1 may have been invalidated, since the capacity was unknown. v.reserve(20); // Capacity is now at least 20. int *p2 = &v[0]; v.push_back(4); // p2 is *not* invalidated, since the size of `v` is now 7. v.insert(v.end(), 30, 9); // Inserts 30 elements at the end. The size exceeds the // requested capacity of 20, so `p2` is (probably) invalidated. int *p3 = &v[0]; v.reserve(v.capacity() + 20); // Capacity exceeded, thus `p3` is invalid.
auto old_cap = v.capacity();
v.shrink_to_fit();
if(old_cap != v.capacity())
// Iterators were invalidated.
कोई भी सम्मिलन ऑपरेशन, जो क्षमता में वृद्धि नहीं करता है, फिर भी पुनरावृत्ति स्थिति में तत्वों की ओर इशारा करते हुए पुनरावृत्तियों / बिंदुओं को अमान्य कर देगा और इसे पिछले कर देगा। इसमें
end
पुनरावृत्ति शामिल है:vector<int> v(5); v.reserve(20); // Capacity is at least 20. int *p1 = &v[0]; int *p2 = &v[3]; v.insert(v.begin() + 2, 5, 0); // `p2` is invalidated, but since the capacity // did not change, `p1` remains valid. int *p3 = &v[v.size() - 1]; v.push_back(10); // The capacity did not change, so `p3` and `p1` remain valid.
कोई भी निष्कासन कार्रवाई हटाए गए तत्वों की ओर इशारा करते हुए पुनरावृत्तियों / सूचक को हटा देगा और हटाए गए तत्वों के किसी भी तत्व को इंगित करेगा। इसमें
end
पुनरावृत्ति शामिल है:vector<int> v(10); int *p1 = &v[0]; int *p2 = &v[5]; v.erase(v.begin() + 3, v.end()); // `p2` is invalid, but `p1` remains valid.
operator=
(प्रतिलिपि, चाल, या अन्यथा) औरclear()
वेक्टर में इंगित सभी पुनरावृत्तियों / बिंदुओं को अमान्य कर देगा।
तत्वों को हटाना
अंतिम तत्व हटाना:
std::vector<int> v{ 1, 2, 3 };
v.pop_back(); // v becomes {1, 2}
सभी तत्वों को हटाना:
std::vector<int> v{ 1, 2, 3 };
v.clear(); // v becomes an empty vector
सूचकांक द्वारा तत्व हटाना:
std::vector<int> v{ 1, 2, 3, 4, 5, 6 };
v.erase(v.begin() + 3); // v becomes {1, 2, 3, 5, 6}
नोट: एक vector
को हटाने के लिए एक तत्व जो अंतिम तत्व नहीं है, हटाए गए तत्व से परे सभी तत्वों को अंतर को भरने के लिए कॉपी या स्थानांतरित किया जाना है, नीचे दिए गए नोट और std :: सूची देखें ।
सभी तत्वों को एक सीमा में हटाना:
std::vector<int> v{ 1, 2, 3, 4, 5, 6 };
v.erase(v.begin() + 1, v.begin() + 5); // v becomes {1, 6}
नोट: उपरोक्त विधियाँ वेक्टर की क्षमता को नहीं बदलती हैं, केवल आकार। वेक्टर आकार और क्षमता देखें।
erase
विधि, जो तत्वों की एक सीमा को हटाती है, अक्सर मिटाने-हटाने के मुहावरे के एक भाग के रूप में उपयोग की जाती है। यही है, पहले std::remove
वेक्टर के अंत में, और उसके बाद करने के लिए कुछ तत्वों को ले जाता है erase
चॉप उन्हें बंद। यह वेक्टर के अंतिम सूचकांक से कम किसी भी सूचकांक के लिए एक अपेक्षाकृत अक्षम ऑपरेशन है क्योंकि मिटाए गए खंडों के बाद सभी तत्वों को नए पदों पर स्थानांतरित किया जाना चाहिए। गति महत्वपूर्ण अनुप्रयोगों के लिए एक कंटेनर में मनमाने ढंग से तत्वों के कुशल निष्कासन की आवश्यकता होती है, std :: सूची देखें ।
तत्वों को मूल्य से हटाना:
std::vector<int> v{ 1, 1, 2, 2, 3, 3 };
int value_to_remove = 2;
v.erase(std::remove(v.begin(), v.end(), value_to_remove), v.end()); // v becomes {1, 1, 3, 3}
तत्वों को स्थिति से हटाना:
// std::remove_if needs a function, that takes a vector element as argument and returns true,
// if the element shall be removed
bool _predicate(const int& element) {
return (element > 3); // This will cause all elements to be deleted that are larger than 3
}
...
std::vector<int> v{ 1, 2, 3, 4, 5, 6 };
v.erase(std::remove_if(v.begin(), v.end(), _predicate), v.end()); // v becomes {1, 2, 3}
अतिरिक्त विधेय समारोह बनाए बिना, लंबोदर द्वारा तत्वों को हटाना
std::vector<int> v{ 1, 2, 3, 4, 5, 6 };
v.erase(std::remove_if(v.begin(), v.end(),
[](auto& element){return element > 3;} ), v.end()
);
एक लूप से स्थिति द्वारा तत्वों को हटाना:
std::vector<int> v{ 1, 2, 3, 4, 5, 6 };
std::vector<int>::iterator it = v.begin();
while (it != v.end()) {
if (condition)
it = v.erase(it); // after erasing, 'it' will be set to the next element in v
else
++it; // manually set 'it' to the next element in v
}
हालांकि यह एक विलोपन के मामले में it
नहीं बढ़ाना महत्वपूर्ण है, आपको एक अलग विधि का उपयोग करने पर विचार करना चाहिए जब एक लूप में बार-बार मिटा रहा हो। अधिक कुशल तरीके के लिए remove_if
पर विचार करें।
रिवर्स लूप से स्थिति से तत्वों को हटाना:
std::vector<int> v{ -1, 0, 1, 2, 3, 4, 5, 6 };
typedef std::vector<int>::reverse_iterator rev_itr;
rev_itr it = v.rbegin();
while (it != v.rend()) { // after the loop only '0' will be in v
int value = *it;
if (value) {
++it;
// See explanation below for the following line.
it = rev_itr(v.erase(it.base()));
} else
++it;
}
पूर्ववर्ती लूप के लिए कुछ बिंदुओं पर ध्यान दें:
एक रिवर्स इटरेटर को देखते हुए
it
कुछ तत्व की ओर इशारा करते, विधिbase
नियमित (गैर रिवर्स) इटरेटर एक ही तत्व की ओर इशारा करते देता है।vector::erase(iterator)
एक इट्रेटर द्वारा इंगित किए गए तत्व को मिटा देता है, और दिए गए तत्व का अनुसरण करने वाले तत्व को एक इटरेटर लौटाता है।reverse_iterator::reverse_iterator(iterator)
एक पुनरावृत्त से एक पुनरावृत्ती का निर्माण करता है।
पूरी तरह से it = rev_itr(v.erase(it.base()))
, तो it = rev_itr(v.erase(it.base()))
लाइन it = rev_itr(v.erase(it.base()))
कहती है: रिवर्स इटरेटर it
ले लो, v
को इसके रेगुलर इटरेटर द्वारा it = rev_itr(v.erase(it.base()))
गए तत्व को मिटा दें; जिसके परिणामस्वरूप इटरेटर लेते हैं, इसमें से एक रिवर्स इटरेटर का निर्माण, और के लिए असाइन करें इटरेटर रिवर्स it
।
v.clear()
का उपयोग कर सभी तत्वों को हटाने से वेक्टर की मेमोरी ( capacity()
अपरिवर्तित नहीं रहती है। स्थान को पुनः प्राप्त करने के लिए, उपयोग करें:
std::vector<int>().swap(v);
shrink_to_fit()
अप्रयुक्त वेक्टर क्षमता को मुक्त करता है:
v.shrink_to_fit();
shrink_to_fit
वास्तव में स्थान को पुनः प्राप्त करने की गारंटी नहीं देता है, लेकिन अधिकांश वर्तमान कार्यान्वयन करते हैं।
एसटीडी में एक तत्व ढूँढना :: वेक्टर
फ़ंक्शन std::find
, <algorithm>
हेडर में परिभाषित किया गया है, इसका उपयोग std::vector
में एक तत्व को खोजने के लिए किया जा सकता है।
समानता के लिए तत्वों की तुलना करने के लिए std::find
operator==
का उपयोग करता है। यह मूल्य के बराबर की सीमा में पहले तत्व के लिए एक पुनरावृत्ति देता है।
यदि विचाराधीन तत्व नहीं मिला है, तो std::find
रिटर्न रिटर्न std::vector::end
(या std::vector::cend
अगर वेक्टर const
)।
static const int arr[] = {5, 4, 3, 2, 1};
std::vector<int> v (arr, arr + sizeof(arr) / sizeof(arr[0]) );
std::vector<int>::iterator it = std::find(v.begin(), v.end(), 4);
std::vector<int>::difference_type index = std::distance(v.begin(), it);
// `it` points to the second element of the vector, `index` is 1
std::vector<int>::iterator missing = std::find(v.begin(), v.end(), 10);
std::vector<int>::difference_type index_missing = std::distance(v.begin(), missing);
// `missing` is v.end(), `index_missing` is 5 (ie. size of the vector)
std::vector<int> v { 5, 4, 3, 2, 1 };
auto it = std::find(v.begin(), v.end(), 4);
auto index = std::distance(v.begin(), it);
// `it` points to the second element of the vector, `index` is 1
auto missing = std::find(v.begin(), v.end(), 10);
auto index_missing = std::distance(v.begin(), missing);
// `missing` is v.end(), `index_missing` is 5 (ie. size of the vector)
यदि आपको एक बड़े वेक्टर में कई खोज करने की आवश्यकता है, तो आप पहले binary_search
एल्गोरिथ्म का उपयोग करने से पहले वेक्टर को क्रमबद्ध करने पर विचार कर सकते हैं।
वेक्टर में पहला तत्व खोजने के लिए जो किसी स्थिति को संतुष्ट करता है, std::find_if
का उपयोग किया जा सकता है। std::find
, std::find_if
को दिए गए दो मापदंडों के अलावा, एक तीसरा तर्क स्वीकार करता है जो कि एक कार्य वस्तु या फ़ंक्शन सूचक है जो एक समर्पित फ़ंक्शन के लिए है। विधेय को कंटेनर से एक तत्व को एक तर्क के रूप में स्वीकार करना चाहिए और कंटेनर को संशोधित किए बिना, एक मान को bool
वापस करना चाहिए:
bool isEven(int val) {
return (val % 2 == 0);
}
struct moreThan {
moreThan(int limit) : _limit(limit) {}
bool operator()(int val) {
return val > _limit;
}
int _limit;
};
static const int arr[] = {1, 3, 7, 8};
std::vector<int> v (arr, arr + sizeof(arr) / sizeof(arr[0]) );
std::vector<int>::iterator it = std::find_if(v.begin(), v.end(), isEven);
// `it` points to 8, the first even element
std::vector<int>::iterator missing = std::find_if(v.begin(), v.end(), moreThan(10));
// `missing` is v.end(), as no element is greater than 10
// find the first value that is even
std::vector<int> v = {1, 3, 7, 8};
auto it = std::find_if(v.begin(), v.end(), [](int val){return val % 2 == 0;});
// `it` points to 8, the first even element
auto missing = std::find_if(v.begin(), v.end(), [](int val){return val > 10;});
// `missing` is v.end(), as no element is greater than 10
एक सरणी को std में बदलना :: वेक्टर
एक सरणी को आसानी से एक std::vector
में परिवर्तित किया जा सकता है std::vector
का उपयोग करके std::begin
और std::end
:
int values[5] = { 1, 2, 3, 4, 5 }; // source array
std::vector<int> v(std::begin(values), std::end(values)); // copy array to new vector
for(auto &x: v)
std::cout << x << " ";
std::cout << std::endl;
1 2 3 4 5
int main(int argc, char* argv[]) {
// convert main arguments into a vector of strings.
std::vector<std::string> args(argv, argv + argc);
}
एक बार में वेक्टर को आरंभ करने के लिए C ++ 11 initializer_list <> का भी उपयोग किया जा सकता है
initializer_list<int> arr = { 1,2,3,4,5 };
vector<int> vec1 {arr};
for (auto & i : vec1)
cout << i << endl;
वेक्टर : अपवाद इतने सारे, इतने सारे नियम
मानक (खंड 23.3.7) निर्दिष्ट करता है कि vector<bool>
का एक विशेषज्ञता प्रदान किया जाता है, जो bool
मूल्यों को पैक करके अंतरिक्ष का अनुकूलन करता है, ताकि प्रत्येक केवल एक बिट लेता है। चूंकि बिट्स C ++ में पता करने योग्य नहीं हैं, इसका मतलब है कि vector
पर कई आवश्यकताओं को vector<bool>
पर नहीं रखा गया है:
- संग्रहीत डेटा को सन्निहित होने की आवश्यकता नहीं है, इसलिए एक
vector<bool>
को C API से पारित नहीं किया जा सकता है जो एकbool
सरणी की अपेक्षा करता है। -
at()
,operator []
, और पुनरावृत्तियों की डीफ़रलाइनिंगbool
संदर्भ में वापस नहीं आती है। बल्कि वे एक छद्म वस्तु लौटाते हैं जो (अपूर्ण रूप से) अपने असाइनमेंट ऑपरेटरों को ओवरलोड करके एकbool
संदर्भ का अनुकरण करती है। एक उदाहरण के रूप में, निम्नलिखित कोडstd::vector<bool>
लिए मान्य नहीं हो सकता है, क्योंकि एक पुनरावृत्ति को संदर्भित करने वाला संदर्भ संदर्भित नहीं करता है:
std::vector<bool> v = {true, false};
for (auto &b: v) { } // error
इसी प्रकार, bool&
तर्क की अपेक्षा करने वाले कार्यों का उपयोग operator []
के परिणाम के साथ नहीं किया जा सकता है operator []
या at()
vector<bool>
लागू होता है, या इसके पुनरावृत्ति के परिणाम के साथ:
void f(bool& b);
f(v[0]); // error
f(*v.begin()); // error
std::vector<bool>
का कार्यान्वयन संकलक और वास्तुकला दोनों पर निर्भर है। स्मृति के सबसे कम पते योग्य अनुभाग में n
बुलियन को पैक करके विशेषज्ञता को लागू किया जाता है। यहाँ, n
सबसे कम पता योग्य मेमोरी के बिट्स में आकार है। अधिकांश आधुनिक प्रणालियों में यह 1 बाइट या 8 बिट्स है। इसका मतलब यह है कि एक बाइट 8 बुलियन मूल्यों को संग्रहीत कर सकता है। यह पारंपरिक कार्यान्वयन पर एक सुधार है जहां 1 बूलियन मान 1 बाइट मेमोरी में संग्रहीत होता है।
नोट: नीचे का उदाहरण पारंपरिक बनाम अनुकूलित vector<bool>
में व्यक्तिगत बाइट्स के संभावित बिटवाइस मान दिखाता है। यह सभी वास्तुशिल्प में हमेशा सही नहीं होगा। हालांकि, यह अनुकूलन का अनुमान लगाने का एक अच्छा तरीका है। नीचे दिए गए उदाहरणों में एक बाइट को [x, x, x, x, x, x, x] के रूप में दर्शाया गया है।
पारंपरिक std::vector<char>
8 बूलियन मान संग्रहीत करना:
std::vector<char> trad_vect = {true, false, false, false, true, false, true, true};
बिटवाइज़ प्रतिनिधित्व:
[0,0,0,0,0,0,0,1], [0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,1], [0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1], [0,0,0,0,0,0,0,1]
विशिष्ट std::vector<bool>
भंडारण 8 बूलियन मान:
std::vector<bool> optimized_vect = {true, false, false, false, true, false, true, true};
बिटवाइज़ प्रतिनिधित्व:
[1,0,0,0,1,0,1,1]
उपरोक्त उदाहरण में ध्यान दें, कि std::vector<bool>
के पारंपरिक संस्करण में std::vector<bool>
, 8 बूलियन मान स्मृति के 8 बाइट्स लेते हैं, जबकि std::vector<bool>
के अनुकूलित संस्करण में std::vector<bool>
, वे केवल 1 बाइट का उपयोग करते हैं स्मृति। यह स्मृति उपयोग पर एक महत्वपूर्ण सुधार है। यदि आपको C- शैली API में vector<bool>
पास करने की आवश्यकता है, तो आपको किसी सरणी में मान कॉपी करने की आवश्यकता हो सकती है, या API का उपयोग करने का एक बेहतर तरीका मिल सकता है, यदि स्मृति और प्रदर्शन जोखिम में हैं।
वेक्टर का आकार और क्षमता
वेक्टर का आकार बस वेक्टर में तत्वों की संख्या है:
वर्तमान वेक्टर आकार
size()
सदस्य फ़ंक्शन द्वारा क्वियर किया गया है। सुविधाempty()
फ़ंक्शनtrue
अगर आकार 0 है:vector<int> v = { 1, 2, 3 }; // size is 3 const vector<int>::size_type size = v.size(); cout << size << endl; // prints 3 cout << boolalpha << v.empty() << endl; // prints false
डिफ़ॉल्ट निर्माण वेक्टर 0 के आकार के साथ शुरू होता है:
vector<int> v; // size is 0 cout << v.size() << endl; // prints 0
वेक्टर में
N
तत्वों को जोड़ने सेN
(जैसेpush_back()
,insert()
याresize()
फ़ंक्शन) द्वारा आकार बढ़ता है।वेक्टर से
N
तत्वों को हटाने सेN
(जैसेpop_back()
,pop_back()
erase()
याclear()
फ़ंक्शन द्वारा आकार घटता है।वेक्टर में इसके आकार पर एक कार्यान्वयन-विशिष्ट ऊपरी सीमा होती है, लेकिन आपके पहुंचने से पहले रैम से बाहर चलने की संभावना है:
vector<int> v; const vector<int>::size_type max_size = v.max_size(); cout << max_size << endl; // prints some large number v.resize( max_size ); // probably won't work v.push_back( 1 ); // definitely won't work
सामान्य गलती: आकार आवश्यक नहीं है (या आमतौर पर भी) int
:
// !!!bad!!!evil!!!
vector<int> v_bad( N, 1 ); // constructs large N size vector
for( int i = 0; i < v_bad.size(); ++i ) { // size is not supposed to be int!
do_something( v_bad[i] );
}
वेक्टर क्षमता आकार से भिन्न होती है। जबकि आकार बस वेक्टर के कितने तत्व हैं, क्षमता यह है कि कितने तत्वों के लिए यह आवंटित / आरक्षित मेमोरी के लिए है। यह उपयोगी है, क्योंकि बहुत बड़े आकार के अक्सर (पुनः) आवंटन महंगे हो सकते हैं।
वर्तमान वेक्टर क्षमता
capacity()
सदस्य फ़ंक्शन द्वारा क्वेरी की गईcapacity()
। क्षमता हमेशा आकार से अधिक या बराबर होती है :vector<int> v = { 1, 2, 3 }; // size is 3, capacity is >= 3 const vector<int>::size_type capacity = v.capacity(); cout << capacity << endl; // prints number >= 3
आप मैन्युअल रूप से
reserve( N )
फ़ंक्शन द्वारा क्षमता आरक्षित कर सकते हैं (यह वेक्टर क्षमता कोN
बदलता है):// !!!bad!!!evil!!! vector<int> v_bad; for( int i = 0; i < 10000; ++i ) { v_bad.push_back( i ); // possibly lot of reallocations } // good vector<int> v_good; v_good.reserve( 10000 ); // good! only one allocation for( int i = 0; i < 10000; ++i ) { v_good.push_back( i ); // no allocations needed anymore }
आप
shrink_to_fit()
द्वारा जारी की जाने वाली अतिरिक्त क्षमता के लिए अनुरोध कर सकते हैं (लेकिन क्रियान्वयन का आपको पालन करने की आवश्यकता नहीं है)। यह उपयोग की गई स्मृति के संरक्षण के लिए उपयोगी है:vector<int> v = { 1, 2, 3, 4, 5 }; // size is 5, assume capacity is 6 v.shrink_to_fit(); // capacity is 5 (or possibly still 6) cout << boolalpha << v.capacity() == v.size() << endl; // prints likely true (but possibly false)
वेक्टर आंशिक रूप से क्षमता का प्रबंधन करता है, जब आप तत्वों को जोड़ते हैं तो यह बढ़ने का फैसला कर सकता है। बढ़ने वाले कारक के लिए 2 या 1.5 का उपयोग करना पसंद करते हैं (सुनहरा अनुपात आदर्श मूल्य होगा - लेकिन तर्कसंगत संख्या होने के कारण अव्यावहारिक है)। दूसरी ओर वेक्टर आमतौर पर स्वचालित रूप से सिकुड़ता नहीं है। उदाहरण के लिए:
vector<int> v; // capacity is possibly (but not guaranteed) to be 0
v.push_back( 1 ); // capacity is some starter value, likely 1
v.clear(); // size is 0 but capacity is still same as before!
v = { 1, 2, 3, 4 }; // size is 4, and lets assume capacity is 4.
v.push_back( 5 ); // capacity grows - let's assume it grows to 6 (1.5 factor)
v.push_back( 6 ); // no change in capacity
v.push_back( 7 ); // capacity grows - let's assume it grows to 9 (1.5 factor)
// and so on
v.pop_back(); v.pop_back(); v.pop_back(); v.pop_back(); // capacity stays the same
संबंधित क्षेत्र
एक std::vector
सदस्य फ़ंक्शन insert()
का उपयोग करके दूसरे के लिए संलग्न किया जा सकता है:
std::vector<int> a = {0, 1, 2, 3, 4};
std::vector<int> b = {5, 6, 7, 8, 9};
a.insert(a.end(), b.begin(), b.end());
हालाँकि, यह समाधान विफल हो जाता है यदि आप अपने आप को वेक्टर को जोड़ने की कोशिश करते हैं, क्योंकि मानक निर्दिष्ट करता है कि insert()
लिए दिए गए पुनरावृत्त insert()
रिसीवर ऑब्जेक्ट के तत्वों के समान सीमा से नहीं होने चाहिए।
वेक्टर के सदस्य कार्यों का उपयोग करने के बजाय, कार्य std::begin()
और std::end()
का उपयोग किया जा सकता है:
a.insert(std::end(a), std::begin(b), std::end(b));
यह एक अधिक सामान्य समाधान है, उदाहरण के लिए, क्योंकि b
भी एक सरणी हो सकता है। हालाँकि, यह समाधान भी आपको अपने आप को एक वेक्टर जोड़ने की अनुमति नहीं देता है।
यदि प्राप्त वेक्टर में तत्वों का क्रम मायने नहीं रखता है, तो प्रत्येक वेक्टर में तत्वों की संख्या को देखते हुए अनावश्यक प्रतिलिपि संचालन से बचा जा सकता है:
if (b.size() < a.size())
a.insert(a.end(), b.begin(), b.end());
else
b.insert(b.end(), a.begin(), a.end());
एक वेक्टर की क्षमता को कम करना
एक std::vector
स्वचालित रूप से आवश्यकतानुसार अपनी क्षमता बढ़ाता है, लेकिन यह तत्व निकालने के बाद अपनी क्षमता को कभी कम नहीं करता है।
// Initialize a vector with 100 elements
std::vector<int> v(100);
// The vector's capacity is always at least as large as its size
auto const old_capacity = v.capacity();
// old_capacity >= 100
// Remove half of the elements
v.erase(v.begin() + 50, v.end()); // Reduces the size from 100 to 50 (v.size() == 50),
// but not the capacity (v.capacity() == old_capacity)
इसकी क्षमता को कम करने के लिए, हम एक वेक्टर की सामग्री को एक नए अस्थायी वेक्टर में कॉपी कर सकते हैं। नए वेक्टर में न्यूनतम क्षमता होगी जो मूल वेक्टर के सभी तत्वों को संग्रहीत करने के लिए आवश्यक है। यदि मूल सदिश की आकार में कमी महत्वपूर्ण थी, तो नए वेक्टर के लिए क्षमता में कमी महत्वपूर्ण है। फिर हम अपनी न्यूनतम क्षमता को बनाए रखने के लिए मूल वेक्टर को अस्थायी रूप से स्वैप कर सकते हैं:
std::vector<int>(v).swap(v);
C ++ 11 में हम एक समान प्रभाव के लिए shrink_to_fit()
सदस्य फ़ंक्शन का उपयोग कर सकते हैं:
v.shrink_to_fit();
नोट: shrink_to_fit()
सदस्य फ़ंक्शन एक अनुरोध है और क्षमता को कम करने की गारंटी नहीं देता है।
फास्ट तत्व लुकअप के लिए एक सॉर्ट किए गए वेक्टर का उपयोग करना
<algorithm>
हेडर सॉर्ट किए गए वैक्टर के साथ काम करने के लिए कई उपयोगी कार्य प्रदान करता है।
क्रमबद्ध वैक्टर के साथ काम करने के लिए एक महत्वपूर्ण शर्त यह है कि संग्रहीत मान <
साथ तुलनीय हैं।
फंक्शन std::sort()
का उपयोग करके एक अनियोजित वेक्टर को सॉर्ट किया जा सकता है:
std::vector<int> v;
// add some code here to fill v with some elements
std::sort(v.begin(), v.end());
सॉर्ट किए गए वैक्टर फ़ंक्शन std::lower_bound()
का उपयोग करके कुशल तत्व लुकअप की अनुमति देते हैं। std::find()
विपरीत, यह वेक्टर पर एक कुशल बाइनरी खोज करता है। नकारात्मक पक्ष यह है कि यह केवल हल किए गए इनपुट सीमाओं के लिए मान्य परिणाम देता है:
// search the vector for the first element with value 42
std::vector<int>::iterator it = std::lower_bound(v.begin(), v.end(), 42);
if (it != v.end() && *it == 42) {
// we found the element!
}
नोट: यदि अनुरोधित मूल्य वेक्टर का हिस्सा नहीं है, तो std::lower_bound()
पहले तत्व के लिए एक पुनरावर्तक लौटाएगा जो अनुरोधित मूल्य से अधिक है। यह व्यवहार हमें पहले से ही हल किए गए वेक्टर में अपने नए स्थान पर एक नया तत्व सम्मिलित करने की अनुमति देता है:
int const new_element = 33;
v.insert(std::lower_bound(v.begin(), v.end(), new_element), new_element);
यदि आपको एक बार में बहुत सारे तत्वों को सम्मिलित करने की आवश्यकता है, तो पहले उन सभी के लिए push_back()
कॉल करना अधिक कुशल हो सकता है और फिर सभी तत्वों को सम्मिलित करने के लिए std::sort()
कॉल करें। इस मामले में, छंटाई की बढ़ी हुई लागत वेक्टर के अंत में नए तत्वों को डालने की कम लागत के खिलाफ भुगतान कर सकती है और बीच में नहीं।
यदि आपके वेक्टर में समान मान के कई तत्व हैं, तो खोज किए गए मान के पहले तत्व में std::lower_bound()
को वापस करने का प्रयास करेगा। हालांकि, यदि आपको खोज किए गए मान के अंतिम तत्व के बाद एक नया तत्व सम्मिलित करने की आवश्यकता है, तो आपको फ़ंक्शन std::upper_bound()
उपयोग करना चाहिए क्योंकि इससे तत्वों की कम शिफ्टिंग हो जाएगी:
v.insert(std::upper_bound(v.begin(), v.end(), new_element), new_element);
यदि आपको ऊपरी बाउंड और लोअर बाउंड iterators दोनों की आवश्यकता है, तो आप दोनों को एक कॉल के साथ कुशलतापूर्वक प्राप्त करने के लिए फ़ंक्शन std::equal_range()
का उपयोग कर सकते हैं:
std::pair<std::vector<int>::iterator,
std::vector<int>::iterator> rg = std::equal_range(v.begin(), v.end(), 42);
std::vector<int>::iterator lower_bound = rg.first;
std::vector<int>::iterator upper_bound = rg.second;
यह जांचने के लिए कि क्या कोई तत्व सॉर्ट किए गए वेक्टर (हालांकि वैक्टर के लिए विशिष्ट नहीं है) में मौजूद है, आप फ़ंक्शन std::binary_search()
उपयोग कर सकते हैं:
bool exists = std::binary_search(v.begin(), v.end(), value_to_find);
बड़े क्षेत्र लौटते हुए कार्य
C ++ 11 में, कंपाइलरों को स्थानीय चर से वापस ले जाने के लिए आवश्यक है। इसके अलावा, अधिकांश कंपाइलर कई मामलों में कॉपी एलीशन कर सकते हैं और पूरी तरह से स्थानांतरित कर सकते हैं। इस के परिणामस्वरूप, बड़ी वस्तुओं को लौटाया जा सकता है जिन्हें सस्ते में ले जाया जा सकता है, अब विशेष हैंडलिंग की आवश्यकता नहीं है:
#include <vector>
#include <iostream>
// If the compiler is unable to perform named return value optimization (NRVO)
// and elide the move altogether, it is required to move from v into the return value.
std::vector<int> fillVector(int a, int b) {
std::vector<int> v;
v.reserve(b-a+1);
for (int i = a; i <= b; i++) {
v.push_back(i);
}
return v; // implicit move
}
int main() { // declare and fill vector
std::vector<int> vec = fillVector(1, 10);
// print vector
for (auto value : vec)
std::cout << value << " "; // this will print "1 2 3 4 5 6 7 8 9 10 "
std::cout << std::endl;
return 0;
}
C ++ 11 से पहले, प्रतिलिपि संलयन की अनुमति पहले से ही थी और अधिकांश संकलक द्वारा लागू की गई थी। हालाँकि, लेग सेमेन्टिक्स की अनुपस्थिति के कारण, विरासत कोड या कोड में, जो पुराने संकलक संस्करणों के साथ संकलित किया जाना है, जो इस अनुकूलन को लागू नहीं करते हैं, आप अनावश्यक कॉपी को रोकने के लिए वैक्टर को आउटपुट तर्कों के रूप में पारित कर सकते हैं:
#include <vector>
#include <iostream>
// passing a std::vector by reference
void fillVectorFrom_By_Ref(int a, int b, std::vector<int> &v) {
assert(v.empty());
v.reserve(b-a+1);
for (int i = a; i <= b; i++) {
v.push_back(i);
}
}
int main() {// declare vector
std::vector<int> vec;
// fill vector
fillVectorFrom_By_Ref(1, 10, vec);
// print vector
for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
std::cout << *it << " "; // this will print "1 2 3 4 5 6 7 8 9 10 "
std::cout << std::endl;
return 0;
}
एक वेक्टर में अधिकतम और न्यूनतम तत्व और प्रतिक्रियाशील सूचकांक खोजें
वेक्टर में संग्रहीत सबसे बड़े या सबसे छोटे तत्व को खोजने के लिए, आप क्रमशः std::max_element
और std::min_element
विधियों का उपयोग कर सकते हैं। इन तरीकों को <algorithm>
हेडर में परिभाषित किया गया है। यदि कई तत्व सबसे बड़े (सबसे छोटे) तत्व के समतुल्य हैं, तो विधियाँ पहले ऐसे तत्व को पुनरावृत्त लौटाती हैं। खाली वैक्टर के लिए v.end()
लौटें।
std::vector<int> v = {5, 2, 8, 10, 9};
int maxElementIndex = std::max_element(v.begin(),v.end()) - v.begin();
int maxElement = *std::max_element(v.begin(), v.end());
int minElementIndex = std::min_element(v.begin(),v.end()) - v.begin();
int minElement = *std::min_element(v.begin(), v.end());
std::cout << "maxElementIndex:" << maxElementIndex << ", maxElement:" << maxElement << '\n';
std::cout << "minElementIndex:" << minElementIndex << ", minElement:" << minElement << '\n';
आउटपुट:
maxElementIndex: 3, maxElement: 10
minElementIndex: 1, minElement: 2
वेक्टर में न्यूनतम और अधिकतम तत्व एक ही समय में विधि std::minmax_element
का उपयोग करके प्राप्त किया जा सकता है, जिसे <algorithm>
हेडर में भी परिभाषित किया गया है:
std::vector<int> v = {5, 2, 8, 10, 9};
auto minmax = std::minmax_element(v.begin(), v.end());
std::cout << "minimum element: " << *minmax.first << '\n';
std::cout << "maximum element: " << *minmax.second << '\n';
आउटपुट:
न्यूनतम तत्व: 2
अधिकतम तत्व: 10
वैक्टर का उपयोग कर मैट्रिसेस
वैक्टर को वेक्टर के रूप में परिभाषित करके 2 डी मैट्रिक्स के रूप में इस्तेमाल किया जा सकता है।
0 के रूप में परिभाषित प्रत्येक सेल के साथ 3 पंक्तियों और 4 स्तंभों के साथ एक मैट्रिक्स के रूप में परिभाषित किया जा सकता है:
std::vector<std::vector<int> > matrix(3, std::vector<int>(4));
आरंभिक सूचियों का उपयोग करके उन्हें आरंभ करने के लिए सिंटैक्स या सामान्य वेक्टर के समान है।
std::vector<std::vector<int>> matrix = { {0,1,2,3},
{4,5,6,7},
{8,9,10,11}
};
ऐसे वेक्टर में मानों को 2 डी सरणी के समान एक्सेस किया जा सकता है
int var = matrix[0][2];
पूरे मैट्रिक्स पर इरेटिंग एक सामान्य वेक्टर के समान है लेकिन एक अतिरिक्त आयाम के साथ।
for(int i = 0; i < 3; ++i)
{
for(int j = 0; j < 4; ++j)
{
std::cout << matrix[i][j] << std::endl;
}
}
for(auto& row: matrix)
{
for(auto& col : row)
{
std::cout << col << std::endl;
}
}
वेक्टर का एक वेक्टर मैट्रिक्स का प्रतिनिधित्व करने का एक सुविधाजनक तरीका है, लेकिन यह सबसे कुशल नहीं है: व्यक्तिगत वैक्टर स्मृति के आसपास बिखरे हुए हैं और डेटा संरचना कैश के अनुकूल नहीं है।
इसके अलावा, एक उचित मैट्रिक्स में, प्रत्येक पंक्ति की लंबाई समान होनी चाहिए (वैक्टर के वेक्टर के लिए ऐसा नहीं है)। अतिरिक्त लचीलापन त्रुटियों का स्रोत हो सकता है।