Quicksort ด้วย Python


95

ฉันใหม่มากกับ python และฉันกำลังพยายามใช้ Quicksort ในนั้น ใครช่วยกรุณาช่วยฉันกรอกรหัสได้ไหม

ฉันไม่รู้ว่าจะเชื่อมอาร์เรย์ทั้งสามเข้าด้วยกันและพิมพ์ได้อย่างไร

def sort(array=[12,4,5,6,7,3,1,15]):
    less = []
    equal = []
    greater = []

    if len(array) > 1:
        pivot = array[0]
        for x in array:
            if x < pivot:
                less.append(x)
            if x == pivot:
                equal.append(x)
            if x > pivot:
                greater.append(x)
            sort(less)
            sort(pivot)
            sort(greater)

my_list = list1 + list2 + ...ที่จะรวมรายการที่คุณสามารถใช้บวกกับผู้ประกอบการ หรือแกะรายการไปยังรายการใหม่my_list = [*list1, *list2]
Mark Mishyn

คำตอบ:


256
def sort(array=[12,4,5,6,7,3,1,15]):
    """Sort the array by using quicksort."""

    less = []
    equal = []
    greater = []

    if len(array) > 1:
        pivot = array[0]
        for x in array:
            if x < pivot:
                less.append(x)
            elif x == pivot:
                equal.append(x)
            elif x > pivot:
                greater.append(x)
        # Don't forget to return something!
        return sort(less)+equal+sort(greater)  # Just use the + operator to join lists
    # Note that you want equal ^^^^^ not pivot
    else:  # You need to handle the part at the end of the recursion - when you only have one element in your array, just return the array.
        return array

8
นอกจากนี้คุณยังสามารถสลับifวินาทีที่2 ในสำหรับลูปด้วยelifและelseเพื่อหลีกเลี่ยงการเปรียบเทียบที่ไม่จำเป็น
SlimPDX

13
ฟังดูเหมือนการเรียงลำดับการผสานไม่ใช่การเรียงลำดับอย่างรวดเร็ว
Emad Mokhtar

47
มันเป็นเรื่องจริงที่ดีที่สุดและสามารถอ่านได้มากที่สุดรหัสหลามฉันพบ quicksort ที่ใดก็ได้ ไม่มีดัชนีไม่มีฟังก์ชั่นตัวช่วยแสดงส่วนสำคัญของอัลกอริทึม (แบ่งและพิชิต) อย่างชัดเจน (ค่าเริ่มต้นของอาร์เรย์ค่อนข้างไม่จำเป็น)
cmantas

20
@jsmedmar มันจะใช้หน่วยความจำมากกว่ารุ่นในสถานที่ดูคำตอบของ suquant สำหรับการจัดเรียงอย่างรวดเร็วในสถานที่
จอห์น

15
อ่านได้มาก แต่สิ่งนี้ไม่ทำให้จุดประสงค์ของการเรียงลำดับอย่างรวดเร็วเนื่องจากสิ่งนี้จะไม่บรรลุการเรียงลำดับ 'ในสถานที่' @RasmiRanjanNayak การเรียงลำดับที่นี่คือฟังก์ชันที่ผู้ใช้กำหนดเอง (เป็นการเรียกแบบเรียกซ้ำ) ไม่ใช่ฟังก์ชันในตัว
Maksood

161

จัดเรียงอย่างรวดเร็วโดยไม่มีหน่วยความจำเพิ่มเติม (ในสถานที่)

การใช้งาน:

array = [97, 200, 100, 101, 211, 107]
quicksort(array)
# array -> [97, 100, 101, 107, 200, 211]
def partition(array, begin, end):
    pivot = begin
    for i in xrange(begin+1, end+1):
        if array[i] <= array[begin]:
            pivot += 1
            array[i], array[pivot] = array[pivot], array[i]
    array[pivot], array[begin] = array[begin], array[pivot]
    return pivot



def quicksort(array, begin=0, end=None):
    if end is None:
        end = len(array) - 1
    def _quicksort(array, begin, end):
        if begin >= end:
            return
        pivot = partition(array, begin, end)
        _quicksort(array, begin, pivot-1)
        _quicksort(array, pivot+1, end)
    return _quicksort(array, begin, end)

23
นี่ควรเป็นคำตอบที่เลือกเนื่องจาก Quicksort มักเป็นอัลกอริทึมที่เลือก (มากกว่าเช่น merge sort) เนื่องจากจัดเรียงตามตำแหน่ง (และยังให้รันไทม์ O (nlogn))
BoltzmannBrain

3
if end is None:Trueเป็นไปได้ที่การตรวจสอบหลายครั้งและเพียงครั้งเดียวมันเป็นไปได้ คุณควรใส่สิ่งนี้ในฟังก์ชัน wrapper เพื่อให้ถูกเรียกเพียงครั้งเดียว
Gillespie

ใช่แล้ว bruhs, @mksteve ถูกต้องและบรรทัดนี้ไม่ถูกต้อง นอกจากนี้array[pivot], array[begin] = array[begin], array[pivot]ควรแทนที่beginด้วยend.
Ryan J McCall

2
แม้ว่าในสถานที่จะดี แต่ก็ช้าและเกิดข้อผิดพลาดเนื่องจากการกดความลึกสูงสุดของการเรียกซ้ำเมื่อมีรายการจำนวนมาก ดูrepl.it/@almenon/quicksorts?language=python3
Almenon

@mksteve และ Ryan ฉันทดสอบการเปลี่ยนแปลงเหล่านี้และแบ่งการ
เรียงลำดับ

68

มีอีกเวอร์ชั่นหนึ่งที่กระชับและสวยงาม

def qsort(arr): 
    if len(arr) <= 1:
        return arr
    else:
        return qsort([x for x in arr[1:] if x < arr[0]]) + \
               [arr[0]] + \
               qsort([x for x in arr[1:] if x >= arr[0]])

# this comment is just to improve readability due to horizontal scroll!!!

ให้ฉันอธิบายรหัสข้างต้นเพื่อดูรายละเอียด

  1. เลือกองค์ประกอบแรกของอาร์เรย์arr[0]เป็นเดือย

    [arr[0]]

  2. qsort องค์ประกอบเหล่านั้นของอาร์เรย์ซึ่งน้อยกว่าเดือยด้วย List Comprehension

    qsort([x for x in arr[1:] if x < arr[0]])

  3. qsort องค์ประกอบของอาร์เรย์ที่มีขนาดใหญ่กว่าเดือยด้วย List Comprehension

    qsort([x for x in arr[1:] if x >= arr[0]])


15
@zangw เหตุผลที่เป็นไปได้สำหรับการโหวตลดลง: 1) รันไทม์กำลังสองบนอาร์เรย์ที่เรียงลำดับแล้วหรือย้อนกลับ 2) โซลูชันไม่อยู่ในตำแหน่ง ดังนั้นการใช้งานที่แย่มากขออภัย
alisianoi

16
อ่านไม่ออกเลยคุณกำลังพยายามลดจำนวนบรรทัดอย่างแท้จริงหรือไม่? รหัสถูกตีความโดยเครื่องจักร แต่มนุษย์เข้าใจได้
jsmedmar

