Python Forum
Don't understand why this quicksort code works
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Don't understand why this quicksort code works
#1
Hi, here there's a quicksort code in Python 3.
It works but my problem is this: i understand what the partition function makes, but i don't understand how the quickSort function is able to change the list if the partition function returns an index, not an element of the list.

Has anyone any hint or advise in order to give me an insight?

def partition(alist,first,last):
   pivotvalue = alist[first]

   leftmark = first+1
   rightmark = last

   done = False
   while not done:

       while leftmark <= rightmark and alist[leftmark] <= pivotvalue:
           leftmark = leftmark + 1

       while alist[rightmark] >= pivotvalue and rightmark >= leftmark:
           rightmark = rightmark -1

       if rightmark < leftmark:
           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

def quickSort(alist,first,last):
   if first<last:

       splitpoint = partition(alist,first,last)

       quickSort(alist,first,splitpoint-1)
       quickSort(alist,splitpoint+1,last)


alist = [4,2,11,1,5]
quickSort(alist,0,len(alist)-1)
print(alist)
Output:
[1, 2, 4, 5, 11]
Reply
#2
It doesn't need to return an element, because it's already moved the items (in place).
Reply
#3
(Mar-26-2018, 04:02 PM)nilamo Wrote: It doesn't need to return an element, because it's already moved the items (in place).

Yes, but i don't understand how the QuickSort function is able to move the items in place...(in this case when i say "how" i mean "in which part of the function" this process happens).

I'm studying on the book "Introduction to Algorithms" and it's the first algorithm that i'm not able to understand even after hours..
Reply
#4
Lines 19-21 are where two values are switched (within a while loop), and at the end of the function, lines 23-25, there's another two values switching places.

In a nutshell, leftmark is increased until it's an index to a value that's larger than the value rightmark is an index to, then those two values exchange places. And that's done repeatedly, until no values in the range are larger than any of the values to their right.

I don't think I can explain it very well, so instead, I took your function and added some print functions to it, so we can see what's happening at every step of the process:
def partition(alist, first, last):
    pivotvalue = alist[first]

    leftmark = first + 1
    rightmark = last

    print("Starting partition: pivotvalue={0}".format(pivotvalue))

    done = False
    while not done:

        while leftmark <= rightmark and alist[leftmark] <= pivotvalue:
            leftmark = leftmark + 1

        while alist[rightmark] >= pivotvalue and rightmark >= leftmark:
            rightmark = rightmark - 1

        print("finding indices complete: leftmark={0}, rightmark={1}".format(
            leftmark, rightmark))

        if rightmark < leftmark:
            done = True
        else:
            print("moving values: alist[{0}]={1} <-> alist[{2}]={3}".format(
                leftmark, alist[leftmark], rightmark, alist[rightmark]))
            temp = alist[leftmark]
            alist[leftmark] = alist[rightmark]
            alist[rightmark] = temp

    print("moving pivotvalue to final position: alist[{0}]={1} <-> alist[{2}]={3}".format(
        first, alist[first], rightmark, alist[rightmark]))
    temp = alist[first]
    alist[first] = alist[rightmark]
    alist[rightmark] = temp

    return rightmark


def quickSort(alist, first, last):
    print("Entering quickSort: alist={0}, first={1}, last={2}".format(
        alist, first, last))
    if first < last:

        splitpoint = partition(alist, first, last)
        print("partition() complete, splitpoint={0}".format(splitpoint))
        print()
        quickSort(alist, first, splitpoint - 1)
        quickSort(alist, splitpoint + 1, last)


alist = [4, 2, 11, 1, 5]
quickSort(alist, 0, len(alist) - 1)
print(alist)
Output:
>python spam.py Entering quickSort: alist=[4, 2, 11, 1, 5], first=0, last=4 Starting partition: pivotvalue=4 finding indices complete: leftmark=2, rightmark=3 moving values: alist[2]=11 <-> alist[3]=1 finding indices complete: leftmark=3, rightmark=2 moving pivotvalue to final position: alist[0]=4 <-> alist[2]=1 partition() complete, splitpoint=2 Entering quickSort: alist=[1, 2, 4, 11, 5], first=0, last=1 Starting partition: pivotvalue=1 finding indices complete: leftmark=1, rightmark=0 moving pivotvalue to final position: alist[0]=1 <-> alist[0]=1 partition() complete, splitpoint=0 Entering quickSort: alist=[1, 2, 4, 11, 5], first=0, last=-1 Entering quickSort: alist=[1, 2, 4, 11, 5], first=1, last=1 Entering quickSort: alist=[1, 2, 4, 11, 5], first=3, last=4 Starting partition: pivotvalue=11 finding indices complete: leftmark=5, rightmark=4 moving pivotvalue to final position: alist[3]=11 <-> alist[4]=5 partition() complete, splitpoint=4 Entering quickSort: alist=[1, 2, 4, 5, 11], first=3, last=3 Entering quickSort: alist=[1, 2, 4, 5, 11], first=5, last=4 [1, 2, 4, 5, 11]
Reply
#5
(Mar-26-2018, 06:33 PM)nilamo Wrote:
Output:
>python spam.py Entering quickSort: alist=[4, 2, 11, 1, 5], first=0, last=4 Starting partition: pivotvalue=4 finding indices complete: leftmark=2, rightmark=3 moving values: alist[2]=11 <-> alist[3]=1 finding indices complete: leftmark=3, rightmark=2 moving pivotvalue to final position: alist[0]=4 <-> alist[2]=1 partition() complete, splitpoint=2 Entering quickSort: alist=[1, 2, 4, 11, 5], first=0, last=1 Starting partition: pivotvalue=1 finding indices complete: leftmark=1, rightmark=0 moving pivotvalue to final position: alist[0]=1 <-> alist[0]=1 partition() complete, splitpoint=0 Entering quickSort: alist=[1, 2, 4, 11, 5], first=0, last=-1 Entering quickSort: alist=[1, 2, 4, 11, 5], first=1, last=1 Entering quickSort: alist=[1, 2, 4, 11, 5], first=3, last=4 Starting partition: pivotvalue=11 finding indices complete: leftmark=5, rightmark=4 moving pivotvalue to final position: alist[3]=11 <-> alist[4]=5 partition() complete, splitpoint=4 Entering quickSort: alist=[1, 2, 4, 5, 11], first=3, last=3 Entering quickSort: alist=[1, 2, 4, 5, 11], first=5, last=4 [1, 2, 4, 5, 11]

