I got a task to sort data with quicksort in-place. The input is a list of lists (name, score1, score2).
The data should be sorted by score1 in descending order, then (if equal) by score2 in ascending order, then (if equal) by name in ascending order.
Example input:
5
antony 4 100
jack 6 1000
jerry 2 90
ricky 2 90
timy 4 80
Expected output:
jack
timy
antony
jerry
ricky
So far I have coded the quicksort in-place algorithm and tested it with some custom input, but I can't figure out how to compare values in a list of lists. Or is there any other way to do this comparison?
import random
def compare(l1, l2):
if l1[1] > l2[1]:
return True
elif l1[1] == l2[1] and l1[2] < l2[2]:
return True
elif l1[2] == l2[2] and l1[1] == l2[1] and l1[0] > l1[0]:
return True
else:
return False
def quicksort(A, l=0, r=None):
if r is None:
r = len(A) - 1
# end = len(array) - 1
if l >= r:
return
else:
q = random.choice(A[l:r 1])
i = l
j = r
while i <= j:
while compare(q, A[i]):
i = 1
while compare(A[j], q):
j -= 1
if i <= j:
A[i], A[j] = A[j], A[i]
i = 1
j -= 1
quicksort(A, l, j)
quicksort(A, i, r)
return A
def read_input():
k = int(input())
values = []
while k > 0:
n = input().split()
values.append(n[0])
values.append(n[1])
values.append(n[2])
k -= 1
return values
CodePudding user response:
There are the following issues in your code:
read_input
reads all values in a 1 dimensional list, i.e. it doesn't create a list of tripletsread_input
does not convert the scores toint
data type, but leaves them as strings, which will have an impact on how they are compared bycompare
To solve these two issues, change the body of the loop in
read_input
with this:name, score1, score2 = input().split() values.append([name, int(score1), int(score2)]) k -= 1
compare
returnsTrue
when the first argument should be ordered after the second argument. When you callcompare
you treatTrue
as a message not to swap. But you pass the arguments in the order as they appear in the input, which means you should swap when you getTrue
. So here the code is wrong. Fix by passing the arguments in opposite order.The recursive calls of
quickSort
are made at the wrong time. These calls should not be done during the loop, but after it.quicksort
has areturn
without list and areturn A
with list. This is not consistent. Asquicksort
is inplace it is more pythonic to not return the list, so change that finalreturn
. The caller should take the list that it passed as argument, which will have been sorted.compare
has a typo in the string comparison: it hasl1[0] > l1[0]
(the two operands are the same), which should bel2[0] > l1[0]
Here is your code with the above mentioned corrections:
def compare(l1, l2):
if l1[1] > l2[1]:
return True
elif l1[1] == l2[1] and l1[2] < l2[2]:
return True
elif l1[2] == l2[2] and l1[1] == l2[1] and l2[0] > l1[0]:
return True
else:
return False
def quicksort(A, l=0, r=None):
if r is None:
r = len(A) - 1
if l >= r:
return
else:
q = random.choice(A[l:r 1])
i = l
j = r
while i <= j:
while compare(A[i], q): # args swapped
i = 1
while compare(q, A[j]): # args swapped
j -= 1
if i <= j:
A[i], A[j] = A[j], A[i]
i = 1
j -= 1
quicksort(A, l, j) # Fixed indentation
quicksort(A, i, r)
return # Don't return A
def read_input():
k = int(input())
values = []
while k > 0:
name, score1, score2 = input().split()
# Append a triple, and convert the scores to int:
values.append([name, int(score1), int(score2)])
k -= 1
return values