4
@AlfredoGallegos จุดรวมของ Quicksort มันเกิดขึ้นในสถานที่คุณอาจใช้การจัดเรียงแบบผสานได้เช่นกันหากคุณจะทำสิ่งนี้
Padraic Cunningham

14
ความคิดเห็นเหล่านี้เป็นจริงหรือไม่? หากคุณต้องการประสิทธิภาพให้ใช้sortedสิ่งนี้มีวัตถุประสงค์เพื่อการศึกษาอย่างชัดเจน และน่าอ่านอ่านได้มากกว่าคำตอบที่ยอมรับ
Nobilis

4
FWIW ฉันคิดว่านี่เป็นการใช้งานที่อ่านง่ายที่สุดในบรรดาทั้งหมด มันแสดงโครงสร้างแบบวนซ้ำของอัลกอริทึมได้ดีกว่าคำตอบอื่น ๆ แน่นอนว่าประสิทธิภาพจะไม่ดีเกินไป
SolveIt

37

คำตอบนี้เป็น QuickSort Python 2.xในสถานที่สำหรับ คำตอบของฉันคือการตีความโซลูชันในสถานที่จากRosetta Codeซึ่งใช้ได้ผลPython 3เช่นกัน:

import random

def qsort(xs, fst, lst):
    '''
    Sort the range xs[fst, lst] in-place with vanilla QuickSort

    :param xs:  the list of numbers to sort
    :param fst: the first index from xs to begin sorting from,
                must be in the range [0, len(xs))
    :param lst: the last index from xs to stop sorting at
                must be in the range [fst, len(xs))
    :return:    nothing, the side effect is that xs[fst, lst] is sorted
    '''
    if fst >= lst:
        return

    i, j = fst, lst
    pivot = xs[random.randint(fst, lst)]

    while i <= j:
        while xs[i] < pivot:
            i += 1
        while xs[j] > pivot:
            j -= 1

        if i <= j:
            xs[i], xs[j] = xs[j], xs[i]
            i, j = i + 1, j - 1
    qsort(xs, fst, j)
    qsort(xs, i, lst)

และหากคุณยินดีที่จะละทิ้งสถานที่ให้บริการในสถานที่ด้านล่างนี้เป็นอีกเวอร์ชันหนึ่งซึ่งแสดงให้เห็นถึงแนวคิดพื้นฐานที่อยู่เบื้องหลัง Quicksort ได้ดียิ่งขึ้น นอกเหนือจากความสามารถในการอ่านแล้วข้อดีอีกอย่างคือมีความเสถียร (องค์ประกอบที่เท่ากันจะปรากฏในรายการที่เรียงลำดับตามลำดับเดียวกับที่เคยมีในรายการที่ไม่เรียงลำดับ) คุณสมบัติความเสถียรนี้ไม่ได้ยึดติดกับการใช้งานในสถานที่ที่มีหน่วยความจำน้อยกว่าที่นำเสนอข้างต้น

def qsort(xs):
    if not xs: return xs # empty sequence case
    pivot = xs[random.choice(range(0, len(xs)))]

    head = qsort([x for x in xs if x < pivot])
    tail = qsort([x for x in xs if x > pivot])
    return head + [x for x in xs if x == pivot] + tail

ขอบคุณสำหรับการแบ่งปันวิธีนี้ คุณช่วยให้เราเข้าใจความซับซ้อนของเวลาได้ไหม ฉันเห็นว่าการเรียกซ้ำจะเรียกมันว่า 15 ครั้ง จากทั้ง 8 นี้เป็นการเรียกใช้ฟังก์ชันที่ถูกต้อง นั่นหมายความว่าความซับซ้อนของเวลาคือ O (n) สำหรับโซลูชันแรกและความซับซ้อนของพื้นที่คือ O (1) เป็นการจัดเรียงแบบแทนที่หรือไม่
ForeverLearner

@ แทมมี่ดูเหมือนว่าคุณเข้าใจผิดสัญกรณ์ใหญ่ นอกจากนี้ฉันไม่เข้าใจคำถามของคุณจริงๆ คุณอาจถามแยกกันได้ไหม? สุดท้าย Quicksort เป็นอัลกอริทึมทำงานในเวลา O (n logn) และช่องว่าง O (n)
alisianoi

3
ความผิดฉันเอง. ทำไมฉันถึงนับการวนซ้ำบนโลก? :-) ดี 15 การเรียกซ้ำคือ [1 การโทร (ระดับ 0) + 2 การโทร (พาร์ติชันระดับ 1) + 4 การโทร (พาร์ติชันระดับ 2) + 8 การโทร (พาร์ติชันระดับ 3 หรือโหนด Leaf) ดังนั้นเรายังคงมีความสูงเป็น (lg8 + 1) = lgn การคำนวณรวมในแต่ละระดับสำหรับ c1 (ต้นทุนบางส่วน) * n ดังนั้น O (n lgn) ความซับซ้อนของพื้นที่สำหรับการแลกเปลี่ยนในสถานที่เดียว = O (1) ดังนั้นสำหรับ n องค์ประกอบ = O (n) ขอบคุณสำหรับตัวชี้
ForeverLearner

3
นี่อยู่ไกลและห่างไกลงูเหลือมที่ดีที่สุดบนอินเทอร์เน็ตและเป็นเรื่องน่าเศร้าที่เห็นมันถูกฝังอยู่ภายใต้โซลูชันอวกาศ O (n) จำนวนมาก :(
Sasha Kondrashov

ขอบคุณสำหรับคำพูด @Timofey คุณอาจต้องการดูที่ repo อัลกอริทึมของฉันมันมีประเภทอื่น ๆ อัลกอริทึมกราฟ ฯลฯ ฯลฯgithub.com/alisianoi/algos-py
alisianoi

23

Quicksort ด้วย Python

ในชีวิตจริงเราควรใช้การจัดเรียงแบบ builtin ที่ Python ให้มาเสมอ อย่างไรก็ตามการทำความเข้าใจกับอัลกอริทึมQuicksortเป็นคำแนะนำ

เป้าหมายของฉันที่นี่คือการแยกย่อยเรื่องเพื่อให้ผู้อ่านเข้าใจและทำซ้ำได้ง่ายโดยไม่ต้องกลับไปที่เอกสารอ้างอิง

อัลกอริทึม Quicksort มีดังต่อไปนี้:

  1. เลือกจุดข้อมูล Pivot
  2. ย้ายจุดข้อมูลทั้งหมดที่น้อยกว่า (ด้านล่าง) เดือยไปยังตำแหน่งที่อยู่ด้านล่างเดือย - ย้ายจุดที่มากกว่าหรือเท่ากับ (ด้านบน) เดือยไปยังตำแหน่งที่อยู่เหนือจุดหมุน
  3. ใช้อัลกอริทึมกับพื้นที่ด้านบนและด้านล่างของเดือย

หากข้อมูลถูกกระจายแบบสุ่มการเลือกจุดข้อมูลแรกเนื่องจากเดือยจะเทียบเท่ากับการเลือกแบบสุ่ม

ตัวอย่างที่อ่านได้:

ก่อนอื่นมาดูตัวอย่างที่อ่านได้ซึ่งใช้ความคิดเห็นและชื่อตัวแปรเพื่อชี้ไปที่ค่ากลาง:

def quicksort(xs):
    """Given indexable and slicable iterable, return a sorted list"""
    if xs: # if given list (or tuple) with one ordered item or more: 
        pivot = xs[0]
        # below will be less than:
        below = [i for i in xs[1:] if i < pivot] 
        # above will be greater than or equal to:
        above = [i for i in xs[1:] if i >= pivot]
        return quicksort(below) + [pivot] + quicksort(above)
    else: 
        return xs # empty list

ในการสร้างอัลกอริทึมและโค้ดที่แสดงไว้ที่นี่ - เราย้ายค่าเหนือเดือยไปทางขวาและค่าด้านล่างเดือยไปทางซ้ายแล้วส่งพาร์ติชันเหล่านั้นไปยังฟังก์ชันเดียวกันเพื่อจัดเรียงเพิ่มเติม

กอล์ฟ:

สามารถตีกอล์ฟได้ถึง 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]])

