पाइथन के साथ क्विकॉर्ट
वास्तविक जीवन में, हमें हमेशा पायथन द्वारा प्रदान किए गए बिलिन प्रकार का उपयोग करना चाहिए। हालाँकि, क्विकसॉर्ट एल्गोरिथम को समझना शिक्षाप्रद है।
यहाँ मेरा लक्ष्य इस विषय को तोड़ना है जैसे कि यह आसानी से समझ में आता है और पाठक द्वारा संदर्भ सामग्री पर वापस जाने के बिना प्रतिरूप है।
Quicksort एल्गोरिथ्म अनिवार्य रूप से निम्नलिखित है:
- एक पिवट डेटा पॉइंट चुनें।
- सभी डेटा बिंदुओं को धुरी से नीचे की स्थिति की तुलना में कम (नीचे) की ओर ले जाएँ - उन लोगों को धुरी से ऊपर या ऊपर (ऊपर) की स्थिति में ले जाएँ।
- एल्गोरिथ्म को धुरी के ऊपर और नीचे के क्षेत्रों में लागू करें
यदि डेटा को बेतरतीब ढंग से वितरित किया जाता है, तो पहला डेटा बिंदु चुनना क्योंकि धुरी एक यादृच्छिक चयन के बराबर है।
पठनीय उदाहरण:
सबसे पहले, एक पठनीय उदाहरण देखें, जो मध्यवर्ती मूल्यों को इंगित करने के लिए टिप्पणियों और चर नामों का उपयोग करता है:
def quicksort(xs):
"""Given indexable and slicable iterable, return a sorted list"""
if xs:
pivot = xs[0]
below = [i for i in xs[1:] if i < pivot]
above = [i for i in xs[1:] if i >= pivot]
return quicksort(below) + [pivot] + quicksort(above)
else:
return xs
यहां प्रदर्शित एल्गोरिथ्म और कोड को पुनर्स्थापित करने के लिए - हम धुरी के ऊपर मूल्यों को दाईं ओर ले जाते हैं, और धुरी के बाईं ओर नीचे मान, और फिर उन विभाजनों को पास करने के लिए समान फ़ंक्शन को पास करते हैं।
golfed:
यह 88 वर्णों के लिए गढ़ा जा सकता है:
q=lambda x:x and q([i for i in x[1:]if i<=x[0]])+[x[0]]+q([i for i in x[1:]if i>x[0]])
यह देखने के लिए कि हम वहाँ कैसे पहुँचते हैं, पहले अपना पठनीय उदाहरण लेते हैं, टिप्पणियों और डोकस्ट्रिंग्स को हटाते हैं, और पिवट इन-प्लेस पाते हैं:
def quicksort(xs):
if xs:
below = [i for i in xs[1:] if i < xs[0]]
above = [i for i in xs[1:] if i >= xs[0]]
return quicksort(below) + [xs[0]] + quicksort(above)
else:
return xs
अब नीचे और ऊपर, इन-प्लेस खोजें:
def quicksort(xs):
if xs:
return (quicksort([i for i in xs[1:] if i < xs[0]] )
+ [xs[0]]
+ quicksort([i for i in xs[1:] if i >= xs[0]]))
else:
return xs
अब, यह जानते हुए कि and
यदि गलत है, तो पूर्व तत्व को लौटाता है, यदि यह सत्य है, तो यह निम्नलिखित तत्व का मूल्यांकन करता है और लौटाता है, हमारे पास:
def quicksort(xs):
return xs and (quicksort([i for i in xs[1:] if i < xs[0]] )
+ [xs[0]]
+ quicksort([i for i in xs[1:] if i >= xs[0]]))
चूंकि लैम्ब्डा एक एकल प्रतिक्षेप लौटाता है, और हमने एक एकल अभिव्यक्ति को सरल बनाया है (भले ही यह अधिक अपठनीय है) अब हम एक लैम्ब्डा का उपयोग कर सकते हैं:
quicksort = lambda xs: (quicksort([i for i in xs[1:] if i < xs[0]] )
+ [xs[0]]
+ quicksort([i for i in xs[1:] if i >= xs[0]]))
और हमारे उदाहरण को कम करने के लिए, फ़ंक्शन और चर नामों को एक अक्षर पर छोटा करें, और व्हाट्सएप को समाप्त करें जिसकी आवश्यकता नहीं है।
q=lambda x:x and q([i for i in x[1:]if i<=x[0]])+[x[0]]+q([i for i in x[1:]if i>x[0]])
ध्यान दें कि यह लैम्बडा, अधिकांश कोड गोल्फिंग की तरह, बल्कि बुरी शैली है।
इन-प्लेस क्विकॉर्ट, होरे विभाजन योजना का उपयोग करते हुए
पूर्व कार्यान्वयन अनावश्यक अतिरिक्त सूचियों का एक बहुत बनाता है। अगर हम ऐसा कर सकते हैं, तो हम जगह बर्बाद करने से बचेंगे।
नीचे कार्यान्वयन होरे विभाजन योजना का उपयोग करता है, जिसे आप विकिपीडिया के बारे में अधिक पढ़ सकते हैं (लेकिन हमने स्पष्ट रूप से प्रति partition()
कॉल के बजाय लूप शब्दार्थ का उपयोग करके और कॉलिंग चरणों को समाप्त करने के लिए चलते हुए प्रति कॉल पर 4 निरर्थक गणनाओं को हटा दिया है बाहरी जबकि लूप।)।
def quicksort(a_list):
"""Hoare partition scheme, see https://en.wikipedia.org/wiki/Quicksort"""
def _quicksort(a_list, low, high):
if low < high:
p = partition(a_list, low, high)
_quicksort(a_list, low, p)
_quicksort(a_list, p+1, high)
def partition(a_list, low, high):
pivot = a_list[low]
while True:
while a_list[low] < pivot:
low += 1
while a_list[high] > pivot:
high -= 1
if low >= high:
return high
a_list[low], a_list[high] = a_list[high], a_list[low]
low += 1
high -= 1
_quicksort(a_list, 0, len(a_list)-1)
return a_list
यकीन नहीं होता कि मैंने इसे पूरी तरह से जांच लिया है:
def main():
assert quicksort([1]) == [1]
assert quicksort([1,2]) == [1,2]
assert quicksort([1,2,3]) == [1,2,3]
assert quicksort([1,2,3,4]) == [1,2,3,4]
assert quicksort([2,1,3,4]) == [1,2,3,4]
assert quicksort([1,3,2,4]) == [1,2,3,4]
assert quicksort([1,2,4,3]) == [1,2,3,4]
assert quicksort([2,1,1,1]) == [1,1,1,2]
assert quicksort([1,2,1,1]) == [1,1,1,2]
assert quicksort([1,1,2,1]) == [1,1,1,2]
assert quicksort([1,1,1,2]) == [1,1,1,2]
निष्कर्ष
यह एल्गोरिथ्म अक्सर कंप्यूटर विज्ञान पाठ्यक्रमों में पढ़ाया जाता है और नौकरी के लिए साक्षात्कार के लिए कहा जाता है। यह हमें पुनरावृत्ति और विभाजन और जीत के बारे में सोचने में मदद करता है।
पाइथन में क्विकॉर्ट बहुत व्यावहारिक नहीं है क्योंकि हमारी बिल्ट टाइमसॉर्ट एल्गोरिथ्म काफी कुशल है, और हमारे पास पुनरावृत्ति सीमाएं हैं। हम सूची को इन-प्लेस के साथ सॉर्ट करने list.sort
या नई सॉर्ट की गई सूचियों को बनाने की अपेक्षा करेंगे sorted
- जिनमें से दोनों में तर्क key
और reverse
तर्क हो।
my_list = list1 + list2 + ...
। या नई सूची में अनपैक सूचीmy_list = [*list1, *list2]