I'm working on understanding and implementing a merge sort. I'm running into a brick wall on this one, and can't seem to get an implementation that works. My current implementation hits a "list index out of range" error. Here is my code:
def merge_sort(list_a):
mid = len(list_a) // 2
print('Mid is ', mid)
while len(list_a) > 1:
left = list_a[:mid]
print('Left is now ', left)
right = list_a[mid:]
print('Right is now ', right)
merge_sort(left)
merge_sort(right)
merge(list_a, left, right)
def merge(comb_list, list_a, list_b):
print('Starting the merge.')
a1, b1, c1 = 0, 0, 0
na, nb, nc = len(list_a), len(list_b), len(comb_list)
while a1 < na and b1 < nb:
if list_a[a1] < list_b[b1]:
print('Adding from A')
comb_list[c1] = list_a[a1]
a1 += 1
else:
print('Adding from B')
comb_list[c1] = list_b[b1]
b1 += 1
c1 += 1
while list_a:
comb_list[c1] = list_a[a1]
c1 += 1
a1 += 1
while list_b:
comb_list[c1] = list_b[b1]
c1 += 1
b1 += 1
if __name__ == '__main__':
list_a = [54,26,93,17,77,31,44,55,20]
merge_sort(list_a)
I have made three changes to your script to get it to work. As pointed by sshdup while list_a
will always evaluate to true as you don't remove any elements inside the loop. Therefore I have changed while list_a:
to len(list_a)>a1
, while list_b:
to len(list_b)>b1
. I also added return merge(list_a, left, right)
to your merge_sort
method in line with the pseudo code . After adding the return
statement the while
in merge_sort
can also be replaced with an if
statement. I have tested this on a random array of integers and it seems to work, however, as usual you should test your edge cases to make sure it works as expected.
def merge_sort(list_a):
mid = len(list_a) // 2
print('Mid is ', mid)
if len(list_a) > 1:
left = list_a[:mid]
print('Left is now ', left)
right = list_a[mid:]
print('Right is now ', right)
merge_sort(left)
merge_sort(right)
return merge(list_a, left, right)
def merge(comb_list, list_a, list_b):
print('Starting the merge.')
a1, b1, c1 = 0, 0, 0
na, nb, nc = len(list_a), len(list_b), len(comb_list)
while a1 < na and b1 < nb:
if list_a[a1] < list_b[b1]:
print('Adding from A')
comb_list[c1] = list_a[a1]
a1 += 1
else:
print('Adding from B')
comb_list[c1] = list_b[b1]
b1 += 1
c1 += 1
while len(list_a)>a1:
comb_list[c1] = list_a[a1]
del list_a[a1]
c1 += 1
a1 += 1
while len(list_b)>b1:
comb_list[c1] = list_b[b1]
c1 += 1
b1 += 1
if __name__ == '__main__':
list_a = [54,26,93,17,77,31,44,55,20]
merge_sort(list_a)
print list_a
To make the code work, you would have to make 2 adjustments:
The working code:
def merge_sort(list_a):
mid = len(list_a) // 2
print('Mid is ', mid)
#Use if statement instead
if len(list_a) > 1:
left = list_a[:mid]
print('Left is now ', left)
right = list_a[mid:]
print('Right is now ', right)
merge_sort(left)
merge_sort(right)
merge(list_a, left, right)
#Print the result
print(list_a)
#Or return it directly:
#return list_a
def merge(comb_list, list_a, list_b):
print('Starting the merge.')
a1, b1, c1 = 0, 0, 0
na, nb, nc = len(list_a), len(list_b), len(comb_list)
while a1 < na and b1 < nb:
if list_a[a1] < list_b[b1]:
print('Adding from A')
comb_list[c1] = list_a[a1]
a1 += 1
else:
print('Adding from B')
comb_list[c1] = list_b[b1]
b1 += 1
c1 += 1
#Change while loop:
while a1 < na:
comb_list[c1] = list_a[a1]
c1 += 1
a1 += 1
#Change while loop:
while b1 < nb:
comb_list[c1] = list_b[b1]
c1 += 1
b1 += 1
if __name__ == '__main__':
list_a = [54,26,93,17,77,31,44,55,20]
merge_sort(list_a)
You might want to return the result directly, to do that just add
return list_a
at the end of your merge_sort() function. With that approach, you could print the result directly using print(merge_sort(list_a)) in the main method.
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.