หากต้องการดูว่าเราไปที่นั่นได้อย่างไรอันดับแรกให้ใช้ตัวอย่างที่อ่านได้ของเราลบความคิดเห็นและ docstrings แล้วค้นหาจุดหมุนในตำแหน่ง:

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]]))

เนื่องจาก lambdas ส่งคืน epression เดียวและเราได้ทำให้ง่ายขึ้นเป็นนิพจน์เดียว (แม้ว่าจะไม่สามารถอ่านได้มากขึ้นก็ตาม) ตอนนี้เราสามารถใช้ lambda:

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]])

โปรดทราบว่าแลมด้านี้เช่นเดียวกับการตีกอล์ฟส่วนใหญ่เป็นรูปแบบที่ไม่ดี

Quicksort ในสถานที่โดยใช้โครงร่าง Hoare Partitioning

การใช้งานก่อนหน้านี้จะสร้างรายการพิเศษที่ไม่จำเป็นจำนวนมาก หากเราทำได้ในสถานที่เราจะหลีกเลี่ยงการเสียพื้นที่

การใช้งานด้านล่างนี้ใช้โครงร่างการแบ่ง Hoare ซึ่งคุณสามารถอ่านเพิ่มเติมเกี่ยวกับวิกิพีเดียได้ (แต่เห็นได้ชัดว่าเราได้ลบการคำนวณซ้ำซ้อนออกมากถึง 4 รายการต่อการpartition()โทรหนึ่งครั้งโดยใช้ความหมาย while-loop แทน do-while และย้ายขั้นตอนที่แคบลงไปที่จุดสิ้นสุดของ ด้านนอกในขณะที่วนซ้ำ)

def quicksort(a_list):
    """Hoare partition scheme, see https://en.wikipedia.org/wiki/Quicksort"""
    def _quicksort(a_list, low, high):
        # must run partition on sections with 2 elements or more
        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]

สรุป

อัลกอริทึมนี้มักจะสอนในหลักสูตรวิทยาการคอมพิวเตอร์และขอให้สัมภาษณ์งาน มันช่วยให้เราคิดถึงการเรียกซ้ำและการแบ่งแยกและพิชิต

Quicksort ไม่สามารถใช้งานได้จริงใน Python เนื่องจากอัลกอริทึมtimsort ในตัวของเราค่อนข้างมีประสิทธิภาพและเรามีข้อ จำกัด ในการเรียกซ้ำ เราคาดหวังว่าจะจัดเรียงรายการในตำแหน่งที่มีlist.sortหรือสร้างรายการที่เรียงใหม่ด้วยsortedซึ่งทั้งสองอย่างใช้เวลา a keyและreverseอาร์กิวเมนต์


คุณฟังก์ชั่นดูเหมือนจะไม่ทำงานอย่างถูกต้องสำหรับ:partition partition([5,4,3,2,1], 0, 4)ดัชนีผลตอบแทนที่คาดหวังคือ 4 ในขณะที่ส่งกลับ 3
matino

@matino ความคาดหวังนั้นมาจากไหน? ฉันเชื่อว่าฉันทำให้อัลกอริทึมง่ายขึ้น (ตามที่ระบุไว้ในวิกิพีเดียเมื่อเขียนคำตอบนี้) แม้ว่าฉันจะผิดหรืออาจมีประสิทธิภาพน้อยกว่า หากคุณพบกรณีทดสอบที่ฟังก์ชัน Quicksort ทั้งหมดล้มเหลวนั่นจะเป็นประโยชน์
Aaron Hall

@AaronHall เมื่อฉันเลือก pivot = a_list [high] แต่ฉันคิดไม่ออกว่าจะทำให้มันใช้งานได้อย่างไร คุณสามารถช่วย?
Qiulang

@matino ฉันมีความสับสนเหมือนกัน! ฟังก์ชั่นพาร์ติชันนั้นใช้ได้ดีค่าคงที่ที่ตอบสนองนั้นอ่อนแอกว่าที่คุณคาดหวัง - ไม่ต้องหาตำแหน่งที่แน่นอนที่แยกซ้ายและขวาให้เล็กลงและใหญ่กว่าเดือย รับประกันเฉพาะพาร์ติชันที่ไม่สำคัญและดัชนีที่ส่งคืนด้านซ้ายทั้งหมดมีขนาดเล็กกว่าด้านขวาของดัชนีที่ส่งคืน
Dror Speiser

21

มีคำตอบมากมายสำหรับสิ่งนี้แล้ว แต่ฉันคิดว่าวิธีนี้เป็นการใช้งานที่สะอาดที่สุด:

def quicksort(arr):
    """ Quicksort a list

    :type arr: list
    :param arr: List to sort
    :returns: list -- Sorted list
    """
    if not arr:
        return []

    pivots = [x for x in arr if x == arr[0]]
    lesser = quicksort([x for x in arr if x < arr[0]])
    greater = quicksort([x for x in arr if x > arr[0]])

    return lesser + pivots + greater

แน่นอนคุณสามารถข้ามการจัดเก็บทุกอย่างในตัวแปรและส่งคืนได้ทันทีดังนี้:

def quicksort(arr):
    """ Quicksort a list

    :type arr: list
    :param arr: List to sort
    :returns: list -- Sorted list
    """
    if not arr:
        return []

    return quicksort([x for x in arr if x < arr[0]]) \
        + [x for x in arr if x == arr[0]] \
        + quicksort([x for x in arr if x > arr[0]])

11
บน!)? นี่คือ 'slowSort' หรือไม่?
Scott 混合理论

3
ฉันเชื่อว่าในตัวอย่างโค้ดแรกควรเป็น 'lesser' และ 'greater' แทนที่จะเป็น '[lesser]' และ '[greater]' - มิฉะนั้นคุณจะลงเอยด้วยรายการที่ซ้อนกันแทนที่จะเป็นแบบแบน
Alice

