সি ++ এ সেট দুটি দফার ছেদটি কীভাবে খুঁজে পাবেন?


93

আমি সি ++ তে দুটি স্ট্যান্ড :: সেট করার মধ্যবর্তী ছেদটি সন্ধান করার চেষ্টা করছি, তবে আমি ত্রুটি পেতে থাকি।

আমি এটির জন্য একটি ছোট নমুনা পরীক্ষা তৈরি করেছি

#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::setসি ++ তে দুটিয়ের ছেদটি খুঁজে পাওয়ার আরও ভাল উপায় কি? সাধারণত একটি অন্তর্নির্মিত ফাংশন?

অনেক ধন্যবাদ!


"আমি একটি নতুন সেট আশা করি (আসুন এটিকে এস 3 বলুন)" তবে আপনি তা করেন না এবং আপনি করেন নি। ফলাফলগুলি কোথায় যাবে আপনি বুঝতে পারছেন না don't এছাড়াও কোন যুক্তি পাস করতে হবে তা জানতে আপনি ডকুমেন্টেশনটি পড়েন নি।
অরবিটে হালকা হওয়া রেস

উত্তর:


114

আপনি set_intersication জন্য একটি আউটপুট পুনরাবৃত্তি সরবরাহ করেন নি

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সেটটি এখন খালি হওয়ায় আপনার একটি পুনরুক্তি প্রয়োজন । সেট ব্যাকআপ বা ফ্রন্ট_ইনসেটর ব্যবহার করতে পারি না কারণ সেটগুলি এই ক্রিয়াকলাপগুলিকে সমর্থন করে না।


76
আমি বুঝতে চাই যে সেটগুলিতে এই জাতীয় মৌলিক ক্রিয়াকলাপে কেন এই জাতীয় বিন্যাসের উদ্দীপনা প্রয়োজন। কেন একটি সহজ set<T>& set::isect(set<T>&)পদ্ধতি, যে প্রয়োজনীয়? (আমি একটি জন্য জিজ্ঞেস করবে না set<T>& set::operator^(set<T>&), কিন্তু যে সম্ভবত একটি সেতু অতিদূরে আছে।)
রায়ান ভি Bissell

4
@ রায়ানভি.বিসেল এটি <algorithm>ধারাবাহিকতায় প্রায় সমস্ত অ্যালগরিদমের সাথে একই রকম নকশা যা অন্য কিছু না হলে। আমিও ধরে নিয়েছি এই শৈলীটি আপনাকে নমনীয়তা দেয়। এবং বেশিরভাগ পাত্রে আলগোসগুলি ব্যবহার করার অনুমতি দেয়, যদিও এটি এখানে না ঘটে .. এছাড়াও আপনার স্বাক্ষরটি কাজ নাও করতে পারে, আপনাকে সম্ভবত কোনও মান ফেরত দিতে হবে। এবং এটি আগের দিনগুলিতে কপির শব্দার্থবিজ্ঞানগুলি আমার মনে হয় একটি ডাবল অনুলিপি হত। আমি কিছুক্ষণের জন্য সি ++ করেছি না তাই এটি একটি চিমটি বা 3
টি

4
আমি এখনও নিজেকে একটি এসটিএল নবজাতক হিসাবে বিবেচনা করি, তাই লবণের দানার প্রয়োগও প্রযোজ্য। আমার মন্তব্য সম্পাদনার উইন্ডোটির মেয়াদ শেষ হয়ে গেছে, তাই আমি রিটার্ন বাই রেফারেন্স ভুল-পাস সংশোধন করতে পারি না। আমার মন্তব্যটি ধারাবাহিকতা সম্পর্কে অভিযোগ ছিল না, তবে এই বাক্য গঠনটি কেন অবশ্যই তিক্ততার স্বাদ গ্রহণ করতে হবে তা সম্পর্কে একটি সৎ প্রশ্ন। সম্ভবত আমার এটিকে একটি প্রশ্ন করা উচিত।
রায়ান ভি। বিসেল

4
আসলে, বেশিরভাগ সি ++ স্টিড লিব এই অস্পষ্ট ফ্যাশনে ডিজাইন করা হয়েছে। ডিজাইনের কমনীয়তা সুস্পষ্টভাবে উপস্থিত থাকলেও (কেবল জারিতির উদারতা নয়, তবে) এপিআইয়ের জটিলতার বিপর্যয়কর প্রভাব রয়েছে (বেশিরভাগ কারণ লোকেরা পুনরায় উদ্ভাবনী চাকা চালিয়ে যায় কারণ তারা তাদের সংকলক সহ জাহাজগুলি ব্যবহার করতে পারে না)। অন্য একটি জগতে, ডিজাইনাররা তাদের ব্যবহারকারীর উপর তাদের সন্তুষ্টির পক্ষে চড় মারতেন। এই বিশ্বে ... ভাল, কমপক্ষে আমাদের স্ট্যাকওভারফ্লো রয়েছে।

