न्यूनतम क्यों है, उदाहरण हास्केल एस्कॉर्ट "सच" क्विकसॉर्ट नहीं है?


118

हास्केल की वेबसाइट एक बहुत ही आकर्षक 5-लाइन एस्कॉर्ट फंक्शन पेश करती है , जैसा कि नीचे देखा गया है।

quicksort [] = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
    where
        lesser = filter (< p) xs
        greater = filter (>= p) xs

उनमें "सी में ट्रू क्विकर" भी शामिल है ।

// To sort array a[] of size n: qsort(a,0,n-1)

void qsort(int a[], int lo, int hi) 
{
  int h, l, p, t;

  if (lo < hi) {
    l = lo;
    h = hi;
    p = a[hi];

    do {
      while ((l < h) && (a[l] <= p)) 
          l = l+1;
      while ((h > l) && (a[h] >= p))
          h = h-1;
      if (l < h) {
          t = a[l];
          a[l] = a[h];
          a[h] = t;
      }
    } while (l < h);

    a[hi] = a[l];
    a[l] = p;

    qsort( a, lo, l-1 );
    qsort( a, l+1, hi );
  }
}

C संस्करण के नीचे एक लिंक एक पृष्ठ पर निर्देशित करता है जो बताता है कि 'परिचय में उद्धृत क्विज़ॉर्ट "वास्तविक" क्विकसॉर्ट नहीं है और सी कोड जैसी लंबी सूचियों के लिए स्केल नहीं करता है।'

उपरोक्त हास्केल फ़ंक्शन एक सही क्विकसॉर्ट क्यों नहीं है? यह लंबी सूचियों के लिए पैमाने पर कैसे विफल हो जाता है?


आपको उस सटीक पृष्ठ पर एक लिंक जोड़ना चाहिए, जिसके बारे में आप बात कर रहे हैं।
स्टवेन

14
यह इन-प्लेस नहीं है, इस प्रकार यह काफी धीमा है? अच्छा सवाल!
फ़ूज

4
@FUxxxxl: हास्केल सूचियां अपरिवर्तनीय हैं, इसलिए कोई भी ऑपरेशन डिफ़ॉल्ट डेटाटाइप्स का उपयोग करते हुए इन-प्लेस नहीं होगा। जैसा कि यह गति है - यह जरूरी धीमा नहीं होगा; जीएचसी संकलक प्रौद्योगिकी का एक प्रभावशाली टुकड़ा है और अपरिवर्तनीय डेटा संरचनाओं का उपयोग करते हुए बहुत बार हैस्केल समाधान अन्य भाषाओं में अन्य परिवर्तनशील लोगों के साथ गति करने के लिए हैं।
कैलम रोजर्स

1
क्या यह वास्तव में qsort नहीं है? याद रखें कि qsort का O(N^2)रनटाइम है।
थॉमस एडिंग

2
यह ध्यान दिया जाना चाहिए कि उपरोक्त उदाहरण हास्केल का परिचयात्मक उदाहरण है, और यह कि छांटना सूचियों के लिए एक बहुत ही बुरा विकल्प है। Data.List में छंटनी को 2002 में वापस मर्ज करने के लिए बदल दिया गया था: hackage.haskell.org/packages/archive/base/3.0.3.1/doc/html/src/… , वहां आप पिछले क्विक क्विक इंप्लीमेंटेशन को भी देख सकते हैं। वर्तमान कार्यान्वयन एक विलय है जो 2009 में बनाया गया था: hackage.haskell.org/packages/archive/base/4.4.0.0/doc/html/src/…
हास्केल एलिफेंट

जवाबों:


75

असली एस्कॉर्ट के दो खूबसूरत पहलू हैं:

  1. फूट डालो और जीतो: समस्या को दो छोटी समस्याओं में तोड़ो।
  2. तत्वों को जगह में विभाजित करें।

लघु हास्केल उदाहरण प्रदर्शित करता है (1), लेकिन नहीं (2)। यदि आप पहले से ही तकनीक नहीं जानते हैं तो (2) कैसे किया जा सकता है!



विभाजन के स्थान पर प्रक्रिया के स्पष्ट विवरण के लिए, देखिए इंटरैक्टिवपीथो.ऑन / कौरसेलिब्ज़ / स्टैटिक / फ़ॉथमंड्स / सार्टसर्च /… ।
pvillela

