दो std का प्रतिच्छेदन कैसे खोजें :: C ++ में सेट करें?


93

मैं दो सेंट के बीच चौराहे को खोजने की कोशिश कर रहा हूँ :: C ++ में सेट, लेकिन मुझे एक त्रुटि मिलती है।

मैंने इसके लिए एक छोटा सा नमूना परीक्षण बनाया

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;

int main() {
  set<int> s1;
  set<int> s2;

  s1.insert(1);
  s1.insert(2);
  s1.insert(3);
  s1.insert(4);

  s2.insert(1);
  s2.insert(6);
  s2.insert(3);
  s2.insert(0);

  set_intersection(s1.begin(),s1.end(),s2.begin(),s2.end());
  return 0;
}

उत्तरार्द्ध कार्यक्रम कोई आउटपुट उत्पन्न नहीं करता है, लेकिन मुझे s3निम्नलिखित मूल्यों के साथ एक नया सेट (चलो इसे कॉल करें ) की उम्मीद है :

s3 = [ 1 , 3 ]

इसके बजाय मुझे त्रुटि मिल रही है:

test.cpp: In function ‘int main()’:
test.cpp:19: error: no matching function for call to ‘set_intersection(std::_Rb_tree_const_iterator<int>, std::_Rb_tree_const_iterator<int>, std::_Rb_tree_const_iterator<int>, std::_Rb_tree_const_iterator<int>)

इस त्रुटि के बारे में मुझे जो समझ है, वह यह है कि पैरामीटर के रूप में set_intersectionउस स्वीकार की कोई परिभाषा नहीं है Rb_tree_const_iterator<int>

इसके अलावा, मुझे लगता है कि std::set.begin()विधि इस तरह के एक वस्तु देता है,

क्या std::setC ++ में दो का प्रतिच्छेदन खोजने का एक बेहतर तरीका है ? अधिमानतः एक अंतर्निहित फ़ंक्शन?

आपका बहुत बहुत धन्यवाद!


"मुझे एक नया सेट मिलने की उम्मीद है (चलो इसे s3 कहते हैं)" लेकिन आप नहीं करते हैं, और आपने नहीं किया। मुझे समझ नहीं आ रहा है कि आपको परिणामों की उम्मीद कहां है। इसके अलावा आपने यह जानने के लिए कि क्या तर्क पारित करने के लिए दस्तावेज़ीकरण पढ़ा है।
लाइटनेस दौड़ ऑर्बिट में

जवाबों:


113

आपने set_intersection के लिए आउटपुट इटेटर प्रदान किया है

template <class InputIterator1, class InputIterator2, class OutputIterator>
OutputIterator set_intersection ( InputIterator1 first1, InputIterator1 last1,
                                InputIterator2 first2, InputIterator2 last2,
                                OutputIterator result );

ऐसा कुछ करके ठीक करें

...;
set<int> intersect;
set_intersection(s1.begin(),s1.end(),s2.begin(),s2.end(),
                  std::inserter(intersect,intersect.begin()));

std::insertसेट के खाली होने के बाद से आपको पुनरावृत्ति की आवश्यकता है । हम back_ या front_inserter का उपयोग नहीं कर सकते हैं क्योंकि सेट उन कार्यों का समर्थन नहीं करता है।


70
मैं यह समझना चाहूंगा कि सेटों पर इस तरह के एक मौलिक ऑपरेशन के लिए इस तरह के एक क्रियात्मक क्रिया की आवश्यकता होती है। क्यों नहीं एक सरल set<T>& set::isect(set<T>&)विधि है, जो जरूरतमंद है? (मैं एक के लिए पूछना चाहते हैं set<T>& set::operator^(set<T>&), लेकिन यह बहुत दूर एक पुल है।)
रयान वी। बिसेल

3
@ RyanV.Bissell यह एक समान डिज़ाइन है जो लगभग सभी एल्गोरिदम में एक समान है <algorithm>यदि कुछ और नहीं है। यह शैली भी, मुझे लगता है, आपको लचीलापन देता है। और अल्गोस को कई कंटेनरों के साथ उपयोग करने की अनुमति देता है, हालांकि यह यहां नहीं हो सकता है .. इसके अलावा आपके हस्ताक्षर काम नहीं कर सकते हैं, आपको संभवतः एक मान वापस करने की आवश्यकता है। और यह कि नकल के पहले के दिनों में शब्दार्थ एक दोहरी प्रति होती जो मुझे लगता है। मैंने थोड़ी देर के लिए c ++ किया, अब इसे चुटकी या नमक के 3 के साथ लें
कार्तिक टी

