पुनरावृत्तियों का उपयोग करके वेक्टर के माध्यम से नेविगेट कैसे करें? (C ++)


105

लक्ष्य [] ऑपरेटर या "एट" विधि के बजाय स्ट्रिंग के एक वेक्टर के "एनटी" तत्व का उपयोग करना है। मैं जो समझता हूं, उससे पुनरावृत्तियों का उपयोग कंटेनरों के माध्यम से नेविगेट करने के लिए किया जा सकता है, लेकिन मैंने इससे पहले कभी भी पुनरावृत्तियों का उपयोग नहीं किया है, और जो मैं पढ़ रहा हूं वह भ्रामक है।

अगर कोई मुझे इस बारे में कुछ जानकारी दे सके कि इसे कैसे हासिल किया जाए, तो मैं इसकी सराहना करूंगा। धन्यवाद।


C ++ के STL के लिए वैक्टर नहीं हैं? मैं इसे परवाह किए बिना संपादित करूंगा
केविन

केविन: वेक्टर एक सामान्य शब्द है जिसका उपयोग किसी भी भाषा, विशेष रूप से गणित से संबंधित गणित या मैटलैब जैसे लोगों द्वारा किया जा सकता है।
गाबे

@michael, येह हाहा मैंने इसे gabe की टिप्पणी के बाद संपादित किया।
केविन

जवाबों:


112

आपको कक्षा के तरीके beginऔर endविधि का उपयोग करने की आवश्यकता है vector, जो क्रमशः पहले और अंतिम तत्व की चर्चा करते हुए पुनरावृत्त लौटाते हैं।

using namespace std;  

vector<string> myvector;  // a vector of stings.


// push some strings in the vector.
myvector.push_back("a");
myvector.push_back("b");
myvector.push_back("c");
myvector.push_back("d");


vector<string>::iterator it;  // declare an iterator to a vector of strings
int n = 3;  // nth element to be found.
int i = 0;  // counter.

// now start at from the beginning
// and keep iterating over the element till you find
// nth element...or reach the end of vector.
for(it = myvector.begin(); it != myvector.end(); it++,i++ )    {
    // found nth element..print and break.
    if(i == n) {
        cout<< *it << endl;  // prints d.
        break;
    }
}

// other easier ways of doing the same.
// using operator[]
cout<<myvector[n]<<endl;  // prints d.

// using the at method
cout << myvector.at(n) << endl;  // prints d.

5
यह इस तथ्य को याद करता है जिसमें std::vectorयादृच्छिक अभिगमकर्ता हैं।
sbi

24
भले ही आपको पता हो कि इट्रेटर टाइप रैंडम-ऐक्सेस है या नहीं, इट्रेटर को आगे बढ़ाने के लिए "बेस्ट" तरीका है एन स्पेस अपने लूप लिखने के लिए नहीं, बल्कि कॉल करने के लिए std::advance(it, n)। इसे ठीक उसी तरह से परिभाषित किया जाता है जैसा आप चाहते हैं, और यह स्वचालित रूप से उपयोग करेगा it + nयदि इट्रेटर को यादृच्छिक-अभिगम के रूप में टैग किया गया है, या यदि यह करना है तो लूप करें।
स्टीव जेसप

61

आमतौर पर, पुनरावृत्तियों का उपयोग रैखिक फैशन में एक कंटेनर के तत्वों तक पहुंचने के लिए किया जाता है; हालांकि, "यादृच्छिक अभिगम पुनरावृत्तियों" के साथ, किसी भी तत्व को उसी तरीके से एक्सेस करना संभव है जैसा कि operator[]

एक वेक्टर में मनमाने तत्वों तक पहुँचने के लिए vec, आप निम्नलिखित का उपयोग कर सकते हैं:

vec.begin()                  // 1st
vec.begin()+1                // 2nd
// ...
vec.begin()+(i-1)            // ith
// ...
vec.begin()+(vec.size()-1)   // last

निम्नलिखित एक विशिष्ट एक्सेस पैटर्न का एक उदाहरण है (C ++ के पुराने संस्करण):

