रेडिक्स सॉर्ट का उपयोग अधिक बार क्यों नहीं किया जाता है?


31

यह स्थिर है और O (n) की समय जटिलता है। यह क्विकसॉर्ट और मर्जसॉर्ट जैसे एल्गोरिदम से अधिक तेज होना चाहिए, फिर भी मैं शायद ही कभी इसका इस्तेमाल करता हूं।


2
यहाँ देखें: en.wikipedia.org/wiki/Radix_sort#Efficiency दक्षता O (kn) है और यह O (n * log (n)) से बेहतर नहीं हो सकती है।
FrustratedWithFormsDesigner

2
मूलांक सॉर्ट का उपयोग अक्सर सॉफ्ट रियल-टाइम सिस्टम जैसे गेम में किया जाता है। एक एल्गोरिथ्म एक या दूसरे से बेहतर प्रदर्शन करता है या नहीं, हमेशा की तरह, समस्या के सभी मापदंडों पर निर्भर करता है, न कि केवल जटिलता बाध्य होती है
awdz9nld

@FrustratedWithFormsDesigner शायद विकी बदल गया है? मुझे अब 'एन लॉग (एन) ,
एफडब्ल्यूआईडब्ल्यू

बूस्ट का एक (इसके स्थान पर संस्करण) है: boost.org/doc/libs/1_62_0/libs/sort/doc/html/sort/sort_hpp.html लेकिन हाँ, मुझे लगता है कि मुझे पता नहीं है कि यह मौजूद नहीं है ... या तो वे या वे सभी "मानक" सॉर्टिंग एल्गोरिथ्म का उपयोग करते हैं, जो भी कारण के लिए, फ्रेमवर्क निर्माता अभी भी "जेनेरिक" प्रकारों का फिर से उपयोग करते हैं जो उतना कुशल नहीं हैं ... शायद वे सॉर्टिंग चींटियों पर ध्यान केंद्रित नहीं करते हैं। आम तौर पर, चूंकि यह एक दुर्लभ उपयोग मामला है?
रोज़गारपैक

जवाबों:


38

मूलांक प्रकार के विपरीत, क्विकॉर्ट सार्वभौमिक है, जबकि रेडिक्स सॉर्ट केवल फिक्स लंबाई पूर्णांक कुंजी के लिए उपयोगी है।

इसके अलावा, आपको यह समझना होगा कि O (f (n)) वास्तव में K * f (n) के क्रम में है, जहां K कुछ मनमाना स्थिरांक है। मूलांक सॉर्ट के लिए यह K काफी बड़ा होता है (कम से कम क्रमबद्ध बिट्स की संख्या में क्रमबद्ध), दूसरी ओर क्विकसॉर्ट में सभी छंटाई एल्गोरिदम और n * लॉग (n) की औसत जटिलता के बीच सबसे कम K है। इस प्रकार वास्तविक जीवन परिदृश्य में रेडिक्स सॉर्ट की तुलना में क्विकॉर्ट बहुत तेजी से होगा।


नोट की गई जटिलता पर ध्यान दें: हालाँकि (LSD) रेडिक्स सॉर्ट में O (n * K) की जटिलता है, यह स्थिरांक आमतौर पर छोटा होता है, आमतौर पर ऐसा चुना जाता है (2 ^ (W / K)) * C L1 में फिट बैठता है, जहाँ C काउंटर के बाइट्स में आकार है, डब्ल्यू के आकार को सॉर्ट किया जा रहा है। अधिकांश कार्यान्वयन x86 पर 32-बिट शब्दों के लिए K = [3,4] चुनते हैं। K को अस्थायी सामंजस्य (निकट-क्रमबद्धता) के दोहन के लिए अनुकूल बनाया जा सकता है, क्योंकि प्रत्येक मूलांक को व्यक्तिगत रूप से क्रमबद्ध किया जाता है।
awdz9nld