4
मैं अभी भी अपने आप को एक एसटीएल नौसिखिया मानता हूं, इसलिए नमक अनाज का आवेदन भी लागू होता है। मेरी टिप्पणी संपादन विंडो की समय-सीमा समाप्त हो गई है, इसलिए मैं रिटर्न-बाय-रेफ़रेंस फ़ॉक्स-पेस को सही नहीं कर सकता। मेरी टिप्पणी सुसंगतता के बारे में शिकायत नहीं थी, लेकिन इस वाक्यविन्यास में इतने कड़वेपन का स्वाद क्यों होना चाहिए, इस बारे में एक ईमानदार सवाल है। शायद मुझे यह एक SO प्रश्न बनाना चाहिए।
रयान वी। बिस्सेल

3
दरअसल, इस अस्पष्ट फैशन में ज्यादातर C ++ std lib डिज़ाइन किए गए हैं। हालांकि डिजाइन की लालित्य स्पष्ट है (wrt सामान्यता, लेकिन न केवल), एपीआई की जटिलता में विनाशकारी प्रभाव होते हैं (ज्यादातर क्योंकि लोग पहियों को फिर से बनाना शुरू कर देते हैं क्योंकि वे उन कंपाइलरों का उपयोग अपने कंपाइलर के साथ नहीं कर सकते हैं)। एक और दुनिया में, डिजाइनरों को अपने उपयोगकर्ता पर अपनी खुशी के लिए थप्पड़ मारा गया होगा। इस दुनिया में ... ठीक है, कम से कम हमारे पास StackOverflow है।

3
यह एक "सामान्य वाक्यविन्यास" है - आप एक वेक्टर पर सेट_इंटर्सफेक्शन भी कर सकते हैं और एक सूची में और एक परिणाम को स्टोर कर सकते हैं, और आपको यह बात कुशलता से करने में सक्षम होना चाहिए (बेशक, यह ध्यान रखना आपकी समस्या है कि दोनों स्रोत कंटेनरों को इसे कॉल करने से पहले सॉर्ट किया जाता है)। मुझे यह बुरा नहीं लगता है, केवल एक चीज जिसकी मुझे समस्या है वह यह है कि setकंटेनर की एक विधि भी हो सकती है जो दूसरे सेट के साथ प्रतिच्छेदन करती है। के बजाय एक कंटेनर से गुजरने का विषय .begin()- .end()एक और बात है - यह तब तय हो जाएगा जब सी ++ में अवधारणाएं होंगी।
इथोरिस

25

लिंक में नमूने पर एक नजर है: http://en.cppreference.com/w/cpp/algorithm/set_intersection

चौराहे के डेटा को स्टोर करने के लिए आपको एक और कंटेनर की आवश्यकता है, जो काम करने के लिए कोड के नीचे है:

std::vector<int> common_data;
set_intersection(s1.begin(),s1.end(),s2.begin(),s2.end(), std::back_inserter(common_data));

6
back_inserterकोई कार्य नहीं है के setरूप setमें के साथ काम नहीं push_backकरता है।
जैक ऐडली

6

Std :: set_intersection देखें । आपको एक आउटपुट पुनरावृत्ति जोड़ना होगा, जहां आप परिणाम संग्रहीत करेंगे:

#include <iterator>
std::vector<int> s3;
set_intersection(s1.begin(),s1.end(),s2.begin(),s2.end(), std::back_inserter(s3));

पूर्ण सूची के लिए Ideone देखें ।


3
ध्यान दें कि back_inserter काम नहीं करेगा यदि आप चाहते हैं कि परिणाम भी एक सेट हो, तो आपको std :: सम्मिलन जैसे कार्तिक का उपयोग करना होगा।
जोसेफ गार्विन

4

बस यहाँ टिप्पणी करें। मुझे लगता है कि यह सेट इंटरफ़ेस के लिए यूनियन, इंटरसेक्ट ऑपरेशन को जोड़ने का समय है। इसे भविष्य के मानकों में प्रस्तावित करते हैं। मैं लंबे समय से एसटीडी का उपयोग कर रहा हूं, हर बार जब मैंने सेट ऑपरेशन का उपयोग किया तो मैं चाहता था कि एसटीडी बेहतर रहे। कुछ जटिल सेट ऑपरेशन के लिए, प्रतिच्छेदन की तरह, आप बस (आसान?) निम्नलिखित कोड को संशोधित कर सकते हैं:

template <class InputIterator1, class InputIterator2, class OutputIterator>
  OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1,
                                   InputIterator2 first2, InputIterator2 last2,
                                   OutputIterator result)
{
  while (first1!=last1 && first2!=last2)
  {
    if (*first1<*first2) ++first1;
    else if (*first2<*first1) ++first2;
    else {
      *result = *first1;
      ++result; ++first1; ++first2;
    }
  }
  return result;
}

