क्यों कलेक्शंस.सॉर्ट मर्ज्सर्ट का उपयोग करता है लेकिन एरेस.सोर्ट नहीं करता है?


94

मैं JDK-8 (x64) का उपयोग कर रहा हूं। के लिए Arrays.sort(पुरातन) मैं जावा दस्तावेज में निम्नलिखित पाया:

सॉर्टिंग एल्गोरिथ्म व्लादिमीर यारोस्लावस्की, जॉन बेंटले और जोशुआ ब्लोच द्वारा एक दोहरी-पिवट क्विकॉर्ट है।

के लिए Collections.sort(वस्तुओं) मैंने पाया इस "Timsort":

यह कार्यान्वयन एक स्थिर, अनुकूली, पुनरावृत्त विलय है ... यह कार्यान्वयन निर्दिष्ट सूची को एक सरणी में रखता है , सरणी को सॉर्ट करता है , और सरणी में संबंधित स्थिति से प्रत्येक तत्व को रीसेट करने वाली सूची पर पुनरावृत्त करता है।

अगर Collections.sortएक सरणी का उपयोग करता है, तो यह सिर्फ Arrays.sortड्यूल- पिवेट क्विकॉर्ट को कॉल या उपयोग क्यों नहीं करता है ? Mergesort का उपयोग क्यों करें ?


8
यह आदिम की सरणियों के लिए javadoc है - वस्तुओं के सरणियों को मात्र का उपयोग करके सॉर्ट किया जाता है।
assylias

2
mergesort हमेशा u nlogn देता है, जबकि quicksort कभी-कभी nlogn2 दे सकता है। आनुवंशिक रूप से सरणियों का आकार बड़ा नहीं होता है, लेकिन संग्रह आसानी से लाखों प्रविष्टियों तक पहुंच जाता है, इसलिए nlogn2 का जोखिम लेना PS nlogn2 के लायक नहीं है। n
कुमार सौरभ

क्विकॉर्ट के लिए ओ (एन ^ 2) चरम सबसे खराब स्थिति है। व्यवहार में यह तेज़ है
जेम्स विएर्ज़बा

लेकिन यू कैंट आपी बनाते समय उन दुमों को नजरअंदाज नहीं करते
कुमार सौरभ

2
यह लिंक बहुत ही संबंधित है।
21

जवाबों:


99

एपीआई एक स्थिर छँटाई की गारंटी देता है जो क्विकसॉर्ट पेश नहीं करता है। हालांकि, जब छँटाई आदिम मूल्यों उनके प्राकृतिक आदेश से आप एक अंतर दिखाई नहीं देगा के रूप में आदिम मूल्यों कोई पहचान नहीं है। इसलिए, क्विकॉर्ट का उपयोग आदिम सरणियों के लिए किया जा सकता है और इसका उपयोग तब किया जाएगा जब इसे अधिक कुशल माना जाता है।

उन वस्तुओं के लिए जिन्हें आप नोटिस कर सकते हैं, जब अलग-अलग पहचान वाली वस्तुएँ जिन्हें उनके equalsकार्यान्वयन के अनुसार समान माना जाता है या प्रदान किया गया Comparatorहै, उनके क्रम को बदल देते हैं। इसलिए, क्विकॉर्ट एक विकल्प नहीं है। तो एक प्रकार का मर्जसॉर्ट का उपयोग किया जाता है, वर्तमान जावा संस्करण टिमोर्ट का उपयोग करते हैं । यह दोनों पर लागू होता है, Arrays.sortऔर Collections.sort, हालांकि, जावा 8 के साथ, Listस्वयं सॉर्ट एल्गोरिदम को ओवरराइड कर सकता है।


¹ क्विकॉर्ट के दक्षता लाभ को जगह में किए जाने पर कम मेमोरी की आवश्यकता होती है। लेकिन इसमें नाटकीय रूप से सबसे खराब स्थिति होती है और यह एक सरणी में पूर्व-सॉर्ट किए गए डेटा के रन का शोषण नहीं कर सकता है, जो टिमर्ट करता है।

इसलिए, छंटाई एल्गोरिदम को संस्करण से संस्करण में फिर से काम किया गया, जबकि अब-भ्रामक रूप से नामित कक्षा में रहते हैं DualPivotQuicksort। इसके अलावा, दस्तावेज़ीकरण ने पकड़ नहीं ली, जो दिखाता है, कि सामान्य रूप से एक खराब उपयोग किए गए एल्गोरिदम को विनिर्देशन में नाम देना, जब आवश्यक नहीं है।