int sum = 0;
using Iter = std::vector<int>::const_iterator;
for (Iter it = vec.begin(); it!=vec.end(); ++it) {
    sum += *it;
}

पुनरावृत्त का उपयोग करने का लाभ यह है कि आप अन्य कंटेनरों के साथ एक ही पैटर्न लागू कर सकते हैं :

sum = 0;
for (Iter it = lst.begin(); it!=lst.end(); ++it) {
    sum += *it;
}

इस कारण से, टेम्पलेट कोड बनाना वास्तव में आसान है जो कंटेनर प्रकार की परवाह किए बिना समान काम करेगा । पुनरावृत्तियों का एक और लाभ यह है कि यह डेटा को स्मृति में निवासी नहीं मानता है; उदाहरण के लिए, कोई एक आगे का इटरेटर बना सकता है जो इनपुट स्ट्रीम से डेटा पढ़ सकता है, या जो केवल फ्लाई पर डेटा उत्पन्न करता है (जैसे एक श्रेणी या यादृच्छिक संख्या जनरेटर)।

एक और विकल्प का उपयोग कर std::for_eachऔर लैम्ब्डा:

sum = 0;
std::for_each(vec.begin(), vec.end(), [&sum](int i) { sum += i; });

C ++ 11 के बाद से आप autoइट्रेटर के बहुत लंबे, जटिल प्रकार के नाम को निर्दिष्ट करने से बचने के लिए उपयोग कर सकते हैं जैसा कि पहले देखा गया है (या इससे भी अधिक जटिल):

sum = 0;
for (auto it = vec.begin(); it!=vec.end(); ++it) {
    sum += *it;
}

और, इसके अलावा, प्रत्येक संस्करण के लिए एक सरल है:

sum = 0;
for (auto value : vec) {
    sum += value;
}

और अंत में वहाँ भी है std::accumulateजहाँ आपको सावधान रहना होगा कि क्या आप पूर्णांक या फ्लोटिंग पॉइंट नंबर जोड़ रहे हैं।


53

C ++ - 11 में आप कर सकते हैं:

std::vector<int> v = {0, 1, 2, 3, 4, 5};
for (auto i : v)
{
   // access by value, the type of i is int
   std::cout << i << ' ';
}
std::cout << '\n';

विविधताओं के लिए यहां देखें: https://en.cppreference.com/w/cpp/language/range-for


4
क्यों यह शून्य जीवन है ?! <३
जंपर

3
@jperl ने 8 साल देर से पोस्ट किया। अगले 8 साल लगेंगे पर्याप्त
उठाव

@jperl, अच्छी तरह से जवाब ऑफ विषय है। यद्यपि यह लूप फीचर अच्छा है, लेकिन यह आपको यह जानने में मदद नहीं करता है कि आप nth एलिमेंट पर कब हैं, जो कि ओपी का प्रश्न है। इसके अलावा, किसी भी उत्तर के लिए ओ (एन) समय की जटिलता की आवश्यकता होती है, जैसे कि यह एक, बहुत खराब है। एक वेक्टर के nth तत्व तक पहुँचना हमेशा O (1) होना चाहिए।
इलियट

@ लैशगर मैंने इसे सरणी के साथ आज़माया लेकिन असफल रहा। यह सरणी के लिए काम करता है?
युग s eraq

@ eras'q, 7.5.0Ubuntu 18.04 पर gcc के साथ कोशिश की और उसी तरह सरणी के लिए काम करता है।
लैशगर

17

वेक्टर के पुनरावृत्तियाँ यादृच्छिक अभिगमकर्ता हैं, जिसका अर्थ है कि वे सादे बिंदुओं की तरह दिखते और महसूस करते हैं।

आप कंटेनर की begin()विधि से लौटाए गए पुनरावृत्त में n जोड़कर nth तत्व तक पहुँच सकते हैं , या आप ऑपरेटर का उपयोग कर सकते हैं []

std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();

int sixth = *(it + 5);
int third = *(2 + it);
int second = it[1];