से कॉपी किया गया http://www.cplusplus.com/reference/algorithm/set_intersection/

उदाहरण के लिए, यदि आपका आउटपुट सेट है, तो आप output.insert (* first1) कर सकते हैं। इसके अलावा, आप फ़ंक्शन को बंद नहीं किया जा सकता है। यदि आप कोड std set_intersection फ़ंक्शन का उपयोग करने से कम हो सकते हैं, तो इसके बाद आगे बढ़ें।

यदि आप दो सेट का एक संघ करना चाहते हैं, तो आप बस सेट कर सकते हैं। (setB.begin (), setB.end ()); यह set_union विधि की तुलना में बहुत सरल है। हालांकि, यह वेक्टर के साथ काम नहीं करेगा।


4

स्वीकृत उत्तर की पहली (अच्छी तरह से मतदान) टिप्पणी मौजूदा एसटीडी संचालन के लिए एक लापता ऑपरेटर के बारे में शिकायत करती है।

एक तरफ, मैं मानक पुस्तकालय में ऐसे ऑपरेटरों की कमी को समझता हूं। दूसरी ओर, उन्हें (व्यक्तिगत आनंद के लिए) अगर चाहें तो जोड़ना आसान है। मैंने ओवरलोड किया

  • operator *() सेट के प्रतिच्छेदन के लिए
  • operator +() सेटों के मिलन के लिए।

नमूना test-set-ops.cc:

#include <algorithm>
#include <iterator>
#include <set>

template <class T, class CMP = std::less<T>, class ALLOC = std::allocator<T> >
std::set<T, CMP, ALLOC> operator * (
  const std::set<T, CMP, ALLOC> &s1, const std::set<T, CMP, ALLOC> &s2)
{
  std::set<T, CMP, ALLOC> s;
  std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
    std::inserter(s, s.begin()));
  return s;
}

template <class T, class CMP = std::less<T>, class ALLOC = std::allocator<T> >
std::set<T, CMP, ALLOC> operator + (
  const std::set<T, CMP, ALLOC> &s1, const std::set<T, CMP, ALLOC> &s2)
{
  std::set<T, CMP, ALLOC> s;
  std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(),
    std::inserter(s, s.begin()));
  return s;
}

// sample code to check them out:

#include <iostream>

using namespace std;

template <class T>
ostream& operator << (ostream &out, const set<T> &values)
{
  const char *sep = " ";
  for (const T &value : values) {
    out << sep << value; sep = ", ";
  }
  return out;
}

int main()
{
  set<int> s1 { 1, 2, 3, 4 };
  cout << "s1: {" << s1 << " }" << endl;
  set<int> s2 { 0, 1, 3, 6 };
  cout << "s2: {" << s2 << " }" << endl;
  cout << "I: {" << s1 * s2 << " }" << endl;
  cout << "U: {" << s1 + s2 << " }" << endl;
  return 0;
}

संकलित और परीक्षण किया गया:

$ g++ -std=c++11 -o test-set-ops test-set-ops.cc 

$ ./test-set-ops     
s1: { 1, 2, 3, 4 }
s2: { 0, 1, 3, 6 }
I: { 1, 3 }
U: { 0, 1, 2, 3, 4, 6 }

$ 

मुझे जो पसंद नहीं है वह ऑपरेटरों में रिटर्न वैल्यू की कॉपी है। हो सकता है, यह चाल असाइनमेंट का उपयोग करके हल किया जा सकता है लेकिन यह अभी भी मेरे कौशल से परे है।

इन "नए फैंसी" चाल शब्दार्थों के बारे में मेरे सीमित ज्ञान के कारण, मैं ऑपरेटर रिटर्न के बारे में चिंतित था जो कि रिटर्न सेट की प्रतियां पैदा कर सकता था। ओलाफ डाइटशे ने बताया कि ये चिंताएँ अनावश्यक हैं क्योंकि std::setपहले से ही मूव कंस्ट्रक्टर / असाइनमेंट से लैस है।

हालांकि मुझे उस पर विश्वास था, मैं सोच रहा था कि इसे कैसे चेक किया जाए ("आत्म-आश्वस्त" जैसी चीज़ के लिए)। दरअसल, यह काफी आसान है। जैसा कि टेम्पलेट्स को स्रोत कोड में प्रदान करना होता है, आप बस डिबगर के माध्यम से कदम बढ़ा सकते हैं। इस प्रकार, मैं कम से एक को तोड़ने बिंदु सही रखा return s;की operator *()और एकल कदम जो मुझे में तुरंत लीडेड साथ रवाना हुएstd::set::set(_myt&& _Right) : एट देखा - चाल निर्माता। धन्यवाद, ओलाफ, (मेरे) ज्ञानोदय के लिए।