@Scott混合理论ฉันยังคงเรียนรู้ซับซ้อนเวลาที่คุณสามารถทำอย่างละเอียดว่าทำไมการดำเนินงานนี้คือO(N!)? สมมติว่ารายการซ้อนกัน[lesser]และ[greater]พิมพ์ผิดมันจะไม่เป็นค่าเฉลี่ยO(3N logN)ที่จะลดลงเป็นค่าเฉลี่ยที่คาดไว้O(N logN)หรือไม่? จริงอยู่ที่คอมพ์ 3 รายการทำงานที่ไม่จำเป็น ..
Chrispy

@Chrispy จะเกิดอะไรขึ้นถ้าคุณเรียงลำดับรายการแบบกลับหัวเช่น 5,4,3,2,1
สก็อตต์混合理论

@Scott 混合理论คุณคิดถูกแล้วที่เวลาเรียกใช้กรณีที่เลวร้ายที่สุดของการเรียงลำดับอย่างรวดเร็วนั้นช้าΘ (n ^ 2) แต่ตาม "บทนำสู่อัลกอริทึม" เวลาทำงานโดยเฉลี่ยคือΘ (n lg n) และที่สำคัญการเรียงลำดับอย่างรวดเร็วโดยทั่วไปมีประสิทธิภาพดีกว่าการเรียงลำดับฮีปในทางปฏิบัติ
Lungang Fang

6

แนวทางการทำงาน:

def qsort(list):
    if len(list) < 2:
        return list

    pivot = list.pop()
    left = filter(lambda x: x <= pivot, list)
    right = filter(lambda x: x > pivot, list)

    return qsort(left) + [pivot] + qsort(right)

รายการสงวนไว้ใน python 3 ดูเวอร์ชันแก้ไขของโค้ดของคุณที่นี่: gist.github.com/kunthar/9d8962e1438e93f50dc6dd94d503af3d
Kunthar

akarca และ @Kunthar โซลูชันทั้งสองนี้ใน python2 หรือ python3 จะปรากฏองค์ประกอบจากรายการทุกครั้งที่เรียกใช้ดังนั้นจึงทำลายรายการ นี่คือเวอร์ชันคงที่: gist.github.com/joshuatvernon/634e0d912401899af0fdc4e23c94192b
joshuatvernon

4

aproach การเขียนโปรแกรมเชิงฟังก์ชัน

smaller = lambda xs, y: filter(lambda x: x <= y, xs)
larger = lambda xs, y: filter(lambda x: x > y, xs)
qsort = lambda xs: qsort(smaller(xs[1:],xs[0])) + [xs[0]] + qsort(larger(xs[1:],xs[0])) if xs != [] else []

print qsort([3,1,4,2,5]) == [1,2,3,4,5]

4

ใช้งานง่ายจากอัลกอริทึม grokking

def quicksort(arr):
    if len(arr) < 2:
        return arr #base case
    else:
        pivot = arr[0]
        less = [i for i in arr[1:] if i <= pivot] 
        more = [i for i in arr[1:] if i > pivot]
        return quicksort(less) + [pivot] + quicksort(more)

3

ฉันคิดว่าทั้งสองคำตอบที่นี่ใช้งานได้กับรายการที่ให้ไว้ (ซึ่งตอบคำถามเดิม) แต่จะแตกหากอาร์เรย์ที่มีค่าที่ไม่ซ้ำกันถูกส่งผ่าน ดังนั้นเพื่อความสมบูรณ์ฉันจะชี้ให้เห็นข้อผิดพลาดเล็ก ๆ น้อย ๆ ในแต่ละข้อและอธิบายวิธีแก้ไข

ตัวอย่างเช่นการพยายามเรียงลำดับอาร์เรย์ต่อไปนี้ [12,4,5,6,7,3,1,15,1] (โปรดทราบว่า 1 จะปรากฏขึ้นสองครั้ง) ด้วยอัลกอริทึมBrionius .. ในบางจุดจะจบลงด้วยอาร์เรย์น้อยกว่าที่ว่างเปล่า และอาร์เรย์เท่ากันที่มีคู่ค่า (1,1) ที่ไม่สามารถแยกออกได้ในการทำซ้ำครั้งต่อไปและlen ()> 1 ... ดังนั้นคุณจะจบลงด้วยการวนซ้ำที่ไม่มีที่สิ้นสุด

คุณสามารถแก้ไขได้โดยส่งคืนอาร์เรย์ถ้าน้อยกว่าว่างหรือดีกว่าโดยไม่เรียก sort ในอาร์เรย์ที่เท่ากันของคุณเช่นเดียวกับคำตอบzangw

def sort(array=[12,4,5,6,7,3,1,15]):
    less = []
    equal = []
    greater = []

    if len(array) > 1:
        pivot = array[0]
        for x in array:
            if x < pivot:
                less.append(x)
            if x == pivot:
                equal.append(x)
            if x > pivot:
                greater.append(x)

        # Don't forget to return something!
        return sort(less)+ equal +sort(greater)  # Just use the + operator to join lists
    # Note that you want equal ^^^^^ not pivot
    else:  # You need to hande the part at the end of the recursion - when you only have one element in your array, just return the array.
        return array

วิธีแก้ปัญหาสำหรับนักเล่นตัวยงก็แตกเช่นกัน แต่ด้วยสาเหตุที่แตกต่างกันมันไม่มีส่วนส่งคืนในบรรทัดการเรียกซ้ำซึ่งจะทำให้เมื่อถึงจุดหนึ่งที่จะส่งคืนไม่มีและพยายามผนวกเข้ากับรายการ ...

หากต้องการแก้ไขให้เพิ่มการกลับไปที่บรรทัดนั้น

def qsort(arr): 
   if len(arr) <= 1:
      return arr
   else:
      return qsort([x for x in arr[1:] if x<arr[0]]) + [arr[0]] + qsort([x for x in arr[1:] if x>=arr[0]])

อย่างไรก็ตามเวอร์ชันที่กระชับมีประสิทธิภาพน้อยกว่าแบบยาวเนื่องจากมีการทำอาร์เรย์ซ้ำสองครั้งเพื่อทำความเข้าใจรายการ
FedeN

3

นี่คือเวอร์ชันของ Quicksort โดยใช้โครงร่างพาร์ติชัน Hoare และมีสวอปและตัวแปรภายในน้อยลง

def quicksort(array):
    qsort(array, 0, len(array)-1)

def qsort(A, lo, hi):
    if lo < hi:
        p = partition(A, lo, hi)
        qsort(A, lo, p)
        qsort(A, p + 1, hi)

def partition(A, lo, hi):
    pivot = A[lo]
    i, j = lo-1, hi+1
    while True:
      i += 1
      j -= 1
      while(A[i] < pivot): i+= 1
      while(A[j] > pivot ): j-= 1

      if i >= j: 
          return j

      A[i], A[j] = A[j], A[i]


test = [21, 4, 1, 3, 9, 20, 25, 6, 21, 14]
print quicksort(test)

3