57

हास्केल में ट्रू इनस्पोर्ट क्वॉर्टोर्ट:

import qualified Data.Vector.Generic as V 
import qualified Data.Vector.Generic.Mutable as M 

qsort :: (V.Vector v a, Ord a) => v a -> v a
qsort = V.modify go where
    go xs | M.length xs < 2 = return ()
          | otherwise = do
            p <- M.read xs (M.length xs `div` 2)
            j <- M.unstablePartition (< p) xs
            let (l, pr) = M.splitAt j xs 
            k <- M.unstablePartition (== p) pr
            go l; go $ M.drop k pr

अस्थिरता के लिए स्रोत से पता चलता है कि यह वास्तव में एक ही जगह पर स्वैपिंग तकनीक है (जहाँ तक मैं बता सकता हूँ)।
डैन बर्टन

3
यह समाधान गलत है। unstablePartitionबहुत के समान है partitionके लिए quicksortहै, लेकिन यह गारंटी नहीं है पर तत्व mवें स्थान बस है p
nymk

29

यहाँ हास्केल में "ट्रू" क्विकॉर्ट सी कोड का लिप्यंतरण है। अपने आप को संभालो।

import Control.Monad
import Data.Array.IO
import Data.IORef

qsort :: IOUArray Int Int -> Int -> Int -> IO ()
qsort a lo hi = do
  (h,l,p,t) <- liftM4 (,,,) z z z z

  when (lo < hi) $ do
    l .= lo
    h .= hi
    p .=. (a!hi)

    doWhile (get l .< get h) $ do
      while ((get l .< get h) .&& ((a.!l) .<= get p)) $ do
        modifyIORef l succ
      while ((get h .> get l) .&& ((a.!h) .>= get p)) $ do
        modifyIORef h pred
      b <- get l .< get h
      when b $ do
        t .=. (a.!l)
        lVal <- get l
        hVal <- get h
        writeArray a lVal =<< a!hVal
        writeArray a hVal =<< get t

    lVal <- get l
    writeArray a hi =<< a!lVal
    writeArray a lVal =<< get p

    hi' <- fmap pred (get l)
    qsort a lo hi'
    lo' <- fmap succ (get l)
    qsort a lo' hi

यह मजेदार था, है ना? मैंने वास्तव letमें शुरुआत में इस बड़े को काट दिया , साथ ही whereफ़ंक्शन के अंत में, पूर्ववर्ती कोड को कुछ हद तक सुंदर बनाने के लिए सभी सहायकों को परिभाषित किया।

  let z :: IO (IORef Int)
      z = newIORef 0
      (.=) = writeIORef
      ref .=. action = do v <- action; ref .= v
      (!) = readArray
      (.!) a ref = readArray a =<< get ref
      get = readIORef
      (.<) = liftM2 (<)
      (.>) = liftM2 (>)
      (.<=) = liftM2 (<=)
      (.>=) = liftM2 (>=)
      (.&&) = liftM2 (&&)
  -- ...
  where doWhile cond foo = do
          foo
          b <- cond
          when b $ doWhile cond foo
        while cond foo = do
          b <- cond
          when b $ foo >> while cond foo

और यहां, यह देखने के लिए कि क्या यह काम करता है एक गूंगा परीक्षण।

main = do
    a <- (newListArray (0,9) [10,9..1]) :: IO (IOUArray Int Int)
    printArr a
    putStrLn "Sorting..."
    qsort a 0 9
    putStrLn "Sorted."
    printArr a
  where printArr a = mapM_ (\x -> print =<< readArray a x) [0..9]

मैं हास्केल में बहुत बार अनिवार्य कोड नहीं लिखता, इसलिए मुझे यकीन है कि इस कोड को साफ करने के बहुत सारे तरीके हैं।

तो क्या?

