অবতরণ ক্রমে একটি ভেক্টর বাছাই করা


310

আমার ব্যবহার করা উচিত

std::sort(numbers.begin(), numbers.end(), std::greater<int>());

অথবা

std::sort(numbers.rbegin(), numbers.rend());   // note: reverse iterators

একটি ভেক্টর অবতরণ ক্রম বাছাই? একটি পদ্ধতির সাথে বা অন্যের সাথে কোনও সুবিধা বা ত্রুটি রয়েছে?


2
+1 আমি উত্তরটি সুস্পষ্ট বলে মনে করি, তবে এই প্রশ্নের একটি আকর্ষণীয় কিছুটা ট্রিভিয়াম রয়েছে। :)
wilhelmtell

3
আমি প্রথম বিকল্পটির পক্ষে ভোট দিয়েছি, কেবলমাত্র তখনই আমাকে আর মোকাবেলা করতে হবে না reverse_iterator
evandrix

2
@ উইলহেলমটেল একটি নুব প্রশ্ন তবে কেন দ্বিতীয়টি সাজানো ক্রমে সাজানো উচিত? আমরা সাজানোর পদ্ধতিতে ইনপুট হিসাবে একই অ্যারে দিচ্ছি। এটি ঠিক যে আমরা এটিকে বিপরীত ক্রমে দিচ্ছি তাই কেন এটি সাজানো এবং আরোহী ক্রম হিসাবে সাজানো হবে না যেমন ar.begin () এবং ar.end এর ক্ষেত্রে হবে।
shshnk

6
@shshnk std::sort(b, e);সর্বনিম্ন b(আমাদের ক্ষেত্রে rbegin, সুতরাং শেষ উপাদানটি) এবং সর্বাধিক e(আমাদের ক্ষেত্রে rend, তাই প্রথম উপাদান) রাখে।
ফ্রেডওভারফ্লো

উত্তর:


114

আসলে, প্রথমটি একটি খারাপ ধারণা। দ্বিতীয়টি ব্যবহার করুন বা এটি:

struct greater
{
    template<class T>
    bool operator()(T const &a, T const &b) const { return a > b; }
};

std::sort(numbers.begin(), numbers.end(), greater());

যখন কেউ সিদ্ধান্ত নেয় বা পরিবর্তে numbersরাখা উচিত তখন আপনার কোডটি নীরবে ভাঙ্গবে না ।longlong longint


1
@ ফ্রেড ওভারফ্লো: আপনি আপনার মন্তব্যে অনার্স দিয়েছিলেন;)
ব্যবহারকারী541686

2
বা প্রথমটির সাথে লেগে থাকুন। নাম্বার কনটেইনারটির জন্য একটি টাইপডেফ ব্যবহার করুন - একটি ভাল ধারণা যাতে কেউ দীর্ঘায়িত হয়ে যেতে পারে - এবং লিখুন: std :: সাজ্ট (সংখ্যা.বেগিন (), নম্বরসেন্ড (), স্ট্যান্ড :: বৃহত্তর <numContainer :: value_type> ( ));
রিচার্ড হাওলস

1
+1 প্রথমটি সত্যিই বিভ্রান্তিকর। কিgreater চেয়ে ? rbeginএবং rendএকটি নির্দিষ্ট উদ্দেশ্যে তৈরি করা হয়েছিল।
অভিষেক দিভেকর

6
শুধু std::greater<typename decltype(numbers)::value_type>()বা কিছু না কেন ?
einpoklum

1
এই উত্তরটি পুরানো - আপনি ব্যবহার করতে পারেন std::greater<>() সি ++ ১৪ থেকে ।
নিকোলাই

70

প্রথমটি ব্যবহার করুন:

std::sort(numbers.begin(), numbers.end(), std::greater<int>());

অশুদ্ধ পাঠ সুযোগ কম - এটি কী হচ্ছে বর্ণিত আছে rbeginযেমন beginএমনকি একটি মন্তব্য সহ। এটি পরিষ্কার এবং পঠনযোগ্য যা আপনি যা চান ঠিক তাই।

এছাড়াও, দ্বিতীয়টি বিপরীত পুনরুক্তিগুলির প্রকৃতি প্রদত্ত প্রথমটির চেয়ে কম দক্ষ হতে পারে, যদিও আপনাকে নিশ্চিত হতে এটির প্রোফাইল দিতে হবে।


68

সি ++ 14 দিয়ে আপনি এটি করতে পারেন:

std::sort(numbers.begin(), numbers.end(), std::greater<>());

30

এই সম্পর্কে কি?

std::sort(numbers.begin(), numbers.end());
std::reverse(numbers.begin(), numbers.end());

13
অতিরিক্ত জটিলতা এড়ানো একটি কারণ হতে পারে: ও (এন * লগ (এন)) + ও (এন) বনাম ও (এন * লগ (এন))
গ্রেগ