वैकल्पिक रूप से आप अग्रिम फ़ंक्शन का उपयोग कर सकते हैं जो सभी प्रकार के पुनरावृत्तियों के साथ काम करता है। (आपको यह विचार करना होगा कि क्या आप वास्तव में गैर-यादृच्छिक-पहुंच वाले पुनरावृत्तियों के साथ "यादृच्छिक अभिगम" करना चाहते हैं, क्योंकि यह एक महंगी चीज हो सकती है।)

std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();

std::advance(it, 5);
int sixth = *it;

1
आप advanceयादृच्छिक-पहुँच पुनरावृत्तियों, या अज्ञात श्रेणी के पुनरावृत्तियों के लिए उपयोग कर सकते हैं , क्योंकि यह उस स्थिति में निरंतर समय में काम करने की गारंटी है। यही कारण है कि उपयोगकर्ता द्वारा परिभाषित पुनरावृत्तियों को सही ढंग से टैग किया जाना चाहिए।
स्टीव जेसप

वास्तव में, लेकिन advanceअगर आप जानते हैं कि आप रैंडम एक्सेस के साथ काम कर रहे हैं, तो इसका उपयोग करने के लिए वास्तव में कष्टप्रद है (आउट पैरामीटर उपयोग के कारण)। केवल सामान्य कोड में सिफारिश करेंगे, और यदि बहुत उपयोग नहीं किया जाता है (यदि एल्गोरिथ्म गैर-यादृच्छिक-पहुँच पुनरावृत्तियों का समर्थन नहीं करता है, तो ऐसा हो - उदाहरण के लिए, लेकिन इसे सॉर्ट std::sort कर सकता हैstd::list क्योंकि यह हास्यास्पद रूप से अक्षम होगा )।
अंकलबीन्स

निश्चित रूप से, क्लासिक उदाहरण यह होगा कि यदि आपके एल्गोरिथ्म को वास्तव में एक इनपुटइंटरेटर की आवश्यकता है , लेकिन जिस भी कारण से यह कभी-कभी आगे निकल जाता है, इसलिए आप चाहते हैं कि यदि इट्रेटर में रैंडम एक्सेस हो तो यह अधिक कुशल हो। यह केवल उपयोग करके अपने एल्गोरिथ्म को यादृच्छिक अभिगम तक सीमित रखने के लायक नहीं है operator+। लेकिन प्रश्न स्पष्ट रूप से वेक्टर के बारे में था, इसलिए आपके उत्तर के पहले भाग में कुछ भी गलत नहीं है। मैंने अभी सोचा कि दूसरा भाग "आप यादृच्छिक अभिगमकर्ताओं के साथ अग्रिम का उपयोग नहीं कर सकते हैं, भले ही आप उस व्यक्ति को" चाहते हैं जो पहले कभी नहीं देखा है advance
स्टीव जेसप

ठीक है, उस बिट को फिर से तैयार किया और एक वेक्टर के साथ उदाहरण दिया।
अंकल बीन्स

दूसरी पंक्ति, Vectorकम मामला होना चाहिए
लेई यांग

0

यहां एक लूप के भीतर का उपयोग करने के ithसूचकांक तक पहुंचने का एक उदाहरण है जिसमें दो पुनरावृत्तियों को बढ़ाने की आवश्यकता नहीं है।std::vectorstd::iterator

std::vector<std::string> strs = {"sigma" "alpha", "beta", "rho", "nova"};
int nth = 2;
std::vector<std::string>::iterator it;
for(it = strs.begin(); it != strs.end(); it++) {
    int ith = it - strs.begin();
    if(ith == nth) {
        printf("Iterator within  a for-loop: strs[%d] = %s\n", ith, (*it).c_str());
    }
}

बिना लूप के

it = strs.begin() + nth;
printf("Iterator without a for-loop: strs[%d] = %s\n", nth, (*it).c_str());

और atविधि का उपयोग कर :

printf("Using at position: strs[%d] = %s\n", nth, strs.at(nth).c_str());
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.