พาร์ติชั่น - แบ่งอาร์เรย์ด้วยเดือยที่องค์ประกอบขนาดเล็กย้ายไปทางซ้ายและองค์ประกอบที่ใหญ่กว่าจะย้ายไปทางขวาหรือในทางกลับกัน เดือยสามารถเป็นองค์ประกอบแบบสุ่มจากอาร์เรย์ ในการสร้างอัลกอริทึมนี้เราจำเป็นต้องทราบว่าดัชนีเริ่มต้นและสิ้นสุดของอาร์เรย์คืออะไรและจุดหมุนอยู่ที่ไหน จากนั้นตั้งค่าตัวชี้เสริมสองตัว L, R

ดังนั้นเราจึงมีผู้ใช้อาร์เรย์ [... , เริ่ม, ... , จบ, ... ]

ตำแหน่งเริ่มต้นของตัวชี้ L และ R
[... , เริ่ม, ถัดไป, ... , สิ้นสุด, ... ]
     R L

ในขณะที่ L <end
  1. ถ้าผู้ใช้ [pivot]> ผู้ใช้ [L] ให้ย้าย R ทีละคนและสลับผู้ใช้ [R] กับผู้ใช้ [L]
  2. ย้าย L ทีละคน

หลังจากสลับผู้ใช้ [R] กับผู้ใช้ [pivot]

การเรียงลำดับอย่างรวดเร็ว - ใช้อัลกอริทึมพาร์ติชันจนกว่าทุกส่วนถัดไปของการแบ่งโดยเดือยจะมีดัชนีเริ่มต้นมากกว่าหรือเท่ากับดัชนีสิ้นสุด

def qsort(user, begin, end):

    if begin >= end:
        return

    # partition
    # pivot = begin
    L = begin+1
    R = begin
    while L < end:
        if user[begin] > user[L]:
            R+=1
            user[R], user[L] = user[L], user[R]
        L+= 1
    user[R], user[begin] = user[begin], user[R]

    qsort(user, 0, R)
    qsort(user, R+1, end)

tests = [
    {'sample':[1],'answer':[1]},
    {'sample':[3,9],'answer':[3,9]},
    {'sample':[1,8,1],'answer':[1,1,8]},
    {'sample':[7,5,5,1],'answer':[1,5,5,7]},
    {'sample':[4,10,5,9,3],'answer':[3,4,5,9,10]},
    {'sample':[6,6,3,8,7,7],'answer':[3,6,6,7,7,8]},
    {'sample':[3,6,7,2,4,5,4],'answer':[2,3,4,4,5,6,7]},
    {'sample':[1,5,6,1,9,0,7,4],'answer':[0,1,1,4,5,6,7,9]},
    {'sample':[0,9,5,2,2,5,8,3,8],'answer':[0,2,2,3,5,5,8,8,9]},
    {'sample':[2,5,3,3,2,0,9,0,0,7],'answer':[0,0,0,2,2,3,3,5,7,9]}
]

for test in tests:

    sample = test['sample'][:]
    answer = test['answer']

    qsort(sample,0,len(sample))

    print(sample == answer)

โปรดอธิบายรหัส / ส่วนเพิ่มเติมของคุณเพื่อให้ OP และมุมมองในอนาคตได้รับประโยชน์มากขึ้น
Omar Einea

2

หรือถ้าคุณต้องการซับเดียวที่แสดงถึง Python ที่เทียบเท่ากับ varags C / C ++, นิพจน์แลมบ์ดาและนิพจน์ if:

qsort = lambda x=None, *xs: [] if x is None else qsort(*[a for a in xs if a<x]) + [x] + qsort(*[a for a in xs if a>=x])

2
def quick_sort(self, nums):
    def helper(arr):
        if len(arr) <= 1: return arr
        #lwall is the index of the first element euqal to pivot
        #rwall is the index of the first element greater than pivot
        #so arr[lwall:rwall] is exactly the middle part equal to pivot after one round
        lwall, rwall, pivot = 0, 0, 0
        #choose rightmost as pivot
        pivot = arr[-1]
        for i, e in enumerate(arr):
            if e < pivot:
                #when element is less than pivot, shift the whole middle part to the right by 1
                arr[i], arr[lwall] = arr[lwall], arr[i]
                lwall += 1
                arr[i], arr[rwall] = arr[rwall], arr[i]
                rwall += 1
            elif e == pivot:
                #when element equals to pivot, middle part should increase by 1
                arr[i], arr[rwall] = arr[rwall], arr[i]
                rwall += 1
            elif e > pivot: continue
        return helper(arr[:lwall]) + arr[lwall:rwall] + helper(arr[rwall:])
    return helper(nums)

2

ฉันรู้ว่าหลายคนตอบคำถามนี้ถูกต้องและฉันก็สนุกกับการอ่าน คำตอบของฉันเกือบจะเหมือนกันกับ zangw แต่ฉันคิดว่าผู้ให้ข้อมูลก่อนหน้านี้ไม่สามารถอธิบายให้เห็นได้ดีว่าสิ่งต่างๆทำงานอย่างไร ... ดังนั้นนี่คือความพยายามของฉันที่จะช่วยเหลือผู้อื่นที่อาจเข้ามาเยี่ยมชมคำถาม / คำตอบนี้ในอนาคตเกี่ยวกับ a วิธีง่ายๆสำหรับการใช้งาน Quicksort

มันทำงานอย่างไร?

  1. โดยทั่วไปเราเลือกรายการแรกเป็นเดือยจากรายการของเราจากนั้นเราสร้างรายการย่อยสองรายการ
  2. รายการย่อยแรกของเรามีรายการที่น้อยกว่า pivot
  3. รายการย่อยที่สองของเรามีรายการของเราที่ดีกว่าหรือเท่ากับเดือย
  4. จากนั้นเราเรียงลำดับแต่ละรายการอย่างรวดเร็วและรวมกลุ่มแรก + เดือย + กลุ่มที่สองเพื่อให้ได้ผลลัพธ์สุดท้าย

นี่คือตัวอย่างพร้อมกับภาพที่จะไปด้วย ... (pivot) 9,11,2,0

ค่าเฉลี่ย: n บันทึกของ n

กรณีที่แย่กว่า: n ^ 2

ป้อนคำอธิบายภาพที่นี่

รหัส:

def quicksort(data):
if (len(data) < 2):
    return data
else:
    pivot = data[0]  # pivot
    #starting from element 1 to the end
    rest = data[1:]
    low = [each for each in rest if each < pivot]
    high = [each for each in rest if each >= pivot]
    return quicksort(low) + [pivot] + quicksort(high)

items = [9,11,2,0] พิมพ์ (Quicksort (items))


2

อัลกอริทึมประกอบด้วยสองขอบเขตโดยหนึ่งมีองค์ประกอบน้อยกว่าเดือย (ติดตามโดยดัชนี "j") และอีกอันมีองค์ประกอบที่มากกว่าเดือย (ติดตามโดยดัชนี "i")

ในการวนซ้ำแต่ละครั้งองค์ประกอบใหม่จะถูกประมวลผลโดยการเพิ่ม j