Thank you so much, now i've understood the whole process/algorithm (damn! is very hard to grasp all these recursions for someone that he's been studying programming for only 3 months like me...) but there is a last thing that i don't understand.

Why all the process that happens in that 2 functions remains outside the functions without any definition of global variables?

I mean, if i code:

def f(x):
    x = x * 2
    return ('a casual expression')

x = 3

f(x)

print(x)
The output is 3, not 6 because x in the function is a local variable and it can't change the global variable x.

I hope i was able to explain my doubt...
Reply
#6
Because the data structure is a list, which is mutable. When you assign something to a variable (x = 42), the old value of the variable still exists, but there's a new binding to the new value. But with lists, the actual variable was never reassigned, the only thing that changed was the contents of the list.

Using your example...
>>> def f(x):
...   x[0] = x[0] * 2
...   return "unrelated string"
...
>>> x = [5, 4, 3, 2, 1, 0]
>>> f(x)
'unrelated string'
>>> x
[10, 4, 3, 2, 1, 0]
>>> # but if we were to re-assign x, instead of using an element...
...
>>> def f(x):
...   x = ['green', 'eggs', 'and', 'spam']
...   return 0
...
>>> x
[10, 4, 3, 2, 1, 0]
>>> f(x)
0
>>> x
[10, 4, 3, 2, 1, 0]
Reply
#7
(Mar-26-2018, 08:17 PM)nilamo Wrote: Because the data structure is a list, which is mutable. When you assign something to a variable (x = 42), the old value of the variable still exists, but there's a new binding to the new value. But with lists, the actual variable was never reassigned, the only thing that changed was the contents of the list.

Using your example...
>>> def f(x):
...   x[0] = x[0] * 2
...   return "unrelated string"
...
>>> x = [5, 4, 3, 2, 1, 0]
>>> f(x)
'unrelated string'
>>> x
[10, 4, 3, 2, 1, 0]
>>> # but if we were to re-assign x, instead of using an element...
...
>>> def f(x):
...   x = ['green', 'eggs', 'and', 'spam']
...   return 0
...
>>> x
[10, 4, 3, 2, 1, 0]
>>> f(x)
0
>>> x
[10, 4, 3, 2, 1, 0]

Thank you so much, now i've understood
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Unable to understand the meaning of the line of code. jahuja73 0 312 Jan-23-2024, 05:09 AM
Last Post: jahuja73
  My code works on Jupyter Lab/Notebook, but NOT on Visual Code Editor jst 4 1,052 Nov-15-2023, 06:56 PM
Last Post: jst
  Code works but doesn't give the right results colin_dent 2 727 Jun-22-2023, 06:04 PM
Last Post: jefsummers
  Code used to work 100%, now sometimes works! muzicman0 5 1,449 Jan-13-2023, 05:09 PM
Last Post: muzicman0
  Pyspark - my code works but I want to make it better Kevin 1 1,797 Dec-01-2021, 05:04 AM
Last Post: Kevin
Question email code works in 2.7 but not in 3 micksulley 3 2,594 Nov-04-2021, 09:44 PM
Last Post: micksulley
  My simple code don't works !! Nabi666 1 1,620 Sep-06-2021, 12:10 PM
Last Post: jefsummers
  HackerRank Problem: Code works on VS Code but not on the HackerRank site Pnerd 3 2,649 Feb-28-2021, 07:12 PM
Last Post: Pnerd
Question Google Foobar- Code works in my IDE but not in foobar. Static method? pr3ttykitty 4 4,961 Feb-24-2021, 05:03 PM
Last Post: nilamo
  Unable to understand how given code takes a fixed input value, without inputting. jahuja73 4 2,713 Jan-28-2021, 05:22 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020