आप देखेंगे कि उपरोक्त कोड बहुत लंबा है। इसका ह्रदय C कोड जितना लंबा होता है, हालाँकि प्रत्येक पंक्ति प्रायः थोड़ी अधिक होती है। इसका कारण यह है कि सी गुप्त रूप से बहुत सी गंदी चीजें करता है जो आपको दी जा सकती हैं। उदाहरण के लिए, a[l] = a[h];। इस परिवर्तनशील चर तक पहुँचता है lऔर h, और फिर अस्थायी सरणी तक पहुँचता है aतो mutates परिवर्तनशील सरणी, और a। पवित्र उत्परिवर्तन, बैटमैन! हास्केल में, उत्परिवर्तन और पहुंच योग्य परिवर्तनशील चर स्पष्ट है। "नकली" qort विभिन्न कारणों से आकर्षक है, लेकिन उनमें से प्रमुख यह है कि यह उत्परिवर्तन का उपयोग नहीं करता है; यह स्व-लगाया प्रतिबंध एक नज़र में समझने में बहुत आसान बनाता है।


3
यह कमाल है, एक तरह से चुटीले तरीके से। मुझे आश्चर्य है कि कोड जीएचसी किस तरह के कुछ से उत्पन्न होता है?
इयान रॉस

@IanRoss: अशुद्ध Quicksort से? GHC वास्तव में काफी सभ्य कोड का उत्पादन करता है।
JD

"नकली" क्यूर्स विभिन्न कारणों से आकर्षक है ... "मुझे डर लगता है कि बिना जगह में हेरफेर के (जैसे कि पहले ही उल्लेख किया गया है) इसका प्रदर्शन भयानक होगा। और हमेशा 1 तत्व को धुरी के रूप में लेने से भी मदद नहीं मिलती है।
dbaltor

25

मेरी राय में, यह कहना कि यह "सच्चा तेज नहीं है" मामले को खत्म कर देता है। मुझे लगता है कि यह क्विकसॉर्ट एल्गोरिथ्म का एक मान्य कार्यान्वयन है , बस एक विशेष रूप से कुशल नहीं है।


9
मेरे पास एक बार किसी के साथ यह तर्क था: मैंने वास्तविक पेपर देखा जो क्विकॉर्ट को निर्दिष्ट करता है, और वास्तव में इन-प्लेस है।
ivanm

2
@ivanm हाइपरलिंक या ऐसा नहीं हुआ :)
डैन बर्टन

1
मुझे पसंद है कि यह पेपर कैसे जरूरी है और इसमें लॉगरिदमिक स्पेस यूज़ की गारंटी देने की ट्रिक भी शामिल है (जिसके बारे में बहुत से लोगों को पता नहीं है) जबकि ALGOL में (अब लोकप्रिय) रिकर्सिव वर्जन सिर्फ एक फुटनोट है। मुझे लगता है कि मैं अब अन्य कागज के लिए देखना होगा ... :)
hugomg

6
किसी भी एल्गोरिथ्म के "मान्य" कार्यान्वयन में समान विषम सीमाएं होनी चाहिए, क्या आपको नहीं लगता है? बस्टर्डाइज्ड हास्केल क्विकॉर्ट मूल एल्गोरिथम की मेमोरी जटिलता में से किसी को संरक्षित नहीं करता है। आस - पास भी नहीं। यही कारण है कि यह सी में सेडगेविक के वास्तविक क्विकॉर्ट की तुलना में 1,000x से अधिक धीमा है
जेडी

16

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


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

16

आलसी मूल्यांकन के लिए धन्यवाद, एक हास्केल कार्यक्रम (लगभग नहीं कर सकता है) ) जैसा वह दिखता है।

इस कार्यक्रम पर विचार करें:

main = putStrLn (show (quicksort [8, 6, 7, 5, 3, 0, 9]))

एक उत्सुक भाषा में, सबसे पहले quicksort, फिर show, तब चलेगाputStrLn । फ़ंक्शन के तर्क की गणना की जाती है, इससे पहले कि फ़ंक्शन चलना शुरू हो जाए।

हास्केल में, यह विपरीत है। फ़ंक्शन पहले चलना शुरू होता है। तर्कों की गणना केवल तब की जाती है जब फ़ंक्शन वास्तव में उनका उपयोग करता है। और एक यौगिक तर्क, एक सूची की तरह, एक समय में एक टुकड़े की गणना की जाती है, क्योंकि इसके प्रत्येक टुकड़े का उपयोग किया जाता है।