पूर्णता के लिए, मैंने इसी असाइनमेंट ऑपरेटरों को भी लागू किया

  • operator *=() सेट के "विनाशकारी" चौराहे के लिए
  • operator +=() सेट के "विनाशकारी" संघ के लिए।

नमूना test-set-assign-ops.cc:

#include <iterator>
#include <set>

template <class T, class CMP = std::less<T>, class ALLOC = std::allocator<T> >
std::set<T, CMP, ALLOC>& operator *= (
  std::set<T, CMP, ALLOC> &s1, const std::set<T, CMP, ALLOC> &s2)
{
  auto iter1 = s1.begin();
  for (auto iter2 = s2.begin(); iter1 != s1.end() && iter2 != s2.end();) {
    if (*iter1 < *iter2) iter1 = s1.erase(iter1);
    else {
      if (!(*iter2 < *iter1)) ++iter1;
      ++iter2;
    }
  }
  while (iter1 != s1.end()) iter1 = s1.erase(iter1);
  return s1;
}

template <class T, class CMP = std::less<T>, class ALLOC = std::allocator<T> >
std::set<T, CMP, ALLOC>& operator += (
  std::set<T, CMP, ALLOC> &s1, const std::set<T, CMP, ALLOC> &s2)
{
  s1.insert(s2.begin(), s2.end());
  return s1;
}

// sample code to check them out:

#include <iostream>

using namespace std;

template <class T>
ostream& operator << (ostream &out, const set<T> &values)
{
  const char *sep = " ";
  for (const T &value : values) {
    out << sep << value; sep = ", ";
  }
  return out;
}

int main()
{
  set<int> s1 { 1, 2, 3, 4 };
  cout << "s1: {" << s1 << " }" << endl;
  set<int> s2 { 0, 1, 3, 6 };
  cout << "s2: {" << s2 << " }" << endl;
  set<int> s1I = s1;
  s1I *= s2;
  cout << "s1I: {" << s1I << " }" << endl;
  set<int> s2I = s2;
  s2I *= s1;
  cout << "s2I: {" << s2I << " }" << endl;
  set<int> s1U = s1;
  s1U += s2;
  cout << "s1U: {" << s1U << " }" << endl;
  set<int> s2U = s2;
  s2U += s1;
  cout << "s2U: {" << s2U << " }" << endl;
  return 0;
}

संकलित और परीक्षण किया गया:

$ g++ -std=c++11 -o test-set-assign-ops test-set-assign-ops.cc 

$ ./test-set-assign-ops
s1: { 1, 2, 3, 4 }
s2: { 0, 1, 3, 6 }
s1I: { 1, 3 }
s2I: { 1, 3 }
s1U: { 0, 1, 2, 3, 4, 6 }
s2U: { 0, 1, 2, 3, 4, 6 }

$

1
std::setपहले से ही आवश्यक कदम निर्माता और असाइनमेंट ऑपरेटर को लागू करता है, इसलिए इसके बारे में चिंता करने की कोई आवश्यकता नहीं है। इसके अलावा संकलक सबसे अधिक संभावना रिटर्न वैल्यू ऑप्टिमाइजेशन
ओलाफ डायटशे

@OlafDietsche आपकी टिप्पणी के लिए धन्यवाद। मैंने इसकी जाँच की और क्रमशः उत्तर में सुधार किया। आरवीओ के बारे में, मेरे पास अपने सहयोगियों के साथ पहले से ही कुछ विचार-विमर्श था, जब तक कि मैंने उन्हें वीएस2013 के डिबगर में नहीं दिखाया कि ऐसा नहीं होता है (कम से कम हमारे डेवेल प्लेटफॉर्म में)। वास्तव में, यह महत्वपूर्ण नहीं है सिवाय इसके कि यदि कोड प्रदर्शन महत्वपूर्ण है। बाद के मामले में, मैं आरवीओ पर भरोसा नहीं करना चाहता हूं। (यह वास्तव में सी ++ में उतना मुश्किल नहीं है ...)
शेफ

अच्छी तरह से Scheff (बोस नहीं), अच्छा विवरण।
जीजू

अब भी C ++ 17 के गारंटीकृत एलिसन के लिए वीएस का समर्थन शोकपूर्ण है।
लाइटनेस दौड़ ऑर्बिट में
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.