32
@ গ্রেগ ও (এন * লগ (এন)) = ও (এন * লগ (এন) + এন)। তারা একই সেট সংজ্ঞায়িত করার দুটি উপায়। আপনি বলতে চাইছেন "এটি ধীর হতে পারে"।
pjvandehaar

4
@pjvandehaar গ্রেগ ঠিক আছে। তিনি সুস্পষ্টভাবে O (n * লগ (এন) + এন) বলেননি, তিনি ও (এন * লগ (এন)) + ও (এন) বলেছেন। আপনি ঠিক বলেছেন যে তাঁর শব্দটি অস্পষ্ট (বিশেষত জটিলতার শব্দের অপব্যবহার), তবে আপনি দয়া করে উত্তর দিতে পারতেন। উদাহরণস্বরূপ: আপনি বোঝাতে চেয়েছিলেন 'জটিলতা' শব্দটির পরিবর্তে 'গণনা' শব্দটি ব্যবহার করা। সংখ্যাগুলি বিপরীত করা অন্যথায় অভিন্ন ও (এন * লগ (এন)) ধাপে অপ্রয়োজনীয় ও (এন) পদক্ষেপ।
ওফেক গিলা

3
@ ওফেকগিলা আমার বোধগম্যতা হল যে বড়-ও স্বরলিপিটি ফাংশনগুলির সেট এবং নোটেশন জড়িত =এবং +এটি কেবল সুবিধাজনক অর্থ এবং । সেক্ষেত্রে , O(n*log(n)) + O(n)একটি সুবিধাজনক স্বরলিপি O(n*log(n)) ∪ O(n)যা এর মত একই O(n*log(n))। "গণনা" শব্দটি একটি ভাল পরামর্শ এবং আপনি সুরটি সম্পর্কে ঠিক বলেছেন।
pjvandehaar


16

আমার মেশিন অনুযায়ী, বাছাই একটি long long প্রথম পদ্ধতিটি ব্যবহার করে [1..3000000] এর ভেক্টর প্রায় 4 সেকেন্ড সময় লাগে, যখন দ্বিতীয়টি ব্যবহার করতে সময় প্রায় দ্বিগুণ লাগে। এটি স্পষ্টতই কিছু বলছে, তবে কেন তা আমি বুঝতে পারি না। মনে করুন এটি সহায়ক হবে।

একই জিনিস এখানে রিপোর্ট করা

জিও দ্বারা যেমন বলা হয়েছে, -O3তারা সমাপ্তির জন্য একই সময় ব্যবহার করে।


12
আপনি সম্ভবত অপ্টিমাইজেশন চালু সঙ্গে সংকলন না? সাউন্ড খুব মত reverse_iteratorঅপারেশন inlined করা হয় নি, এবং প্রদত্ত যে, তারা প্রকৃত iterators প্রায় শুধু একটি মোড়কের আছেন, এটা আশ্চর্যের কিছু তারা ইনলাইনিং ছাড়া ডবল সময় লাগবে না।
শিও

@ জিতেও যদি তারা কিছুটা কার্যকর করে তবে কিছু বাস্তবায়ন ডেরিফারেন্স অনুযায়ী একটি সংযোজন ব্যবহার করে।
পাব্বি

@ এল্ডজার্ন: কারণ এরকম? base()উদাহরণস্বরূপ আয় জন্য সদস্য ফাংশন পুনরুক্তিকারীর আবৃত।
Xoo

1
@ শিও এখন তারা দু'জনই এক সেকেন্ডে শেষ করে। ধন্যবাদ!
zw324

3
@ শিও: আমি আবার ফিরিয়ে নিই; মান আসলে ম্যান্ডেট যে std::vector<>::reverse_iteratorপরিপ্রেক্ষিতে বাস্তবায়িত হয় std::reverse_iterator<>। উদ্ভট; আজ আমি শিখলাম. :
পি

11

প্রথম পদ্ধতির উল্লেখ:

    std::sort(numbers.begin(), numbers.end(), std::greater<>());

দ্বিতীয়টির চেয়ে বেশি দক্ষতা পাওয়ার কারণে আপনি প্রথম পদ্ধতির ব্যবহার করতে পারেন।
প্রথম পদ্ধতির সময় জটিলতা দ্বিতীয়টির চেয়ে কম।


এটি ম্রেক্সসিটিংয়ের মতো একই উত্তর। জটিলতা সম্পর্কে মন্তব্যটিও আমার কাছে অস্পষ্ট।
ফিলিপ ক্লেন

7
bool comp(int i, int j) { return i > j; }
sort(numbers.begin(), numbers.end(), comp);

4
একটি বৈধ উত্তর হতে চাইলে আমাদের অবশ্যই সুফল সম্পর্কে কিছু লেখার বিবেচনা করা উচিত / ওপি আপনার বনাম অপূর্ণতা উল্লেখ পদ্ধতি
স্টিফান Hegny

