简体   繁体   中英

Quicksort, where am I going wrong in this in-place implementation?

I'm trying to implement in-place partitioning for quicksort, but am stuck.

This is my code:

def quicksort(b):
    print("Passed b is : ",b)
    if len(b)<=1 :
        return
    p=b[0]

    i=1
    for j in range(0,len(b)):
        if b[j]<p:
            temp=b[j]
            b[j]=b[i]
            b[i]=temp
            i=i+1
    temp2=b[0]
    b[0]=b[i-1]
    b[i-1]=temp2
    print("Parially sorted b is :",b)
    print("Left half is :", b[:i-1], " Pivot is ",b[i-1], " Right half is ",b[i:])
    print("\n")
    quicksort(b[:i-1])
    quicksort(b[i:])

b=[3,1,7,2,6,5,9]
quicksort(b)
print(b)

What am I missing?

First of all, please use whitespace around operators so your code is comprehensible. Use black if you aren't sure how to format your code.

As mentioned in the comments , your implementation isn't in-place . An in-place algorithm is one that doesn't use auxiliary space and instead moves the elements around on the existing data structure. Slicing (the [:] syntax) makes a copy of your list, an immediate breach of contract.

You probably got steered off course beginning with your function parameters: def quicksort(b): . This pretty much forces you to slice. The correct parameters for an in-place algorithm are def quicksort(lst, start_index, end_index): , where the indices designate the subsequence of the list that a particular quicksort call should operate on. Each function call must not touch any other portion of the list outside the designated range. The code should set all indices relative to these parameters.

Of course, you don't want to burden the client with having to specify these initial indices correctly, so the normal approach is to use default arguments:

def quicksort(lst, start_index=0, end_index=None):
    if end_index is None:
        end_index = len(lst)
    ...

...or a wrapper call:

def quicksort(lst):
    def qsort(lst, start_index, end_index):
        ...

    qsort(lst, 0, len(lst))

With that in place, you're ready for the logic, which looks generally OK. After a cleanup and some spot tests, we have:

def quicksort(lst):
    def qsort(lst, start_i, end_i):
        if end_i - start_i <= 1:
            return

        pivot = lst[start_i]
        i = start_i + 1

        for j in range(start_i + 1, end_i):
            if lst[j] < pivot:
                lst[j], lst[i] = lst[i], lst[j]
                i += 1

        lst[i-1], lst[start_i] = lst[start_i], lst[i-1]
        qsort(lst, start_i, i - 1)
        qsort(lst, i, end_i)

    qsort(lst, 0, len(lst))


if __name__ == "__main__":
    from random import randint

    for _ in range(3000):
        lst = [randint(-3000, 3000) for _ in range(1000)]
        cpy = lst[:]
        quicksort(lst)

        if sorted(cpy) != lst:
            print("FAIL")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM