Reputation: 479
I am working on merge sort using recursive Python. I couldn't find out where I made mistake and always got wrong answers. The code is as follows:
def mergeSort(xlist):
print ('Splitting',xlist, len(xlist))
if len(xlist)>1:
midpoint = len(xlist) // 2
left = xlist[:midpoint]
right = xlist[midpoint:]
print ('----------------------------')
mergeSort(left)
mergeSort(right)
print (left, 'r', right)
while len(right) >0:
left.append(right[0])
right.remove(right[0])
slot= len(left)-1
while slot >0:
if left[slot] < left[slot-1]: left[slot], left[slot-1] = left[slot-1], left[slot]
slot -= 1
print ('sorted',left, right,xlist)
return left
print('A',mergeSort([100,1,91,54]))
When merging, the output also shows in the wrong way, like:
Splitting [100, 1, 91, 54]
----------------------------
Splitting [100, 1] 2
----------------------------
Splitting [100] 1
Splitting [1] 1
[100] r [1]
sorted [1, 100] [] [100, 1]
Splitting [91, 54] 2
----------------------------
Splitting [91] 1
Splitting [54] 1
[91] r [54]
sorted [54, 91] [] [91, 54]
[100, 1] r [91, 54]
sorted [1, 54, 100, 91] [] [100, 1, 91, 54]
A [1, 54, 100, 91]
I expect the last third line should be "[1,100] r [54, 91]" after return back. What is wrong here? I know there is a code in interactivePython.org, but I wish to understand where I made logical mistake. Can anyone help me? A ton of thanks!
Upvotes: 1
Views: 122
Reputation: 77837
It took me a few minutes, but I found it. You recur on the left & right halves properly, but then you throw away the results and merge the original lists. Correction:
print ('----------------------------')
left = mergeSort(left)
right = mergeSort(right)
I expect you can see the effect now.
Here's the working code that produced the output above:
def mergeSort(xlist):
print 'Splitting', xlist, len(xlist)
if len(xlist) <= 1:
return xlist
else:
midpoint = len(xlist) // 2
left = xlist[:midpoint]
right = xlist[midpoint:]
print ('----------------------------')
left = mergeSort(left)
right = mergeSort(right)
print left, 'r', right
# print "merge", left, right
while len(right) > 0:
left.append(right[0])
right.remove(right[0])
slot = len(left) - 1
while slot > 0:
if left[slot] < left[slot-1]:
left[slot], left[slot-1] = left[slot-1], left[slot]
# print "switched", left
slot -= 1
print 'sorted', left, right, xlist
return left
print 'A',mergeSort([100,1,91,54])
Output:
A Splitting [100, 1, 91, 54] 4
----------------------------
Splitting [100, 1] 2
----------------------------
Splitting [100] 1
Splitting [1] 1
[100] r [1]
sorted [1, 100] [] [100, 1]
Splitting [91, 54] 2
----------------------------
Splitting [91] 1
Splitting [54] 1
[91] r [54]
sorted [54, 91] [] [91, 54]
[1, 100] r [54, 91]
sorted [1, 54, 91, 100] [] [100, 1, 91, 54]
[1, 54, 91, 100]
Upvotes: 0
Reputation: 104712
You need to decide whether your mergesort
code is going to modify the list it is passed in place, or if it is going to return a new list. The top part of your code is written as if it will modify the list in place. The bottom half is written as if it returns a new list. They both need to work the same way, or the sort won't work.
If you want to stick with the modify-in-place approach, the top part of the code is fine, it's just the merging of left
and right
at the end that you need to fix up. Instead of merging into left
, you need to merge into xlist
. I'd suggest using separate indexes into each of the three lists, rather than doing costly insertions into left
like you're currently doing.
If you want to return a new list, you need to change the top part of the code. If you hit the base case (len(xlist) < 2
), you need to return xlist
unmodified. You also need to save the return values from the recursive calls, perhaps with left = mergesort(left)
and right = mergesort(right)
. Your later merging code is probably OK, though it discards most of the performance advantages of merge sort, since the insertion logic is O(N**2)
.
Upvotes: 1