3

টি এল; ডিআর

যে কোনও ব্যবহার করুন। তারা প্রায় একই।

বিরক্তিকর উত্তর

যথারীতি যথাযথ এবং কুফল রয়েছে।

ব্যবহার std::reverse_iterator:

  • আপনি যখন কাস্টম ধরণের বাছাই করছেন এবং আপনি প্রয়োগ করতে চান না operator>()
  • আপনি টাইপ করতে খুব অলস যখন std::greater<int>()

std::greaterযখন ব্যবহার করুন :

  • আপনি আরও সুস্পষ্ট কোড পেতে চাইলে
  • যখন আপনি অস্পষ্ট বিপরীত পুনরাবৃত্তি ব্যবহার করা এড়াতে চান

কর্মক্ষমতা হিসাবে, উভয় পদ্ধতি সমান দক্ষ। আমি নিম্নলিখিত মানদণ্ড চেষ্টা করেছি:

#include <algorithm>
#include <chrono>
#include <iostream>
#include <fstream>
#include <vector>

using namespace std::chrono;

/* 64 Megabytes. */
#define VECTOR_SIZE (((1 << 20) * 64) / sizeof(int))
/* Number of elements to sort. */
#define SORT_SIZE 100000

int main(int argc, char **argv) {
    std::vector<int> vec;
    vec.resize(VECTOR_SIZE);

    /* We generate more data here, so the first SORT_SIZE elements are evicted
       from the cache. */
    std::ifstream urandom("/dev/urandom", std::ios::in | std::ifstream::binary);
    urandom.read((char*)vec.data(), vec.size() * sizeof(int));
    urandom.close();

    auto start = steady_clock::now();
#if USE_REVERSE_ITER
    auto it_rbegin = vec.rend() - SORT_SIZE;
    std::sort(it_rbegin, vec.rend());
#else
    auto it_end = vec.begin() + SORT_SIZE;
    std::sort(vec.begin(), it_end, std::greater<int>());
#endif
    auto stop = steady_clock::now();

    std::cout << "Sorting time: "
          << duration_cast<microseconds>(stop - start).count()
          << "us" << std::endl;
    return 0;
}

এই কমান্ড লাইনের সাথে:

g++ -g -DUSE_REVERSE_ITER=0 -std=c++11 -O3 main.cpp \
    && valgrind --cachegrind-out-file=cachegrind.out --tool=cachegrind ./a.out \
    && cg_annotate cachegrind.out
g++ -g -DUSE_REVERSE_ITER=1 -std=c++11 -O3 main.cpp \
    && valgrind --cachegrind-out-file=cachegrind.out --tool=cachegrind ./a.out \
    && cg_annotate cachegrind.out

std::greater demo std::reverse_iterator demo

সময় একই। ভালগ্রাইন্ড একই সংখ্যক ক্যাশে মিস করার প্রতিবেদন করে।


2

আমি মনে করি না যে প্রশ্নে আপনার উভয় পদ্ধতিই ব্যবহার করা উচিত কারণ এগুলি উভয়ই বিভ্রান্তিকর, এবং দ্বিতীয়টি মেহেরদাদের পরামর্শ মতো ভঙ্গুর।

আমি নিম্নলিখিতগুলির পক্ষে মতামত করব, কারণ এটি একটি আদর্শ লাইব্রেরি ফাংশনের মতো দেখায় এবং এর উদ্দেশ্যটি পরিষ্কার করে দেয়:

#include <iterator>

template <class RandomIt>
void reverse_sort(RandomIt first, RandomIt last)
{
    std::sort(first, last, 
        std::greater<typename std::iterator_traits<RandomIt>::value_type>());
}

2
এটি std::greaterতুলনামূলক ব্যবহারের চেয়ে হাজার গুণ বেশি বিভ্রান্তির মতো ....
অ্যাপলিস মনিকাকে

@ অ্যাপলিগুলি আমি সম্মত হই যে সি ++ 14 দিয়ে শুরু করা, স্ট্যান্ড :: বৃহত্তর <> পছন্দসই সমাধানের মতো দেখায়। আপনার যদি সি ++ 14 না থাকে তবে আপনি যদি স্টাড :: বৃহত্তর <int> দিয়ে কোনও বিস্ময় প্রকাশ করতে চান তবে এটি কার্যকর হতে পারে (উদাহরণস্বরূপ, যখন কোনও বিন্যাসের প্রকারগুলি দীর্ঘ থেকে দীর্ঘতে পরিবর্তিত হয়)।
ফিলিপ ক্লেন

2

আপনি হয় প্রথমটি ব্যবহার করতে পারেন বা নীচের কোডটি চেষ্টা করতে পারেন যা সমান দক্ষ

sort(&a[0], &a[n], greater<int>());
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.