मुझे लगता है कि सर्वोत्तम का मतलब है कि सबसे तेज़ है जो काम करता है। चूंकि यह दक्षता के बारे में एक सवाल है, इसलिए मैंने कई एल्गोरिदम की दक्षता की तुलना करने के लिए एक सरल बेंचमार्क किया है। ध्यान दें कि वे एक छोटे से अलग के बाद से समस्या एक सा underspecified है - सवाल उठता है कि (और मान्यताओं बेंचमार्क के लिए लिया गया) कर रहे हैं:
- यह गारंटी है कि
vDestination
vSource
से सभी तत्व शामिल हैं है? (धारणा: नहीं)
- या तो
vDestination
या vSource
में डुप्लिकेट की अनुमति है?(धारणा: हाँ, दोनों में)
- परिणाम वेक्टर पदार्थ में तत्वों का क्रम करता है? (दोनों मामलों के परीक्षण के लिए एल्गोरिदम)
vDestination
से प्रत्येक तत्व को हटाया जाना चाहिए यदि यह vSource
से किसी भी तत्व के बराबर है, या केवल एक-एक के लिए है? (धारणा: हाँ, दोनों में)
vDestination
और vSource
के आकार किसी भी तरह से बंधे हैं? उनमें से एक हमेशा बड़ा है या अधिक बड़ा है? (कई मामलों का परीक्षण किया गया)
- टिप्पणियों में यह पहले से ही समझाया गया है कि वैक्टर को क्रमबद्ध करने की आवश्यकता नहीं है, लेकिन मैंने इस बिंदु को शामिल किया है, क्योंकि यह तुरंत प्रश्न से दिखाई नहीं दे रहा है (वेक्टरों में से कोई भी सॉर्टिंग नहीं)
जैसा कि आप देखते हैं, कुछ बिंदुएं हैं जिनमें एल्गोरिदम अलग-अलग होंगे और परिणामस्वरूप, जैसा कि आप अनुमान लगा सकते हैं, सर्वोत्तम एल्गोरिदम आपके उपयोग के मामले पर निर्भर करेगा। तुलना एल्गोरिदम में शामिल हैं:
- मूल एक (प्रश्न में प्रस्तावित) - आधारभूत
- @dkg जवाब में प्रस्तावित
- @Revolver_Ocelot जवाब + अतिरिक्त छंटाई (कलन विधि के लिए आवश्यक) और अंतरिक्ष के पूर्व आरक्षण में प्रस्तावित परिणाम वेक्टर के लिए
- @ Jarod42 में प्रस्तावित का जवाब
- सेट आधारित एल्गोरिथ्म (नीचे प्रस्तुत - ज्यादातर @ Jarod42 एल्गोरिथ्म के अनुकूलन)
- गिनती एल्गोरिथ्म (पी नीचे resended)
सेट आधारित एल्गोरिथ्म:
std::unordered_set<int> elems(vSource.begin(), vSource.end());
auto i = destination.begin();
auto target = destination.end();
while(i <= target) {
if(elems.count(*i) > 0)
std::swap(*i, *(--target));
else
i++;
}
destination.erase(target, destination.end());
गिनती एल्गोरिथ्म:
std::unordered_map<int, int> counts;
counts.max_load_factor(0.3);
counts.reserve(destination.size());
for(auto v: destination) {
counts[v]++;
}
for(auto v: source) {
counts[v]--;
}
auto i = destination.begin();
for(auto k: counts) {
if(k.second < 1) continue;
i = std::fill_n(i, k.second, k.first);
}
destination.resize(std::distance(destination.begin(), i));
बेंचमार्किंग प्रक्रिया Celero लाइब्रेरी का उपयोग कर मार डाला गया था और पीछा कर रहा था:
- उत्पन्न
n
छद्म-यादृच्छिक int
रों (सेट {10,100,1000,10000, 20000, 200000}
में n
) और एक vector
- कॉपी करने के लिए उन्हें डाल सेट
{0.01, 0.1, 0.2, 0.4, 0.6, 0.8}
, मिनट से दूसरे vector
(अंशों करने के लिए इन ints का एक अंश (m
)। 1 तत्व)
- प्रारंभ टाइमर
- निष्पादित हटाने की प्रक्रिया
- टाइमर बंद करें
केवल एल्गोरिदम 3, 5 और 6 उनमें से बाकी के रूप में 10 000 तत्वों की तुलना में बड़े डेटासेट पर मार डाला गया के लिए लंबे समय तक ले गए मुझे आराम से मापने के लिए (इसे स्वयं करने के लिए स्वतंत्र महसूस करें)।
लंबी कहानी छोटी: यदि आपके वैक्टर में 1000 से कम तत्व होते हैं, तो आप जो चाहें उसे चुनें। यदि वे लंबे समय तक हैं - vSource
के आकार पर भरोसा करें। यदि यह vDestination
का 50% से कम है - सेट-आधारित एल्गोरिदम चुनें, यदि यह अधिक है - उन्हें क्रमबद्ध करें और @ Revolver_Ocelot का समाधान चुनें (वे लगभग 60% बांधते हैं, vSource
के लिए सेट-आधारित 2x तेज से vDestination
का 1% आकार है) ।कृपया आदेश पर भरोसा न करें या शुरुआत से क्रमबद्ध वेक्टर प्रदान करें - ऑर्डर करने की आवश्यकता समान है, प्रक्रिया को नाटकीय रूप से धीमा कर दें। अपने उपयोग के मामले, अपने कंपाइलर, अपने झंडे और अपने हार्डवेयर पर बेंचमार्क। यदि आप उन्हें पुन: पेश करना चाहते हैं, तो मैंने अपने बेंचमार्क से लिंक संलग्न किया है।
पूर्ण परिणाम (फ़ाइल vector-benchmarks.csv
) बेंचमार्किंग कोड (फ़ाइल tests/benchmarks/vectorRemoval.cpp
) here के साथ गिटहब पर उपलब्ध हैं।
कृपया ध्यान रखें कि ये परिणाम मेरे कंप्यूटर, मेरे कंपाइलर आदि पर प्राप्त हुए हैं - आपके मामले में वे अलग-अलग होंगे (विशेष रूप से जब यह उस बिंदु पर आता है जिसमें एक एल्गोरिदम दूसरे से बेहतर होता है)।
मैंने वर्चुअलबॉक्स के शीर्ष पर फेडोरा 24 पर -O3
के साथ जीसीसी 6.1.1 का उपयोग किया है।
यह मानते हुए कि वेक्टर ऑप्टिमाइज़ेशन के साथ परेशान करने के लिए पर्याप्त साबित होंगे, मैं पहले वेक्टर से महंगा हटाने से बचने के लिए 'vDestination' को 'std :: list' (या स्मार्ट पॉइंटर्स की सूची?) में बदल दूंगा (क्योंकि यह निरंतर होना चाहिए) और अंत में 'std :: vector' पर – slawekwin
@ स्लेवेकविन पर: मुझे दृढ़ता से संदेह है कि यह वेक्टर के किसी यथार्थवादी आकार के लिए तेज़ होगा। सूचियों को अतिरिक्त पुनर्निर्देशन की आवश्यकता होती है और कुशलतापूर्वक कैश नहीं किया जा सकता है। (मुझे पता है कि तत्वों को हटाने के लिए ओ (1) और वेक्टरों के लिए ओ (एन) है।) –
@ फ्रैंक मुझे इसके बारे में भी यकीन नहीं है, लेकिन मेरा मानना है कि यह मापने के लिए यह एक दिलचस्प प्रयोग होगा :) – slawekwin