11
सार्वभौमिकता पर ध्यान दें: मूलांक सॉर्ट फ़्लोटिंग-पॉइंट कुंजियों के साथ-साथ चर-लंबाई पूर्णांक कुंजियों पर काम करने में पूरी तरह सक्षम है
awdz9nld

20

अधिकांश छंटाई एल्गोरिदम सामान्य उद्देश्य हैं। एक तुलनात्मक कार्य को देखते हुए, वे कुछ भी काम करते हैं, और क्विकॉर्ट और हीप्सर्ट जैसे एल्गोरिदम ओ (1) अतिरिक्त मेमोरी के साथ सॉर्ट करेंगे।

मूलांक छांटना अधिक विशिष्ट है। आपको लेक्सिकोग्राफ़िक क्रम में एक विशिष्ट कुंजी की आवश्यकता है। आपको कुंजी में प्रत्येक संभावित प्रतीक के लिए एक बाल्टी की आवश्यकता है, और बाल्टी को बहुत सारे रिकॉर्ड रखने की आवश्यकता है। (वैकल्पिक रूप से, आपको एक बड़ी सरणी बकेट की आवश्यकता है जो हर संभव कुंजी मान रखेगा।) आपको मूलांक सॉर्ट करने के लिए बहुत अधिक मेमोरी की आवश्यकता है, और आप इसे बेतरतीब ढंग से उपयोग करने जा रहे हैं। न तो यह आधुनिक कंप्यूटरों के लिए अच्छा है, क्योंकि आपको पृष्ठ दोष प्राप्त होने की संभावना है जैसे क्विकॉर्ट को कैश मिस मिलेगा।

अंत में, लोग सामान्य रूप से किसी भी प्रकार के अपने स्वयं के एल्गोरिदम नहीं लिखते हैं। अधिकांश भाषाओं में क्रमबद्ध करने के लिए पुस्तकालय की सुविधा होती है, और उन्हें उपयोग करने के लिए सामान्य रूप से सही बात है। चूंकि मूलांक सॉर्ट सार्वभौमिक रूप से लागू नहीं है, आमतौर पर वास्तविक उपयोग के अनुरूप होना चाहिए, और बहुत सारी अतिरिक्त मेमोरी का उपयोग करता है, इसे लाइब्रेरी फ़ंक्शन या टेम्पलेट में डालना मुश्किल है।