4
এটি একটি "সাধারণ বাক্য গঠন" - আপনি কোনও ভেক্টর এবং একটি তালিকাতে সেট-ইন্টেরেকশনও করতে পারেন এবং ফলাফলগুলি একটি ডীক হিসাবে সংরক্ষণ করতে পারেন এবং আপনি এই জিনিসটি দক্ষতার সাথে করতে সক্ষম হবেন (অবশ্যই, আপনার সমস্যাটি উভয়ই খেয়াল রাখতে হবে) উত্স পাত্রে এটি কল করার আগে বাছাই করা হয়)। আমি এটি খারাপ মনে করি না, কেবলমাত্র আমার সমস্যাটি হ'ল এটি এমন একটি setধারক পদ্ধতিও হতে পারে যা অন্য সেট দিয়ে ছেদ করে। একটি ধারক পরিবর্তে ক্ষণস্থায়ী বিষয় .begin()- .end()অন্য জিনিস হয় - একবার সি ++ ধারণা হয়েছে এই সংশোধন করা হবে।
ইথুরিস

25

লিঙ্কটিতে নমুনাটি দেখুন: http://en.cppreferences.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));

সম্পূর্ণ তালিকার জন্য আইডিয়ন দেখুন ।


4
মনে রাখবেন যে ব্যাক_ইনসেটর কাজ করবে না যদি আপনি ফলাফলটিও একটি সেট হতে চান, তবে আপনার প্রয়োজন স্ট্যান্ড :: কার্তিকের মতো সন্নিবেশক ব্যবহার করা।
জোসেফ গারভিন

4

এখানে শুধু মন্তব্য। আমি মনে করি এটি ইউনিয়ন যুক্ত করার, সেট ইন্টারফেসে ছেদ করার অপারেশন time আসুন ভবিষ্যতের মানগুলিতে এটি প্রস্তাব করি। আমি দীর্ঘদিন ধরে এই স্টাডিটি ব্যবহার করে আসছি, প্রতিটি সময় আমি সেট অপারেশনটি ব্যবহার করলাম আমার ইচ্ছা এই স্ট্যান্ডটি আরও ভাল হয়। ছেদ করার মতো কিছু জটিল সেট অপারেশনের জন্য, আপনি কেবল (সহজ?) নিম্নলিখিত কোডটি সংশোধন করতে পারেন:

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/references/algorithm/set_intersection/ থেকে অনুলিপি

উদাহরণস্বরূপ, যদি আপনার আউটপুট সেট হয় তবে আপনি আউটপুট.িনেট করতে পারেন (* প্রথম ১)। তদ্ব্যতীত, আপনি ফাংশনটি টেম্পলেটেড নাও হতে পারেন you যদি আপনার কোডটি std set_intersection ফাংশনটি ব্যবহার করার চেয়ে ছোট করা যায় তবে এটির সাথে এগিয়ে যান।

আপনি যদি দুটি সেটের একটি ইউনিয়ন করতে চান তবে আপনি কেবল সেটএ.insert (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 *()এবং একক-পদক্ষেপ যা আমার মধ্যে অবিলম্বে leaded সঙ্গে রইল 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 }

$

4
std::setইতিমধ্যে প্রয়োজনীয় মুভ কনস্ট্রাক্টর এবং অ্যাসাইনমেন্ট অপারেটরটি প্রয়োগ করে, সুতরাং এটি সম্পর্কে উদ্বিগ্ন হওয়ার দরকার নেই। এছাড়াও সংকলক সম্ভবত রিটার্ন মান অপ্টিমাইজেশন
ওলাফ ডিয়েটশে

@ ওলাফডিয়েটসে আপনার মন্তব্যের জন্য ধন্যবাদ। আমি এটি পরীক্ষা করে দেখেছি এবং যথাক্রমে উত্তরটি উন্নত করেছি। আরভিও সম্পর্কে, আমার সহকর্মীদের সাথে আমি ইতিমধ্যে নির্দিষ্ট আলোচনা করেছি যতক্ষণ না আমি তাদের ভিএস ২০১৩ এর ডিবাগারে না দেখাই যে এটি ঘটে না (কমপক্ষে আমাদের ডেভেলপ প্ল্যাটফর্মে)। প্রকৃতপক্ষে, কোডটি পারফরম্যান্সের সমালোচনা করা বাদ দিলে এটি গুরুত্বপূর্ণ নয়। পরবর্তী ক্ষেত্রে, আমি আরভিওর উপর নির্ভর না করার জন্য আপাতত রাখি। (এটি আসলে সি ++ ... তে জটিল নয়)
শেফ

@ শেফ ওয়েল শেফ (বোস নয়), দুর্দান্ত ব্যাখ্যা।
JeJo

এখনও এখন সি ++ 17 এর গ্যারান্টিযুক্ত এলিজেনের জন্য ভিএসের সমর্থন দু: খজনক।
হালকা ঘোড়দৌড়
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.