ไม่เปลี่ยนแปลง: -

  1. องค์ประกอบทั้งหมดระหว่าง pivot และ i น้อยกว่า pivot และ
  2. องค์ประกอบทั้งหมดระหว่าง i และ j มีค่ามากกว่าเดือย

หากค่าคงที่ถูกละเมิดองค์ประกอบ ith และ jth จะถูกสลับและ i จะเพิ่มขึ้น

หลังจากประมวลผลองค์ประกอบทั้งหมดแล้วและทุกอย่างหลังจากแบ่งพาร์ติชัน Pivot แล้วองค์ประกอบ Pivot จะถูกสลับกับองค์ประกอบสุดท้ายที่มีขนาดเล็กกว่า

ตอนนี้องค์ประกอบ Pivot จะอยู่ในตำแหน่งที่ถูกต้องในลำดับ องค์ประกอบที่อยู่ข้างหน้าจะน้อยกว่าและองค์ประกอบที่ตามมาจะมากกว่าองค์ประกอบนั้นและจะไม่เรียงลำดับ

def quicksort(sequence, low, high):
    if low < high:    
        pivot = partition(sequence, low, high)
        quicksort(sequence, low, pivot - 1)
        quicksort(sequence, pivot + 1, high)

def partition(sequence, low, high):
    pivot = sequence[low]
    i = low + 1
    for j in range(low + 1, high + 1):
        if sequence[j] < pivot:
            sequence[j], sequence[i] = sequence[i], sequence[j]
            i += 1
    sequence[i-1], sequence[low] = sequence[low], sequence[i-1]
    return i - 1

def main(sequence):
    quicksort(sequence, 0, len(sequence) - 1)
    return sequence

if __name__ == '__main__':
    sequence = [-2, 0, 32, 1, 56, 99, -4]
    print(main(sequence))

การเลือกเดือย

เดือยที่ "ดี" จะทำให้เกิดลำดับย่อยสองลำดับที่มีขนาดใกล้เคียงกัน ในเชิงกำหนดองค์ประกอบ Pivot สามารถเลือกได้ในลักษณะไร้เดียงสาหรือโดยการคำนวณค่ามัธยฐานของลำดับ

การนำไปใช้อย่างไร้เดียงสาในการเลือกเดือยจะเป็นองค์ประกอบแรกหรือองค์ประกอบสุดท้าย รันไทม์กรณีที่เลวร้ายที่สุดในกรณีนี้คือเมื่อลำดับการป้อนข้อมูลถูกเรียงลำดับแล้วหรือเรียงลำดับย้อนกลับเนื่องจากหนึ่งในลำดับต่อมาจะว่างเปล่าซึ่งจะทำให้องค์ประกอบเพียงหนึ่งรายการถูกลบออกต่อการเรียกซ้ำ

การแบ่งที่สมดุลอย่างสมบูรณ์จะทำได้เมื่อเดือยเป็นองค์ประกอบมัธยฐานของลำดับ มีองค์ประกอบจำนวนเท่ากันมากกว่าและน้อยกว่า วิธีนี้รับประกันเวลาการทำงานโดยรวมที่ดีขึ้น แต่ใช้เวลานานกว่ามาก

วิธีที่ไม่กำหนด / สุ่มในการเลือกเดือยคือการเลือกองค์ประกอบที่สม่ำเสมอโดยการสุ่ม นี่เป็นแนวทางที่เรียบง่ายและมีน้ำหนักเบาซึ่งจะลดสถานการณ์ที่เลวร้ายที่สุดและยังนำไปสู่การแบ่งที่สมดุลโดยประมาณ นอกจากนี้ยังช่วยให้เกิดความสมดุลระหว่างแนวทางที่ไร้เดียงสาและแนวทางค่ามัธยฐานของการเลือกเดือย


2
def quicksort(array):
 if len(array) < 2:
  return array
 else:
  pivot = array[0]

 less = [i for i in array[1:] if i <= pivot]
 greater = [i for i in array[1:] if i > pivot]
 return quicksort(less) + [pivot] + quicksort(greater)

แม้ว่ารหัสนี้อาจช่วยแก้ปัญหาได้ แต่ขอแนะนำอย่างยิ่งให้คุณระบุบริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีที่รหัสนี้ตอบคำถาม โดยทั่วไปแล้วการเขียนโค้ดคำตอบจะไม่มีประโยชน์ในระยะยาวเนื่องจากผู้ชมในอนาคตที่ประสบปัญหาคล้าย ๆ กันไม่สามารถเข้าใจเหตุผลเบื้องหลังการแก้ปัญหาได้
palaѕн


1
def Partition(A,p,q):
    i=p
    x=A[i]
    for j in range(p+1,q+1):
        if A[j]<=x:
            i=i+1
            tmp=A[j]
            A[j]=A[i]
            A[i]=tmp
    l=A[p]
    A[p]=A[i]
    A[i]=l
    return i

def quickSort(A,p,q):
    if p<q:
        r=Partition(A,p,q)
        quickSort(A,p,r-1)
        quickSort(A,r+1,q)
    return A

1
โปรดใส่คำอธิบายว่าโค้ดของคุณใช้ทำอะไรและตอบคำถามได้อย่างไร โดยเฉพาะอย่างยิ่งมันเกี่ยวข้องกับรหัสที่โพสต์ในคำถามอย่างไร คำตอบควรให้คำแนะนำแก่ OP และผู้เยี่ยมชมในอนาคตเกี่ยวกับวิธีการดีบักและแก้ไขปัญหาของพวกเขา การชี้ให้เห็นว่าแนวคิดเบื้องหลังโค้ดของคุณคืออะไรช่วยอย่างมากในการทำความเข้าใจปัญหาและการนำไปใช้หรือแก้ไขโซลูชันของคุณ Stack Overflowไม่ใช่บริการเขียนโค้ด แต่เป็นการเรียนการสอน
Palec

1

การนำไปใช้งานแบบ "จริง" [อัลกอริทึม 8.9, 8.11 จากหนังสือการออกแบบอัลกอริทึมและการใช้งานโดย Michael T. Goodrich และ Roberto Tamassia]:

from random import randint

def partition (A, a, b):
    p = randint(a,b)
    # or mid point
    # p = (a + b) / 2

    piv = A[p]

    # swap the pivot with the end of the array
    A[p] = A[b]
    A[b] = piv

    i = a     # left index (right movement ->)
    j = b - 1 # right index (left movement <-)

    while i <= j:
        # move right if smaller/eq than/to piv
        while A[i] <= piv and i <= j:
            i += 1
        # move left if greater/eq than/to piv
        while A[j] >= piv and j >= i:
            j -= 1

        # indices stopped moving:
        if i < j:
            # swap
            t = A[i]
            A[i] = A[j]
            A[j] = t
    # place pivot back in the right place
    # all values < pivot are to its left and 
    # all values > pivot are to its right
    A[b] = A[i]
    A[i] = piv

    return i

def IpQuickSort (A, a, b):

    while a < b:
        p = partition(A, a, b) # p is pivot's location

        #sort the smaller partition
        if p - a < b - p:
            IpQuickSort(A,a,p-1)
            a = p + 1 # partition less than p is sorted
        else:
            IpQuickSort(A,p+1,b)
            b = p - 1 # partition greater than p is sorted


