Reputation: 6221
I am trying to use mergesort--which I get--to count the number of split inversions in a list (that is, where an element in the first half of the unsorted list should appear after a given element in the second half of the unsorted list; for example [3 2 1 4] would contain the split inversion (3, 1), but not (3, 2) as 3 and 2 are both in the first half). When I get to the final print statement, I am getting the answer I expect--in this case 9--but the return value is all wonky since it's returning the split value through the recursion. I've tried all sorts of combinations of indexing to no avail. Any help? (using Python 2.7)
(For the record, this is a Coursera homework problem, but I'm just learning for fun--no one's grading this other than me.)
def mergesort(lst):
'''Recursively divides list in halves to be sorted'''
if len(lst) is 1:
return lst
middle = int(len(lst)/2)
left = mergesort(lst[:middle])
right = mergesort(lst[middle:])
sortedlist = merge(left, right)
return sortedlist
def merge(left, right):
'''Subroutine of mergesort to sort split lists. Also returns number
of split inversions (i.e., each occurence of a number from the sorted second
half of the list appearing before a number from the sorted first half)'''
i, j = 0, 0
splits = 0
result = []
while i < len(left) and j < len(right):
if left[i] < right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
splits += len(left[i:])
result += left[i:]
result += right[j:]
print result, splits
return result, splits
print mergesort([7,2,6,4,5,1,3,8])
Upvotes: 4
Views: 5870
Reputation: 9
Since, in your code merge returns a pair, mergesort must also return a pair. Enable to get the total split inversion in the list you must add the left half, right half and merge split inversions.
Here is the modification I have made in your code.
def mergesort(lst):
'''Recursively divides list in halves to be sorted'''
if len(lst) == 1:
return lst, 0
middle = len(lst)/2
left, s1 = mergesort(lst[:middle])[0] # Ignore intermediate splits
right, s2 = mergesort(lst[middle:])[0] # Ignore intermediate splits
sortedlist, s3 = merge(left, right)
return sortedlist, (s1+s2+s3)`
Upvotes: 0
Reputation: 12174
Modify your mergesort
function to disregard the intermediate splits.
def mergesort(lst):
'''Recursively divides list in halves to be sorted'''
if len(lst) == 1:
return lst, 0
middle = len(lst)/2
left = mergesort(lst[:middle])[0] # Ignore intermediate splits
right = mergesort(lst[middle:])[0] # Ignore intermediate splits
sortedlist, splits = merge(left, right)
return sortedlist, splits
Upvotes: 3
Reputation: 17424
There's a few things wrong in your code:
int()
the result of len() / 2
. If you are using Python3, I'd directly use integer division with the //
operator.mergesort()
is wrong. Firstly, do not use is
to compare for equality. The is
operator is only intended for identity. If you have two different integers which have the same value, they are equal but not identical. For small integers, I believe that at least some Python dialects will intern the value, hence your comparison works, but you are relying on something that isn't guaranteed. Still, using ==
also doesn't work, because you forgot the case of the empty list.merge()
calls.Upvotes: 2