छँटाई एल्गोरिदम जो एक यादृच्छिक तुलनित्र स्वीकार करते हैं


22

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

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

मेरी खुरदरी मानसिक गणना से ऐसा प्रतीत होता है कि एक मर्ज सॉर्ट इस के साथ ठीक होगा और समान रनटाइम लागत को बनाए रखेगा और एक उचित यादृच्छिक क्रम का उत्पादन करेगा। मुझे लगता है कि एक त्वरित प्रकार की तरह कुछ हालांकि पतित हो सकता है, संभवतः खत्म नहीं होगा, और उचित नहीं होगा।

एक यादृच्छिक तुलनित्र के साथ वर्णित के रूप में क्या अन्य छँटाई एल्गोरिदम (मर्ज सॉर्ट के अलावा) काम करेगा?


  1. संदर्भ के लिए, एक तुलनित्र एक क्रम संबंध है यदि यह एक उचित कार्य (निर्धारक) है और एक क्रम के स्वयंसिद्धों को संतुष्ट करता है:

    • यह निर्धारक है: compare(a,b)किसी विशेष के लिए aऔर bहमेशा एक ही परिणाम देता है।
    • यह सकर्मक है: compare(a,b) and compare(b,c) implies compare( a,c )
    • यह एंटीसिमेट्रिक है compare(a,b) and compare(b,a) implies a == b

(मान लें कि सभी इनपुट तत्व अलग हैं, इसलिए रिफ्लेक्सिटी कोई समस्या नहीं है।)

एक यादृच्छिक तुलनित्र इन सभी नियमों का उल्लंघन करता है। हालांकि तुलना करने वाले हैं जो अभी तक संबंधों के आदेश नहीं हैं, यादृच्छिक नहीं हैं (उदाहरण के लिए वे शायद केवल एक नियम का उल्लंघन कर सकते हैं, और केवल सेट में विशेष तत्वों के लिए)।


(१) तुलनात्मक कार्य स्थिर होने से आपका क्या अभिप्राय है? (२) क्या "गैर-स्थिर" और "यादृच्छिक" पर्यायवाची हैं?
त्सुकोशी इतो

"उनके आम तौर पर उद्धृत समय जटिलता पर चलाने के (के रूप में सबसे खराब स्थिति के लिए अपमानजनक करने का विरोध किया" - आम तौर पर उद्धृत समय जटिलता है ! बुरी से बुरी हालत "आदेश एक निष्पक्ष यादृच्छिक आदेश होगा" - द्वारा 'निष्पक्ष' आप मतलब वर्दी? आप यह मान है कि तुलनित्र वर्दी, भी है?
राफेल

शायद औपचारिक सिद्धांत में नहीं, लेकिन व्यवहार में (प्रोग्रामिंग भाषाओं में) कई चीजें परिशोधित समय में उद्धृत की जाती हैं। उदाहरण के लिए, क्विकॉर्ट को अक्सर रूप में दिखाया जाता है, लेकिन वास्तव में ( एन 2 ) हैO(logn)O(n2)
eda-qa mort-ora-y

4
@ edA-qamort-ora-y: (1) आपका मतलब , न कि O ( लॉग एन ) । (२) यह " अमूर्त समय " का अर्थ नहीं है; आप का अर्थ है " अपेक्षित समय ", या कम औपचारिक रूप से, "सामान्य समय"। O(nlogn)O(logn)
जेफई

1
किसी ने (ऊपर से) मेरे लिए अधिक दिलचस्प सवाल नहीं उठाया है: जो एल्गोरिदम को छांटता है (यदि कोई हो) संपत्ति है कि यदि तुलनित्र एक सिक्का फ्लिप है, तो परिणाम एक समान क्रमपरिवर्तन है।
जो

जवाबों:


13

तो मूल रूप से, आप जानना चाहते हैं कि क्या कोई छँटाई एल्गोरिथ्म है जो अपने औसत मामले से नीचा नहीं होगा यदि एक समान फ़ंक्शन दिया जाता है:

int Compare(object a, object b) { return Random.Next(-1,1); }