def main():
    A =  [12,3,5,4,7,3,1,3]
    print A
    IpQuickSort(A,0,len(A)-1)
    print A

if __name__ == "__main__": main()

1

อัลกอริทึมมี 4 ขั้นตอนง่ายๆ:

  1. แบ่งอาร์เรย์ออกเป็น 3 ส่วนที่แตกต่างกัน: ซ้าย, เดือยและขวาโดยที่เดือยจะมีเพียงองค์ประกอบเดียว ให้เราเลือกองค์ประกอบ Pivot นี้เป็นองค์ประกอบแรกของอาร์เรย์
  2. ผนวกองค์ประกอบเข้ากับส่วนที่เกี่ยวข้องโดยการเปรียบเทียบกับองค์ประกอบเดือย (คำอธิบายในความคิดเห็น)
  3. เรียกคืนอัลกอริทึมนี้จนกว่าองค์ประกอบทั้งหมดในอาร์เรย์จะได้รับการจัดเรียง
  4. สุดท้ายเข้าร่วมส่วนซ้าย + เดือย + ขวา

รหัสสำหรับอัลกอริทึมใน python:

def my_sort(A):

      p=A[0]                                       #determine pivot element. 
      left=[]                                      #create left array
      right=[]                                     #create right array
      for i in range(1,len(A)):
        #if cur elem is less than pivot, add elem in left array
        if A[i]< p:
          left.append(A[i])         
          #the recurssion will occur only if the left array is atleast half the size of original array
          if len(left)>1 and len(left)>=len(A)//2:          
              left=my_sort(left)                            #recursive call
        elif A[i]>p: 
          right.append(A[i])                                #if elem is greater than pivot, append it to right array
          if len(right)>1 and len(right)>=len(A)//2:        # recurssion will occur only if length of right array is atleast the size of original array
              right=my_sort(right)
     A=left+[p]+right                                        #append all three part of the array into one and return it
     return A

my_sort([12,4,5,6,7,3,1,15])

ดำเนินการตามอัลกอริทึมนี้ซ้ำโดยใช้ส่วนซ้ายและขวา


1

การใช้งาน Quicksort อื่น:

# A = Array 
# s = start index
# e = end index
# p = pivot index
# g = greater than pivot boundary index

def swap(A,i1,i2):
  A[i1], A[i2] = A[i2], A[i1]

def partition(A,g,p):
    # O(n) - just one for loop that visits each element once
    for j in range(g,p):
      if A[j] <= A[p]:
        swap(A,j,g)
        g += 1

    swap(A,p,g)
    return g

def _quicksort(A,s,e):
    # Base case - we are sorting an array of size 1
    if s >= e:
      return

    # Partition current array
    p = partition(A,s,e)
    _quicksort(A,s,p-1) # Left side of pivot
    _quicksort(A,p+1,e) # Right side of pivot

# Wrapper function for the recursive one
def quicksort(A):
    _quicksort(A,0,len(A)-1)

A = [3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2,3,-1]

print(A)
quicksort(A)
print(A)

1

สำหรับเวอร์ชัน Python 3.x : รูปแบบการทำงานโดยใช้operatorโมดูลเพื่อปรับปรุงความสามารถในการอ่านเป็นหลัก

from operator import ge as greater, lt as lesser

def qsort(L): 
    if len(L) <= 1: return L
    pivot   = L[0]
    sublist = lambda op: [*filter(lambda num: op(num, pivot), L[1:])]

    return qsort(sublist(lesser))+ [pivot] + qsort(sublist(greater))

และได้รับการทดสอบเป็น

print (qsort([3,1,4,2,5]) == [1,2,3,4,5])

นีซ (เท่าที่รหัสที่ไม่มีเอกสารไป) ถ้าคล้ายกับของ acarca , นัลโด้พี Figueira Figueira ของและเบอร์เกอร์ของคำตอบจากปีที่ผ่านมา … complete my code?ไม่แน่ใจว่านี้เป็นคำตอบเมื่อคำถามอ่าน การใช้lambdaเพื่อกำหนดsublist()ดูไม่จำเป็นอย่างยิ่ง
greybeard

@greybeard จริงๆแล้วโค้ดของ Arnaldo ไม่ได้รวบรวมใน Python 3 นอกจากนี้sublistจะกำหนดได้filterอย่างไรโดยใช้? เป็นไปได้หรือไม่?
lifebalance

1
(ความคิดเห็นชั่วคราว: คิดถึงdef- ยังไม่ได้เริ่มต้นการซ่อมแซมในขณะที่ฉันกำลังพยายามคิดว่ามีวิธีที่มีประสิทธิภาพมากกว่าในการ "กระจาย" องค์ประกอบของรายการที่ทำซ้ำไปยังรายการแยกต่างหาก (หรือหรืออีกทางหนึ่งคือรายการเดียวกับรายการเดียว " หมวดหมู่ "ตามหลังอื่น ๆ ))
greybeard

1

นี่คือการใช้งานที่ง่าย: -

def quicksort(array):
            if len(array) < 2:
                  return array
            else:
                  pivot= array[0]
                  less = [i for i in array[1:] if i <= pivot]

                  greater = [i for i in array[1:] if i > pivot]

                  return quicksort(less) + [pivot] + quicksort(greater)

print(quicksort([10, 5, 2, 3]))

0
  1. อันดับแรกเราประกาศค่าแรกในอาร์เรย์เป็น pivot_value และเรายังกำหนดเครื่องหมายซ้ายและขวา
  2. เราสร้างลูปในขณะแรกขณะที่ลูปจะบอกให้กระบวนการพาร์ติชันทำงานอีกครั้งหากไม่เป็นไปตามเงื่อนไขที่จำเป็น
  3. จากนั้นเราใช้กระบวนการพาร์ติชัน
  4. หลังจากที่กระบวนการพาร์ติชันทั้งสองทำงานแล้วเราจะตรวจสอบว่าเป็นไปตามเงื่อนไขที่เหมาะสมหรือไม่ ถ้าเป็นเช่นนั้นเราจะทำเครื่องหมายว่าเสร็จสิ้นถ้าไม่เราสลับค่าซ้ายและขวาแล้วใช้อีกครั้ง
  5. เมื่อเสร็จแล้วให้สลับค่าซ้ายและขวาและส่งคืน Split_point

ฉันกำลังแนบรหัสด้านล่าง! quicksort นี้เป็นเครื่องมือการเรียนรู้ที่ดีเพราะของสถานที่ตั้งของค่าเดือย เนื่องจากอยู่ในสถานที่ที่คงที่คุณสามารถเดินผ่านหลาย ๆ ครั้งและเข้าใจวิธีการทำงานทั้งหมด ในทางปฏิบัติควรสุ่มเดือยเพื่อหลีกเลี่ยงรันไทม์ O (N ^ 2)

def quicksort10(alist):
    quicksort_helper10(alist, 0, len(alist)-1)

def quicksort_helper10(alist, first, last):
    """  """
    if first < last:
        split_point = partition10(alist, first, last)
        quicksort_helper10(alist, first, split_point - 1)
        quicksort_helper10(alist, split_point + 1, last)