दरअसल, बाएं और दाएं विभाजन पर पुनरावर्ती कॉल के O(n^2)कारण क्विकर को सबसे खराब स्थिति में स्मृति की आवश्यकता होती है n। यदि कार्यान्वयन पूंछ पुनर्संरचना अनुकूलन का उपयोग करता है, तो इसे कम किया जा सकता है O(n)क्योंकि सही विभाजन के लिए कॉल के लिए अतिरिक्त स्थान की आवश्यकता नहीं होगी। ( en.wikipedia.org/wiki/Quicksort#Space_complexity )
Chaos

S(n) \in O(n)रेडिक्स के साथ छाँटने के लिए आपको केवल स्थान की आवश्यकता होती है , यानी ढेर या त्वरित प्रकार के लिए।
वेलदा

@SplinterofChaos शायद विकी बदल गया है? यह n^2quicksort के लिए अब और नहीं लगता है , लेकिन O(log n)...
19

मुझे नहीं लगता कि यह "बहुत" अधिक मेमोरी है, शायद 2 * एन (ठीक है कि बहुत अधिक है लेकिन शायद असंभव नहीं है)? और बाल्टियाँ इतनी छोटी हैं (मान लें कि आप बाइट्स पर बंट रहे हैं और दोहरा रहे हैं) कि यह कैश में अच्छी तरह से फिट हो सकती है?
रॉगरडैक

5

यह काफी दुर्लभ है कि आपके द्वारा छांटी गई चाबियाँ वास्तव में एक ज्ञात, विरल सीमा में पूर्णांक हैं। आमतौर पर आपके पास वर्णानुक्रमिक क्षेत्र होते हैं, जो ऐसा लगता है कि वे गैर-तुलनात्मक छँटाई का समर्थन करेंगे, लेकिन चूंकि वास्तविक दुनिया के तार वर्णमाला में समान रूप से वितरित नहीं होते हैं, इसलिए यह सिद्धांत रूप में भी काम नहीं करता है।

अन्य समय में, मानदंड को केवल परिचालनात्मक रूप से परिभाषित किया जाता है (दो रिकॉर्ड दिए गए हैं, आप तय कर सकते हैं कि कौन पहले आता है, लेकिन आप यह आकलन नहीं कर सकते कि एक अलग रिकॉर्ड के पैमाने के नीचे 'दूर' कैसे है)। इसलिए विधि अक्सर लागू नहीं होती है, जितना आप विश्वास कर सकते हैं उससे कम लागू होता है, या ओ (एन * लॉग (एन)) की तुलना में किसी भी तेजी से नहीं।


मूलांक सॉर्टर्स किसी भी सीमा में पूर्णांकों (या स्ट्रिंग्स) को "एक समय में एक बाइट" की तरह छाँट कर संभाल सकता है, इसलिए उन्हें विरल रेंज में नहीं होना चाहिए FWIW ...
rogerdpack

4

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

एक मूल उदाहरण एक खोज या मध्य भाग के भाग के रूप में दिए गए आयाम द्वारा अंक या किसी त्वरित तरीके से संयोग बिंदुओं का पता लगाने के लिए एक त्वरित तरीका है, गहराई सॉर्टिंग टुकड़े, या कई छोरों में उपयोग किए गए सूचकांकों की एक सरणी को छांटने के लिए रेडी-फ्रेंडली एक्सेस प्रदान करने के लिए उपयोग किया जाता है। पैटर्न (स्मृति में आगे-पीछे नहीं और केवल फिर से वापस जाने के लिए और उसी मेमोरी को कैश लाइन में पुनः लोड करें)। मेरे डोमेन (कंप्यूटर ग्राफिक्स) में कम-से-कम 32-बिट और 64-बिट संख्यात्मक कुंजियों को छांटने के लिए बहुत विस्तृत अनुप्रयोग है।

एक बात जो मैं पिच करना चाहता था और कहना चाहता हूं कि मूलांक क्रम फ्लोटिंग-पॉइंट नंबरों और निगेटिव पर काम कर सकता है, हालांकि एफपी संस्करण को लिखना मुश्किल है जो यथासंभव पोर्टेबल है। इसके अलावा, यह O (n * K) है, K को केवल कुंजी आकार के बाइट की संख्या होनी चाहिए (उदा: एक मिलियन 32-बिट पूर्णांक आमतौर पर 4 बाइट-आकार के पास ले जाएगा यदि बाल्टी में 2 ^ 8 प्रविष्टियां हों )। मेमोरी एक्सेस पैटर्न भी क्विकॉर्ट्स की तुलना में बहुत अधिक कैशे-फ्रेंडली होता है, भले ही उसे एक समानांतर एरे और एक छोटे बकेट ऐरे की जरूरत होती है (दूसरा आमतौर पर स्टैक पर बस ठीक बैठ सकता है)। छिटपुट रैंडम-एक्सेस पैटर्न वाले एक मिलियन पूर्णांकों की एक सरणी को सॉर्ट करने के लिए QS 50 मिलियन स्वैप कर सकता है। मूलांक सॉर्ट कर सकते हैं कि 4 रैखिक में, कैश-फ्रेंडली डेटा के ऊपर से गुजरता है।

हालाँकि, फ्लोटिंग-पॉइंट के साथ-साथ ऋणात्मक संख्याओं पर एक छोटी सी K के साथ ऐसा करने में जागरूकता की कमी, मूलांक की लोकप्रियता की कमी में महत्वपूर्ण योगदान दे सकती है।

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

कुछ बेंचमार्क:

Sorting 10000000 elements 3 times...

mt_sort_int: {0.135 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]

mt_radix_sort: {0.228 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]

std::sort: {1.697 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]

qsort: {2.610 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]

और यह सिर्फ मेरे भोले कार्यान्वयन के साथ है ( mt_sort_intयह भी मूलांक छंटनी है लेकिन कोड की एक तेज़ शाखा के साथ यह दिया गया है कि यह मान सकता है कि कुंजी एक पूर्णांक है)। कल्पना कीजिए कि विशेषज्ञों द्वारा लिखित एक मानक कार्यान्वयन कितनी तेजी से हो सकता है।

एकमात्र मामला जहां मुझे C ++ की तुलना में मूलांक अधिक खराब लगता है, वास्तव में तेजी से तुलना-आधारित std::sortतत्व वास्तव में बहुत कम संख्या में तत्वों के लिए था, 32 का कहना है, जिस बिंदु पर मेरा मानना ​​है std::sortकि सबसे छोटी संख्या जैसे तत्वों या अन्य तत्वों के लिए बेहतर अनुकूलता का उपयोग करना शुरू होता है। सम्मिलन प्रकार, हालांकि उस बिंदु पर मेरा कार्यान्वयन सिर्फ उपयोग करता है std::sort


1
क्षेत्र में अनुभव वाले लोगों की राय सुनने के लिए हमेशा अच्छा होता है।
फ्रैंक हिलमैन

प्रतीत होता है कि mt_ बहु थ्रेडेड कार्यान्वयन हैं: softwareengineering.stackexchange.com/a/362097/65606
rogerdpack

1

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

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

इन दिनों इस तरह के बिग-डेटा मुद्दों को चलाने में बहुत मुश्किल है, मैं शायद फिर कभी ऐसा कुछ नहीं लिखूंगा। (अगर मैं इन दिनों उसी डेटा के साथ सामना कर रहा था तो मैं बस 64-बिट OS निर्दिष्ट करूँगा, अगर आप उस संपादक में थ्रैशिंग प्राप्त करते हैं तो RAM जोड़ें।)


कभी-कभी उल्लेख किए गए मूलांक के अनुसार होने वाले नुकसानों में से एक को देखते हुए, "अधिक स्थान लेता है।" अभी भी मेरे सिर को इस के चारों ओर लपेटने की कोशिश कर रहा है ...
rogerdpack

1
@rogerdpack यह नहीं था कि मेरे दृष्टिकोण ने कम जगह का उपयोग किया, यह है कि यह डेटा तक कम पहुंच का उपयोग करता है। मैं एक फ़ाइल को सॉर्ट कर रहा था जो कंपाइलर लिमिट (यह डॉस प्रोटेक्टेड मोड था, विंडोज का नहीं) के कोड के कुल मेमोरी के 16mb से कम के साथ और 64kb की स्ट्रक्चर लिमिट के साथ काम करते हुए एक गीगाबाइट के आसपास था।
लोरेन Pechtel

-1

यदि आपके सभी पैरामीटर पूर्णांक हैं और यदि आपके पास 1024 से अधिक इनपुट पैरामीटर हैं, तो मूलांक क्रम हमेशा तेज होता है।

क्यूं कर?

Complexity of radix sort = max number of digits x number of input parameters.

Complexity of quick sort = log(number of input parameters) x   number of input parameters

इसलिए जब मूलांक छांटना तेज होता है

log(n)> max num of digits

जावा में अधिकतम पूर्णांक 2147483647 है। जो 10 अंकों का है

इसलिए मूलांक छांटना हमेशा तेज होता है

log(n)> 10

इसलिए मूलांक छांटना हमेशा तेज होता है n>1024


कार्यान्वयन विवरण में छिपे हुए स्थिरांक हैं, लेकिन मूल रूप से आप कह रहे हैं "बड़े इनपुट के लिए मूलांक छांटना तेज है" जो कि ... होना चाहिए! यह इसके लिए उपयोग के मामलों को खोजने के लिए सिर्फ मुश्किल है लेकिन जब आप कर सकते हैं ...
rogerdpack
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.