वर्तमान स्थिति (जावा 8 से जावा 11 सहित) इस प्रकार है:

  • आम तौर पर, आदिम सरणियों के लिए छंटाई के तरीके क्विकॉर्ट को केवल कुछ परिस्थितियों में उपयोग करेंगे । बड़े सरणियों के लिए, वे पहले सॉर्ट किए गए डेटा के रनों को पहचानने की कोशिश करेंगे, जैसे कि टिमसर्ट करता है, और जब एक निश्चित सीमा से अधिक रन नहीं होता है, तो उन्हें मर्ज कर देगा। अन्यथा वे क्विकसॉर्ट में वापस आ जाएंगे , लेकिन एक कार्यान्वयन के साथ जो छोटी रेंज के लिए इंसर्शन सॉर्ट के लिए वापस आ जाएगा , जो न केवल छोटे सरणियों को प्रभावित करता है, बल्कि त्वरित सॉर्ट की पुनरावृत्ति भी है।
  • sort(char[],…)और एरेस केsort(short[],…) लिए काउंटिंग सॉर्ट का उपयोग करने के लिए एक और विशेष मामला जोड़ें, जिसकी लंबाई एक निश्चित सीमा से अधिक है
  • इसी तरह, काउंटिंग सॉर्ट काsort(byte[],…) उपयोग करेंगे , लेकिन बहुत छोटी सीमा के साथ, जो प्रलेखन के सबसे बड़े विपरीत बनाता है, जैसा कि क्विकॉर्टॉर्ट कभी नहीं करता है। यह केवल छोटे सरणियों और गिनती प्रकार के लिए सम्मिलन प्रकार का उपयोग करता है ।sort(byte[],…)

1
हम्म, दिलचस्प रूप से कलेक्शंस.सॉर्ट जवादोक कहता है: "यह सॉर्ट स्थिर होने की गारंटी है", लेकिन चूंकि यह List.sort को दर्शाता है, जिसे सूची कार्यान्वयनों द्वारा ओवरराइड किया जा सकता है, स्थिर सॉर्टिंग वास्तव में सभी लिस्ट के लिए Collections.sort के लिए महत्वपूर्ण नहीं हो सकती है। कार्यान्वयन। या मुझे कुछ याद है? और List.sort को स्थिर होने के लिए छंटनी की आवश्यकता नहीं है।
पूस

11
@ मूल्य: इसका मतलब है कि उस गारंटी के लिए जिम्मेदारी अब उन लोगों के हाथों में है जो ओवरराइडिंग List.sortपद्धति को लागू करते हैं । Collections.sortहर Listकार्यान्वयन के लिए सही गारंटी कभी काम नहीं कर सकता क्योंकि यह गारंटी नहीं दे सकता है, जैसे कि Listयह स्वाभाविक रूप से अपनी सामग्री को नहीं बदलता है। यह सब इस बात से उबलता है कि Collections.sortकेवल सही Listकार्यान्वयन (और सही Comparatorया equalsकार्यान्वयन) की गारंटी लागू होती है ।
होल्गर

1
@Puce: लेकिन आप सही हैं, जावदोक दोनों तरीकों में इस बाधा के बारे में समान रूप से स्पष्ट नहीं है, लेकिन कम से कम सबसे हालिया दस्तावेज़ीकरण बताता है कि किसके Collections.sortप्रतिनिधि होंगे List.sort
होल्गर

@ मूल्य: इस के उदाहरण के टन हैं, जहां महत्वपूर्ण गुण प्रकार का हिस्सा नहीं हैं, बल्कि केवल प्रलेखन में उल्लेख किया गया है (और इस तरह संकलक द्वारा जाँच नहीं की गई है)। जावा का प्रकार प्रणाली किसी भी दिलचस्प गुणों को व्यक्त करने के लिए बस कमजोर है। (यह इस संबंध में एक गतिशील रूप से टाइप की गई भाषा से बहुत अलग नहीं है, वहाँ भी, गुणों को दस्तावेज़ में परिभाषित किया गया है और यह सुनिश्चित करना प्रोग्रामर पर निर्भर है कि वे उल्लंघन नहीं करते हैं।) यह आगे भी जाता है, वास्तव में: आपने ध्यान दिया। यह Collections.sortअपने प्रकार के हस्ताक्षर में भी उल्लेख नहीं करता है कि आउटपुट सॉर्ट किया गया है?
डब्ल्यू पर Jörg W Mittag