def partition10(alist, first, last):
    done = False
    pivot_value = alist[first]
    leftmark = first + 1
    rightmark = last
    while not done:
        while leftmark <= rightmark and alist[leftmark] <= pivot_value:
            leftmark = leftmark + 1
        while leftmark <= rightmark and alist[rightmark] >= pivot_value:
            rightmark = rightmark - 1

        if leftmark > rightmark:
            done = True
        else:
            temp = alist[leftmark]
            alist[leftmark] = alist[rightmark]
            alist[rightmark] = temp
    temp = alist[first]
    alist[first] = alist[rightmark]
    alist[rightmark] = temp
    return rightmark

0
def quick_sort(l):
    if len(l) == 0:
        return l
    pivot = l[0]
    pivots = [x for x in l if x == pivot]
    smaller = quick_sort([x for x in l if x < pivot])
    larger = quick_sort([x for x in l if x > pivot])
    return smaller + pivots + larger

คำตอบอื่น ๆ อีก 18 คำซึ่งมากกว่าครึ่งหนึ่งตอบคำถามดั้งเดิมของ OP ที่ว่า "จะต่ออาร์เรย์ทั้งสามได้อย่างไร" คำตอบของคุณเพิ่มอะไรใหม่หรือไม่?
Teepeemm

0

ตัวอย่างเต็มพร้อมตัวแปรที่พิมพ์ในขั้นตอนพาร์ติชัน:

def partition(data, p, right):
    print("\n==> Enter partition: p={}, right={}".format(p, right))
    pivot = data[right]
    print("pivot = data[{}] = {}".format(right, pivot))

    i = p - 1  # this is a dangerous line

    for j in range(p, right):
        print("j: {}".format(j))
        if data[j] <= pivot:
            i = i + 1
            print("new i: {}".format(i))
            print("swap: {} <-> {}".format(data[i], data[j]))
            data[i], data[j] = data[j], data[i]

    print("swap2: {} <-> {}".format(data[i + 1], data[right]))
    data[i + 1], data[right] = data[right], data[i + 1]
    return i + 1


def quick_sort(data, left, right):
    if left < right:
        pivot = partition(data, left, right)
        quick_sort(data, left, pivot - 1)
        quick_sort(data, pivot + 1, right)

data = [2, 8, 7, 1, 3, 5, 6, 4]

print("Input array: {}".format(data))
quick_sort(data, 0, len(data) - 1)
print("Output array: {}".format(data))

0
def is_sorted(arr): #check if array is sorted
    for i in range(len(arr) - 2):
        if arr[i] > arr[i + 1]:
            return False
    return True

def qsort_in_place(arr, left, right): #arr - given array, #left - first element index, #right - last element index
    if right - left < 1: #if we have empty or one element array - nothing to do
        return
    else:
        left_point = left #set left pointer that points on element that is candidate to swap with element under right pointer or pivot element
        right_point = right - 1 #set right pointer that is candidate to swap with element under left pointer

        while left_point <= right_point: #while we have not checked all elements in the given array
            swap_left = arr[left_point] >= arr[right] #True if we have to move that element after pivot
            swap_right = arr[right_point] < arr[right] #True if we have to move that element before pivot

            if swap_left and swap_right: #if both True we can swap elements under left and right pointers
                arr[right_point], arr[left_point] = arr[left_point], arr[right_point]
                left_point += 1
                right_point -= 1
            else: #if only one True we don`t have place for to swap it
                if not swap_left: #if we dont need to swap it we move to next element
                    left_point += 1
                if not swap_right: #if we dont need to swap it we move to prev element
                    right_point -= 1

        arr[left_point], arr[right] = arr[right], arr[left_point] #swap left element with pivot

        qsort_in_place(arr, left, left_point - 1) #execute qsort for left part of array (elements less than pivot)
        qsort_in_place(arr, left_point + 1, right) #execute qsort for right part of array (elements most than pivot)

def main():
    import random
    arr = random.sample(range(1, 4000), 10) #generate random array
    print(arr)
    print(is_sorted(arr))
    qsort_in_place(arr, 0, len(arr) - 1)
    print(arr)
    print(is_sorted(arr))

if __name__ == "__main__":
    main()

1
กรุณาให้คำอธิบาย
ไร่

0

อัลกอริทึมนี้ไม่ใช้ฟังก์ชันวนซ้ำ

อนุญาตNเป็นรายการใด ๆ len(N) > 0ของตัวเลขที่มี ตั้งค่าK = [N]และรันโปรแกรมต่อไปนี้

หมายเหตุ: นี่เป็นอัลกอริทึมการเรียงลำดับที่เสถียร

def BinaryRip2Singletons(K, S):
    K_L = []
    K_P = [ [K[0][0]] ] 
    K_R = []
    for i in range(1, len(K[0])):
        if   K[0][i] < K[0][0]:
            K_L.append(K[0][i])
        elif K[0][i] > K[0][0]:
            K_R.append(K[0][i])
        else:
            K_P.append( [K[0][i]] )
    K_new = [K_L]*bool(len(K_L)) + K_P + [K_R]*bool(len(K_R)) + K[1:]
    while len(K_new) > 0:
        if len(K_new[0]) == 1:
            S.append(K_new[0][0])
            K_new = K_new[1:]
        else: 
            break
    return K_new, S

N = [16, 19, 11, 15, 16, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1]
K = [ N ]
S = []

print('K =', K, 'S =', S)
while len(K) > 0:
    K, S = BinaryRip2Singletons(K, S)
    print('K =', K, 'S =', S)

เอาท์พุทโปรแกรม:

K = [[16, 19, 11, 15, 16, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1]] S = []
K = [[11, 15, 10, 12, 14, 4, 10, 5, 2, 3, 4, 7, 1], [16], [16], [19]] S = []
K = [[10, 4, 10, 5, 2, 3, 4, 7, 1], [11], [15, 12, 14], [16], [16], [19]] S = []
K = [[4, 5, 2, 3, 4, 7, 1], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = []
K = [[2, 3, 1], [4], [4], [5, 7], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = []
K = [[5, 7], [10], [10], [11], [15, 12, 14], [16], [16], [19]] S = [1, 2, 3, 4, 4]
K = [[15, 12, 14], [16], [16], [19]] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11]
K = [[12, 14], [15], [16], [16], [19]] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11]
K = [] S = [1, 2, 3, 4, 4, 5, 7, 10, 10, 11, 12, 14, 15, 16, 16, 19]

0

อาจเป็นเพียงสิ่งที่ต้องการ แต่ฉันต้องการเพิ่มการตรวจสอบความถูกต้องที่ด้านบนของฟังก์ชันของฉัน

def quicksort(arr):
  if len(arr) <= 1:
    return arr

  left  = []
  right = []
  equal = []
  pivot = arr[-1]
  for num in arr:
    if num < pivot:
      left.append(num)
    elif num == pivot:
      equal.append(num)
    else:
      right.append(num)

  return quicksort(left) + equal + quicksort(right)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.