... जहां Random.Next () कुछ विधि है जो एक निर्दिष्ट समावेशी निचले और ऊपरी बाउंड के बीच एक यादृच्छिक रूप से उत्पन्न पूर्णांक का उत्पादन करेगी।

उत्तर वास्तव में यह है कि अधिकांश बुनियादी सॉर्टिंग एल्गोरिदम अपने औसत मामले के अनुसार प्रदर्शन करेंगे, क्योंकि वे निम्नलिखित दो में से कम से कम एक का पालन करते हैं:

  1. दो अद्वितीय तत्वों के बीच की तुलना दो बार कभी भी सॉर्ट में नहीं की जाती है, और / या
  2. सॉर्ट के प्रत्येक पुनरावृत्ति में, कम से कम एक तत्व की सही स्थिति निर्धारित की जाती है और इसलिए उस तत्व की फिर से तुलना नहीं की जाती है।

उदाहरण के लिए, SelectionSort अनसर्टेड तत्वों की उप-सूची के माध्यम से पुनरावृत्ति करता है, "कम से कम" और / या "सबसे बड़ा" तत्व पाता है (प्रत्येक को अब तक की सबसे बड़ी तुलना करके), इसे अपनी सही स्थिति में रखता है और दोहराता है। नतीजतन, एक गैर-निर्धारक तुलनित्र के साथ भी, प्रत्येक पुनरावृत्ति के अंत में एल्गोरिथ्म को एक ऐसा मूल्य मिलेगा जो यह सोचता है कि यह कम से कम या सबसे बड़ा है, इसे उस तत्व के साथ स्वैप करता है जिस स्थिति में यह निर्धारित करने की कोशिश कर रहा है, और कभी भी विचार नहीं करता है। वह तत्व फिर से, इस प्रकार यह शर्त 2 का पालन करता है। हालांकि, इस प्रक्रिया के दौरान कई बार ए और बी की तुलना की जा सकती है (सबसे चरम उदाहरण के रूप में, एक सरणी पर SelectionSort के कई पास पर विचार करें जो रिवर्स ऑर्डर में क्रमबद्ध है) इसलिए यह शर्त का उल्लंघन करता है 1 ।

MergeSort ने शर्त 1 का पालन किया लेकिन 2 नहीं; जैसा कि उप-सरणियों को विलय किया जाता है, एक ही उप-सरणी (बाईं या दाईं ओर) में तत्वों की एक-दूसरे से तुलना नहीं की जाती है क्योंकि यह पहले से ही निर्धारित किया गया है कि सरणी के उस तरफ के तत्व आपस में क्रम में हैं; एल्गोरिथ्म केवल यह निर्धारित करने के लिए प्रत्येक उप-श्रेणी के कम से कम अनारक्षित तत्व की तुलना करता है जो कम है और विलय की सूची में आगे जाना चाहिए। इसका मतलब यह है कि किसी भी दो अद्वितीय वस्तुओं ए और बी की एक दूसरे से अधिकतम एक समय की तुलना की जाएगी, लेकिन पूर्ण संग्रह में किसी भी दिए गए तत्व के "अंतिम" सूचकांक को तब तक नहीं जाना जाता है जब तक कि एल्गोरिथ्म पूरा नहीं हो जाता है।

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

QuickSort दोनों का पालन करता हैशर्तेँ। प्रत्येक स्तर पर, एक धुरी को चुना जाता है और इस तरह से व्यवस्थित किया जाता है कि "बाईं ओर" में धुरी से कम तत्व होते हैं और "दाएं" पक्ष में धुरी से अधिक तत्व होते हैं। उस स्तर का परिणाम QuickSort (बायाँ) + pivot + QuickSort (दाएँ) है जिसका मूल अर्थ है कि धुरी तत्व की स्थिति ज्ञात है (बाईं ओर की लंबाई से अधिक एक सूचकांक), किसी भी अन्य तत्व की तुलना में धुरी कभी नहीं होती है बाद में इसे एक धुरी के रूप में चुना गया है (इसकी तुलना पिछले धुरी तत्वों के साथ की जा सकती है, लेकिन उन तत्वों को भी जाना जाता है और किसी भी उपधारा में शामिल नहीं किया जाता है), और कोई भी A और B जो धुरी के विपरीत छोर पर रहते हैं, वे कभी नहीं होते हैं की तुलना में। शुद्ध क्विकॉर्ट के अधिकांश कार्यान्वयन में, आधार मामला एक तत्व है, जिसके बिंदु पर इसका वर्तमान सूचकांक इसका अंतिम सूचकांक है और आगे कोई तुलना नहीं की जाती है।