तो इस कार्यक्रम में पहली बात यह है किputStrLn चलना शुरू होता है।

जीएचसी केputStrLn कार्यों के कार्यान्वयन को तर्क के पात्रों को कॉपी करके आउटपुट बफर में भेज दिया गया है। लेकिन जब यह इस लूप में प्रवेश करता है, तो showअभी तक नहीं चला है। इसलिए, जब यह स्ट्रिंग से पहले चरित्र को कॉपी करने के लिए जाता है, तो हास्केल उस चरित्र की गणना करने के लिए आवश्यक कॉल showऔर quicksortकॉल के अंश का मूल्यांकन करता है । फिर अगले चरित्र की ओर बढ़ता है। तो सभी तीन कार्यों के निष्पादन ,putStrLnputStrLnshow है, और quicksort- interleaved है। आकस्मिक रूप से quicksortक्रियान्वित होता है, बिना काटे हुए थैलों का एक ग्राफ छोड़ता है क्योंकि यह याद रखता है कि यह कहाँ छूट गया।

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

उदाहरण के लिए, पहले पुनरावर्ती कॉल से पहले सभी डेटा को एस्कॉर्ट विभाजन का सी संस्करण। हास्केल संस्करण में, परिणाम का पहला तत्व गणना किया जाएगा (और यहां तक ​​कि आपकी स्क्रीन पर भी दिखाई दे सकता है) पहले विभाजन के समाप्त होने से पहले - वास्तव में किसी भी काम के पूरा होने से पहले greater

पीएस हास्केल कोड अधिक क्विकर-जैसा होगा अगर यह क्विकर्स के समान तुलना करता है; जैसा कि लिखा गया कोड दो बार कई तुलना करता है क्योंकि lesserऔर greaterस्वतंत्र रूप से गणना करने के लिए निर्दिष्ट किया जाता है, सूची के माध्यम से दो रैखिक स्कैन करता है। बेशक यह संकलक के लिए सिद्धांत में संभव है कि अतिरिक्त तुलना को खत्म करने के लिए पर्याप्त स्मार्ट हो; या कोड का उपयोग करने के लिए बदला जा सकता हैData.List.partition

पीपीएस हास्केल एल्गोरिदम का उत्कृष्ट उदाहरण है कि आप जो व्यवहार की उम्मीद करते हैं, वह यह नहीं है कि आप किस तरह से अनुमान लगा रहे हैं कि आप कंप्यूटिंग प्राइम के लिए एराटोस्थनीज की छलनी हैं


2
lpaste.net/108190 । - यह "पेड़ों की कटाई छंटाई" कर रहा है, इसके बारे में एक पुराना लाल धागा है। सीएफ stackoverflow.com/questions/14786904/… और संबंधित।
विल नेस

1
लगता है हाँ, यह वास्तव में कार्यक्रम क्या करता है की एक बहुत अच्छा लक्षण वर्णन है।
जेसन ओरेंडोर्फ

छलनी टिप्पणी फिर से, यह एक समकक्ष के रूप में लिखा गया था primes = unfoldr (\(p:xs)-> Just (p, filter ((> 0).(`rem` p)) xs)) [2..], इसकी सबसे तत्काल समस्या शायद स्पष्ट होगी। और इससे पहले कि हम सच चलनी एल्गोरिथ्म पर स्विच करने पर विचार करें।
विल नेस

मैं आपकी परिभाषा से भ्रमित हूं कि "कोड जैसा दिखता है वैसा ही होता है"। आपका कोड मुझे "दिखता है" जैसे कि यह कॉल करता है putStrLnजो कि एक सूची शाब्दिक के showथंक वाले एप्लिकेशन का एक ठग आवेदन है quicksort--- और यही वह करता है! (अनुकूलन से पहले --- लेकिन कुछ समय में अनुकूलित कोडांतरक के लिए सी कोड की तुलना करें!)। शायद आपका मतलब है "आलसी मूल्यांकन के लिए धन्यवाद, एक हास्केल कार्यक्रम ऐसा नहीं करता है जो समान-दिखने वाला कोड अन्य भाषाओं में करता है"?
जोनाथन