1
अधिक अभिव्यंजक प्रकार की प्रणाली वाली भाषा में, वापसी का प्रकार Collections.sortकुछ ऐसा होगा "उसी प्रकार और लंबाई का एक संग्रह जैसा कि गुणों के साथ इनपुट 1) इनपुट में मौजूद प्रत्येक तत्व भी आउटपुट में मौजूद है, 2 ) आउटपुट से तत्वों की प्रत्येक जोड़ी के लिए, बाएं वाला दाएं से अधिक नहीं है, 3) आउटपुट से समान तत्वों के प्रत्येक जोड़े के लिए, इनपुट में बाईं ओर का सूचकांक दाईं ओर से छोटा है "या ऐसा कुछ उस।
जोर्ग डब्ल्यू मित्तग

20

मैं प्रलेखन के बारे में नहीं जानता, लेकिन java.util.Collections#sortजावा 8 (हॉटस्पॉट) का कार्यान्वयन इस प्रकार है:

@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> void sort(List<T> list, Comparator<? super T> c) {
    list.sort(c);
}

और List#sortइस कार्यान्वयन है:

@SuppressWarnings({"unchecked", "rawtypes"})
default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

तो, अंत में, पर्दे के पीछे (वस्तु तत्वों का) Collections#sortउपयोग करता है Arrays#sort। यह कार्यान्वयन मर्ज सॉर्ट या टिम सॉर्ट का उपयोग करता है।


16

Javadoc के अनुसार, Quicksort का उपयोग करके केवल आदिम सरणियों को सॉर्ट किया जाता है। ऑब्जेक्ट सरणियों को एक Mergesort के साथ भी सॉर्ट किया जाता है।

तो कलेक्शंस.सॉर्ट वस्तुओं के लिए Arrays.sort के रूप में एक ही छँटाई एल्गोरिथ्म का उपयोग करने लगता है।

एक और सवाल यह होगा कि ऑब्जेक्ट एरे की तुलना में आदिम सरणियों के लिए एक अलग तरह के एल्गोरिदम का उपयोग क्यों किया जाता है?


2

जैसा कि कई उत्तरों में कहा गया है।

Quicksort का उपयोग आदिम संग्रह को सॉर्ट करने के लिए Arrays.sort द्वारा किया जाता है क्योंकि स्थिरता की आवश्यकता नहीं होती है (यदि आपको पता नहीं होगा या देखभाल नहीं होगी यदि दो समान इन्टर्स को सॉर्ट में स्वैप किया गया था)

MergeSort या अधिक विशेष रूप से Timsort का उपयोग Arrays.sort द्वारा वस्तुओं के संग्रह को सॉर्ट करने के लिए किया जाता है। स्थिरता आवश्यक है। Quicksort स्थिरता के लिए प्रदान नहीं करता है, Timsort करता है।

कलेक्शंस.सॉर्ट, अर्रेसे.सॉर्ट को दर्शाता है, यही वजह है कि आप जार्जॉक को मर्जसॉर्ट का संदर्भ देते हुए देखते हैं।


1

त्वरित सॉर्ट में दो बड़े कमियां हैं जब यह सॉर्ट करने के लिए आता है:

  • यह गैर-आदिम होने की स्थिति में स्थिर नहीं है।
  • यह n लॉग एन प्रदर्शन की गारंटी नहीं देता है।

स्थिरता आदिम प्रकारों के लिए एक गैर-मुद्दा है, क्योंकि समानता (मूल्य) समानता से अलग पहचान की कोई धारणा नहीं है।

मनमानी वस्तुओं को छांटते समय स्थिरता एक बड़ी बात है। यह एक अच्छा पक्ष लाभ है कि मर्ज सॉर्ट एन लॉग एन (समय) के प्रदर्शन की कोई गारंटी नहीं है कि इनपुट क्या है। यही कारण है कि मर्ज सॉर्ट को ऑब्जेक्ट संदर्भों को सॉर्ट करने के लिए एक स्थिर सॉर्ट (मर्ज सॉर्ट) प्रदान करने के लिए चुना जाता है।


1
आपका क्या मतलब है "स्थिर नहीं"?
अरुण गौड़ा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.