(2/3)N1)। जैसे ही तुलनित्र के परिणाम का अधिकतम निरपेक्ष मान बढ़ता है, किसी एक की तुलना नकारात्मक या शून्य पर लौटने की संभावना घट जाती है ।5, एल्गोरिथ्म को समाप्त करने का मौका बनाता है कि बहुत कम संभावना (99 सिक्का का मौका सभी लैंडिंग सिर झटकता है। , जो मूल रूप से यह उबलता है, 1.2 में से 1 * 10 30 है )

संपादित करें एक लंबा समय लेटर: कुछ "प्रकार" हैं जो विशेष रूप से उदाहरण के लिए डिज़ाइन किए गए हैं जो ऐसा नहीं करने के लिए जो एक यादृच्छिक तुलनित्र को शामिल करते हैं; शायद सबसे प्रसिद्ध BogoSort है। "एक सूची को देखते हुए, यदि सूची क्रम में नहीं है, तो सूची को फेरबदल करें और फिर से जांचें"। सैद्धांतिक रूप से यह अंततः मूल्यों के सही क्रमचय पर प्रहार करेगा , ऊपर "गैर-अनुकूलित बबलसॉर्ट" की तरह, लेकिन औसत मामला तथ्यात्मक-समय (एन! / 2) है, और जन्मदिन की समस्या के कारण (पर्याप्त यादृच्छिक सत्यापन के बाद) अनूठे लोगों की तुलना में डुप्लिकेट क्रमपरिवर्तन का सामना करने की अधिक संभावना बन जाती है) एल्गोरिथ्म की एक गैर-छिपी संभावना है कि आधिकारिक तौर पर एल्गोरिथ्म कभी पूरा नहीं होता है समय-निर्बाध।


क्या स्थिति 2 भी त्वरित प्रकार को कवर करेगी? या यह प्रत्येक पुनरावृत्ति के बारे में एक तीसरी स्थिति से अधिक होगा जो पिछले से छोटा है।
eda-qa mort-ora-y

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

शानदार जवाब, लेकिन मैं बबलॉर्ट के बारे में आपसे सहमत नहीं हूं। एक सुसंगत तुलनित्र का उपयोग करते समय, i-th पुनरावृत्ति पर बबलसॉर्ट जानता है कि i-1 अंतिम तत्व अपने अंतिम स्थान पर हैं, और बबलोर्ट का कोई भी उचित कार्यान्वयन प्रत्येक पुनरावृत्ति से कम तत्वों से गुजरेगा, इसलिए इसे nerations के बाद भी रोकना चाहिए ।
बोरिस ट्रेवास

कुछ और विचार के बाद मैं आपसे सहमत होना चाहूंगा; X पास होने के बाद, सबसे बड़ा X मान उनकी उचित जगह पर है, इसलिए आप प्रत्येक पास पर समस्या स्थान को कम कर सकते हैं और इसलिए एक कुशल एल्गोरिथ्म शर्त 2 का पालन करेगा। मैं संपादित करूँगा
किथ्स

आपको क्विकसर्ट कार्यान्वयन के साथ सावधान रहना होगा। एक धारणा हो सकती है कि धुरी से कम नहीं वाले तत्व की तलाश तब खत्म होगी जब हम धुरी या किसी तत्व की धुरी से अधिक से मुठभेड़ करेंगे; यह जरूरी नहीं होगा।
gnasher729

10

O(n2)

n


संपादित करें: जैसा कि मैंने पहले सोचा था कि समस्या अधिक दिलचस्प है, इसलिए यहां एक और टिप्पणी है:

comparecompare(x,y)=true1/2false1/2