4
@ जेकास्ट मुझे लगता है कि इस संबंध में सी और हास्केल के बीच एक व्यावहारिक अंतर है। कमेंट थ्रेड में इस तरह के विषय के बारे में एक सुखद बहस करना वास्तव में कठिन है, मैं इसे वास्तविक जीवन में कॉफी से अधिक पसंद करूंगा। मुझे पता है कि अगर आप कभी भी एक घंटे के साथ नैशविले में हैं!
जेसन ओरेंडोर्फ

12

मेरा मानना ​​है कि अधिकांश लोगों का कहना है कि सुंदर हास्केल क्विकॉर्ट एक "सच" नहीं है क्विकॉर्ट्स तथ्य यह है कि यह जगह में नहीं है - स्पष्ट रूप से, यह अपरिवर्तनीय डेटाटिप्स का उपयोग करते समय नहीं हो सकता है। लेकिन यह भी आपत्ति है कि यह "त्वरित" नहीं है: आंशिक रूप से महंगे ++ के कारण, और यह भी क्योंकि एक अंतरिक्ष रिसाव है - आप कम तत्वों पर पुनरावर्ती कॉल करते समय इनपुट सूची पर लटकाते हैं, और कुछ मामलों में - उदाहरण के लिए जब सूची कम हो रही है - यह द्विघात स्थान उपयोग का परिणाम है। (आप कह सकते हैं कि इसे रैखिक स्थान में चलाना निकटतम है जो आप अपरिवर्तनीय डेटा का उपयोग करके "इन-प्लेस" प्राप्त कर सकते हैं।) दोनों समस्याओं के बड़े पैमाने पर समाधान हैं, संचित मापदंडों का उपयोग करना, ट्यूबलिंग और संलयन; रिचर्ड बर्ड का S7.6.1 देखें '


4

यह विशुद्ध रूप से कार्यात्मक सेटिंग्स में तत्वों को बदलने का विचार नहीं है। परिवर्तनशील सरणियों वाले इस सूत्र में वैकल्पिक विधियां पवित्रता की भावना खो देती हैं।