insert x [] = [x]
insert x y:ys = if x < y then x:y:ys
                else y:insert x ys

sort_aux l e = match l with
                 [] -> e
                 x:xs -> sort_aux xs (insert x ys)

sort l = sort_aux l []

k=1nf(k)nlf(k)insertk:

compare

i=1ki2ii=1i2i=2

O(2n)O(n2)

इस समान तुलनात्मक कार्य को देखते हुए विभिन्न अन्य एल्गोरिदम के लिए औसत चलने वाले समय को काम करना मजेदार होगा।


यदि एक ही तत्व को एक से अधिक बार धुरी के रूप में चुना जाता है (यह सूची में कई बार हो सकता है) तो क्विकॉर्ट्स तुलनाओं को दोहरा सकते हैं।
राफेल

2
@ राफेल: शब्दों की मेरी पसंद खराब थी: मेरा मतलब था कि तत्वों की घटनाओं के बीच की तुलना , जो क्विकॉर्ट में एक से अधिक बार नहीं होती है।
कोड़ी

1
@ गिल्स: मैं गलत हो सकता हूं, लेकिन मुझे विश्वास नहीं है कि तुलनात्मक रूप से परिवर्तनशीलता सबसे अधिक सॉर्टिंग एल्गोरिदम के रनटाइम के लिए महत्वपूर्ण है ; शुद्धता निश्चित रूप से, लेकिन यह सवाल का उद्देश्य नहीं था।
कोड़ी

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

@ जेफ़े मैं समझता हूँ कि अब। यह नहीं है कि मैं शुरू में सवाल कैसे पढ़ता हूं, लेकिन पूछने वाले की टिप्पणियों को देखते हुए, यही था।
गिल्स एसओ- बुराई को रोकना '

2

एक निष्पक्ष यादृच्छिक तुलनित्र के साथ विलय उचित नहीं है। मेरे पास कोई सबूत नहीं है, लेकिन मेरे पास बहुत मजबूत अनुभवजन्य साक्ष्य हैं। (मेले का अर्थ है समान रूप से वितरित किया गया।)

module Main where

import Control.Monad
import Data.Map (Map)
import qualified Data.Map as Map
import System.Random (randomIO)

--------------------------------------------------------------------------------

main :: IO ()
main = do
  let xs = [0..9]
  xss <- replicateM 100000 (msortRand xs)
  print $ countFrequencies xss

msortRand :: [a] -> IO [a]
msortRand = msort (\_ _ -> randomIO)

countFrequencies :: (Ord a) => [[a]] -> [Map a Int]
countFrequencies [] = []
countFrequencies xss = foldr (\k m -> Map.insertWith (+) k 1 m) Map.empty ys : countFrequencies wss
  where
    ys = map head xss
    zss = map tail xss
    wss = if head zss == []
      then []
      else zss

--------------------------------------------------------------------------------

msort :: (Monad m) => (a -> a -> m Bool) -> [a] -> m [a]
msort (<) [] = return []
msort (<) [x] = return [x]
msort (<) xs = do
  ys' <- msort (<) ys
  zs' <- msort (<) zs
  merge (<) ys' zs'
  where
    (ys, zs) = split xs

merge :: (Monad m) => (a -> a -> m Bool) -> [a] -> [a] -> m [a]
merge (<) [] ys = return ys
merge (<) xs [] = return xs
merge (<) (x:xs) (y:ys) = do
  bool <- x < y
  if bool
    then liftM (x:) $ merge (<) xs (y:ys)
        else liftM (y:) $ merge (<) (x:xs) ys

split :: [a] -> ([a], [a])
split [] = ([], [])
split [x] = ([x], [])
split (x:y:zs) = (x:xs, y:ys)
  where
    (xs, ys) = split zs

क्या हस्केल या कैमल अब फैशन में है?
यय

मुझे पता नहीं है। लेकिन हास्केल मेरी एक पसंदीदा भाषा है, इसलिए मैंने इसमें यह प्रोग्राम किया; पैटर्न मिलान ने इसे आसान बना दिया।
थॉमस ईडिंग

0

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

अमूर्त से उद्धरण:

...

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

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

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