त्वरित-प्रकार के मूल संस्करण (जो कि सबसे अधिक अभिव्यंजक संस्करण है) को अनुकूलित करने के लिए कम से कम दो चरण हैं।

  1. संचयकर्ता द्वारा एक रैखिक ऑपरेशन है, जो संघनन (++) का अनुकूलन करें:

    qsort xs = qsort' xs []
    
    qsort' [] r = r
    qsort' [x] r = x:r
    qsort' (x:xs) r = qpart xs [] [] r where
        qpart [] as bs r = qsort' as (x:qsort' bs r)
        qpart (x':xs') as bs r | x' <= x = qpart xs' (x':as) bs r
                               | x' >  x = qpart xs' as (x':bs) r
  2. डुप्लिकेट तत्वों को संभालने के लिए टर्नरी क्विक सॉर्ट (बेंटले और सेडगविक द्वारा उल्लिखित 3-वे विभाजन) का अनुकूलन करें:

    tsort :: (Ord a) => [a] -> [a]
    tsort [] = []
    tsort (x:xs) = tsort [a | a<-xs, a<x] ++ x:[b | b<-xs, b==x] ++ tsort [c | c<-xs, c>x]
  3. 2 और 3 को मिलाएं, रिचर्ड बर्ड की पुस्तक देखें:

    psort xs = concat $ pass xs []
    
    pass [] xss = xss
    pass (x:xs) xss = step xs [] [x] [] xss where
        step [] as bs cs xss = pass as (bs:pass cs xss)
        step (x':xs') as bs cs xss | x' <  x = step xs' (x':as) bs cs xss
                                   | x' == x = step xs' as (x':bs) cs xss
                                   | x' >  x = step xs' as bs (x':cs) xss

या वैकल्पिक रूप से यदि डुप्लिकेट किए गए तत्व बहुमत नहीं हैं:

    tqsort xs = tqsort' xs []

    tqsort' []     r = r
    tqsort' (x:xs) r = qpart xs [] [x] [] r where
        qpart [] as bs cs r = tqsort' as (bs ++ tqsort' cs r)
        qpart (x':xs') as bs cs r | x' <  x = qpart xs' (x':as) bs cs r
                                  | x' == x = qpart xs' as (x':bs) cs r
                                  | x' >  x = qpart xs' as bs (x':cs) r

दुर्भाग्य से, माध्यिका-तीन को एक ही प्रभाव के साथ लागू नहीं किया जा सकता है, उदाहरण के लिए:

    qsort [] = []
    qsort [x] = [x]
    qsort [x, y] = [min x y, max x y]
    qsort (x:y:z:rest) = qsort (filter (< m) (s:rest)) ++ [m] ++ qsort (filter (>= m) (l:rest)) where
        xs = [x, y, z]
        [s, m, l] = [minimum xs, median xs, maximum xs] 

क्योंकि यह अभी भी निम्नलिखित 4 मामलों के लिए खराब प्रदर्शन करता है:

  1. [१, २, ३, ४, ...., एन]

  2. [एन, एन -1, एन -2, ..., 1]

  3. [एम -1, एम -2, ... 3, 2, 1, एम + 1, एम + 2, ..., एन]

  4. [एन, 1, एन -1, 2, ...]

इन सभी 4 मामलों को अच्छी तरह से अनिवार्य मध्यस्थ-तीन दृष्टिकोण द्वारा नियंत्रित किया जाता है।

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

विस्तार के लिए, कृपया मेरे चल रहे लेखन पर जाएँ : https://sites.google.com/site/algoxy/dcsort


आपके द्वारा याद किया गया एक और अनुकूलन है: उप-सूचियों का उत्पादन करने के लिए 2 फ़िल्टर के बजाय विभाजन का उपयोग करें (या 3 उप-सूचियों का उत्पादन करने के लिए समान आंतरिक फ़ंक्शन पर तह)।
जेरेमी लिस्ट

3

क्या है और क्या नहीं है एक स्पष्ट परिभाषा की कोई स्पष्ट परिभाषा नहीं है।

वे इसे सच्चा क्विकॉर्ट नहीं कह रहे हैं, क्योंकि यह इन-प्लेस को सॉर्ट नहीं करता है:

सी में जगह में सही quicksort


-1

क्योंकि सूची से पहला तत्व लेने पर परिणाम बहुत खराब हो जाते हैं। 3 के माध्यिका का उपयोग करें: पहला, मध्य, अंतिम।


2
सूची यादृच्छिक है तो पहला तत्व लेना ठीक है।
कीथ थॉम्पसन

2
लेकिन सॉर्ट की गई या लगभग सॉर्ट की गई सूची को सॉर्ट करना सामान्य है।
जोशुआ 19

7
लेकिन क्वॉर्ट आईएस O(n^2)
थॉमस

8
qsort औसत n लॉग एन, सबसे खराब n ^ 2 है।
जोशुआ

3
तकनीकी रूप से, यह किसी यादृच्छिक मूल्य को चुनने से बुरा नहीं है जब तक कि इनपुट पहले से सॉर्ट या लगभग हल न हो। खराब पिवोट्स मवाद से दूर होने वाले पिवोट्स हैं; पहला तत्व केवल एक खराब धुरी है यदि यह न्यूनतम या अधिकतम के पास है।
प्लैटिनम एज़्योर

-1

किसी को भी हास्केल में क्विकॉर्ट लिखने के लिए कहें, और आपको अनिवार्य रूप से एक ही कार्यक्रम मिलेगा - यह स्पष्ट रूप से क्विकॉर्ट है। यहाँ कुछ फायदे और नुकसान हैं:

प्रो: यह स्थिर होने के द्वारा "सही" क्विकसॉर्ट पर सुधार करता है, अर्थात यह समान तत्वों के बीच अनुक्रम क्रम को संरक्षित करता है।

प्रो: यह तीन-तरफा विभाजन (<=>) के लिए सामान्यीकृत करने के लिए तुच्छ है, जो कुछ मान O (n) बार होने के कारण द्विघात व्यवहार से बचता है।

प्रो: यह पढ़ना आसान है - भले ही किसी को फ़िल्टर की परिभाषा को शामिल करना पड़े।

Con: यह अधिक मेमोरी का उपयोग करता है।

Con: यह आगे के नमूने द्वारा धुरी पसंद को सामान्य करने के लिए महंगा है, जो कुछ कम-एन्ट्रापी आदेशों पर द्विघात व्यवहार से बच सकता है।

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