I am following along with the CLRS book and am implementing all the algorithms in python as I go along, this is the merge sort algorithm. I tested the merge function on a test array and it works, so it must be the merge_sort function, however it's pretty much the same as the pseudocode in the book.
def merge_sort(self, array, p, r):
if p < r:
q = int((p + r) / 2)
self.merge_sort(array, p, q)
self.merge_sort(array, q + 1, r)
self.merge(array, p, q , r)
def merge(self, array, p, q, r):
n1 = q - p + 1
n2 = r - q
left = []
right = []
for i in range(0, n1):
left.append(array[p + i])
for j in range (0, n2):
right.append(array[q + j + 1])
left.append(math.inf)
right.append(math.inf)
i = 0
j = 0
for k in range(p, r):
if left[i] <= right[j]:
array[k] = left[i]
i += 1
else:
array[k] = right[j]
j += 1
I'm going to guess that this:
for k in range(p, r):
should be:
for k in range(p, r + 1):
This will make k take on all values from p to r, before it was taking on the values of p to r - 1 -- just the way range() works.
Related
I am trying to writing the algorithm for merge sort in Python, but I am not getting the correct output. The error I am getting is "list assignment index out of range", so there is some logical error.
This is my code:
def mergeSort(a, l, r):
if l < r:
mid = (l+r)//2
mergeSort(a, l, mid)
mergeSort(a, mid+1, r)
merge(a, l, mid, r)
def merge(a, l, mid, r):
b = []
i = l
j = mid + 1
k = l
while i <= mid and j <= r:
if a[i] < a[j]:
b[k] = a[i]
i = i + 1
else:
b[k] = a[j]
j = j + 1
k = k + 1
if i > mid:
while j <= r:
b[k] = a[j]
k = k + 1
j = j + 1
else:
while i <= mid:
b[k] = a[i]
k = k + 1
j = j + 1
for k in range(l, r+1):
a[k] = b[k]
a = []
n = int(input("Enter the number of elements: "))
print("Enter the elements now")
for i in range(0, n):
element = int(input())
a.append(element)
print("Given array: ", a)
mergeSort(a, 0, len(a) - 1)
print("Sorted array is: ", a)
The first thing is that the array out of bounds error is coming because you are using b = []. When you do b[k] = a[i], it will throw the out of bounds exception. You have to initialize the b array.
Secondly, there are some issues in the logic. I corrected your code as follows:
def mergeSort(a):
if len(a) > 1:
mid = len(a) // 2
L = a[:mid]
R = a[mid:]
mergeSort(L)
mergeSort(R)
merge(a, mid, L, R)
def merge(a, mid, L, R):
i = 0
j = 0
k = 0
while i < len(L) and j < len(R):
if L[i] < R[j]:
a[k] = L[i]
i = i + 1
else:
a[k] = R[j]
j = j + 1
k = k + 1
while j < len(R):
a[k] = R[j]
k = k + 1
j = j + 1
while i < len(L):
a[k] = L[i]
k = k + 1
i = i + 1
a = []
n = int(input("Enter the number of elements: "))
print("Enter the elements now")
for i in range(0, n):
element = int(input())
a.append(element)
print("Given array: ", a)
mergeSort(a)
print("Sorted array is: ", a)
Here are my merge and mergeSort functions. merge merges two separate arrays and mergesSort sorts and merges them with recursion:
def merge(arrL, arrR):
arrNew = []
d = len(arrL) + len(arrR)
i = 0
j = 0
for k in range (0, d-1):
if (arrL[i] < arrR[j]) :
arrNew.append(arrL[i]) # appends to the end of the array
i = i + 1
else:
arrNew.append(arrR[j])
j = j + 1
return arrNew
def mergeSort(arr, m, n):
if (n - m == 1):
return arr[m]
else:
p = (m + n) // 2
arrL = mergeSort(arr, m, p)
arrR = mergeSort(arr, p, n)
arrNew = merge(arrL, arrR)
return arrNew
I am getting an error from lines 32, 33 and 13:
d = len(arrL) + len(arrR)
TypeError: object of type 'int' has no len()
What is causing this error? merge is taking two arrays as inputs.
What is causing this error? merge is taking two arrays as inputs.
Except when it doesn't.
if(n-m == 1):
return arr[m]
This output of mergeSort is not an array.
My guess is it's this line
if(n-m == 1):
return arr[m]
which presumably is returning the content arr[m] of the array and not an array itself.
Since your code sorts arrays, when this naked element gets recursed on, it will generate the error you're seeing.
There are multiple problems in the code:
in mergeSort, you should return arr instead of arr[m] when the length of the array is less than 2. The test if (n - m == 1) does not allow for empty arrays:
if (n - m < 2):
return arr
in merge, the main loop should run d times, ie: instead of for k in range (0, d-1): you should write:
for k in range (d):
the test in the merge loop should also check if the index value in still in range. If the second slice is exhausted, the element arrL[i] should be selected:
for k in range (d):
if i < len(arrL) and (j >= len(arrR) or arrL[i] < arrR[j]):
arrNew.append(arrL[i])
i = i + 1
else:
arrNew.append(arrR[j])
j = j + 1
Here is a modified version:
def merge(arrL, arrR):
arrNew = []
i = 0
j = 0
for k in range(len(arrL) + len(arrR)):
if i < len(arrL) and (j >= len(arrR) or arrL[i] < arrR[j]):
arrNew.append(arrL[i])
i = i + 1
else:
arrNew.append(arrR[j])
j = j + 1
return arrNew
def mergeSort(arr, m, n):
if (n - m < 2):
return arr
else:
p = (m + n) // 2
arrL = mergeSort(arr, m, p)
arrR = mergeSort(arr, p, n)
return merge(arrL, arrR)
I need to implement Merge Sort using Python 3. I coded it. But It doesn't give proper output. Can anybody check it please?
Here my code is,
def mergeSort(A, p, r):
if p < r:
q = (p + r) // 2
mergeSort(A, p, q)
mergeSort(A, q+1, r)
Merge(A, p, q, r)
def Merge(A, p, q, r):
i = 1
j = q+1
k = 0
TEMP = [0] * (r+1)
while i <= q and j <= r:
if A[i] <= A[j]:
TEMP[k] = A[i]
k += 1
i += 1
else:
TEMP[k] = A[j]
k += 1
j += 1
if (j > r) :
for t in range(0, q-1):
A[r-t] = A[q-t]
for t in range(0, k-1):
A[p+t] = TEMP[t+1]
A = [15, 16, 13, 10, 19, 18]
mergeSort(A, 0, len(A)-1)
print(A)
Thank you
The way you perform merge looks weird (to me), but I will correct on what you have so far.
1- Initialization value of i is wrong, it should be:
i = p
because i is the first element you will look in array A.
2- Initialization value of size of TEMP array is wrong, it should be:
(r - p + 1)
3- There seems a mistake in filling in TEMP array and/or replacing A array elements, here is the fixed code. I wrote a comment about the part after first while loop to indicate what needs to be done at that point.
def mergeSort(A,p,r):
if p < r:
q = (p+r)//2
mergeSort(A,p,q)
mergeSort(A,q+1,r)
Merge(A,p,q,r)
def Merge(A,p,q,r):
i = p
j = q+1
k=0
TEMP = [0]*(r - p + 1)
while i <= q and j <= r:
if A[i] <= A[j]:
TEMP[k] = A[i]
k += 1
i += 1
else:
TEMP[k] = A[j]
k += 1
j += 1
"""
There are currently 2 cases
1- i > q, means we exhausted left but there are elements in the right
2- j > r, means we exhausted right but there are elements in the left
"""
if (j > r):
# copy elements at the left side to temp
while (i <= q):
TEMP[k] = A[i]
i += 1
k += 1
else:
# copy elements at the right side to temp
while (j <= r):
TEMP[k] = A[j]
j += 1
k += 1
# replace elements in A with elements in TEMP
for t in range(k):
A[p+t] = TEMP[t]
A = [15,16,13,10,19,18]
mergeSort(A,0,len(A)-1)
print(A)
The error lies in the Merge() function.
Initialisation of i=p and not i=1
After the while loop terminates, there's a chance that either i<q or j<r. We need to accommodate those cases as well.
Size of array TEMP was incorrect.
Corrected Merge Function:
def Merge(A,p,q,r):
i = p
j = q+1
k=0
TEMP = [0]*(r-p+1)
while i <= q and j <= r:
if A[i] <= A[j]:
TEMP[k] = A[i]
k += 1
i += 1
else:
TEMP[k] = A[j]
k += 1
j += 1
while i<=q:
TEMP[k] = A[i]
k+=1
i += 1
while j<=r:
TEMP[k] = A[j]
k+=1
j += 1
for t in range (p,r+1):
A[t] = TEMP[t-p]
Note: Please try using more meaningful variable names.
Why is my merge sort program not working?
def merge(a, p, q, r):
n1 = (q - p) + 1
n2 = r - q
L = [0] * n1
M = [0] * n2
for i in range(n1):
L[i] = a[i]
for j in range(n2):
M[j] = a[j]
i = 0
j = 0
for k in range(p, r):
if L[i] <= M[j]:
a[k] = L[i]
i += 1
else:
a[k] = M[j]
j += 1
def merge_sort(a, p, r):
if len(a) <= 1:
print('list has only one element')
else:
q = len(a) // 2
merge_sort(a, p, q)
merge_sort(a, q + 1, r)
merge(a, p, q, r)
a = [3,41,52,26,38,57,9,49]
merge_sort(a, 0, len(a) - 1)
for _ in range(len(a)):
print('%d', a[_])
There are multiple problems in your code:
The initialization loops for the slices are incorrect. The index into a should start at p and q+1 respectively. Change them to:
for i in range(n1):
L[i] = a[p+i]
for j in range(n2):
M[j] = a[q+1+j]
Or simply write:
L = a[p..q+1]
M = b[q+1..r+1]
Which make it obvious that q and r should be excluded bounds rather than included.
The merging loop is incorrect: the range should be range(p, r+1) and once one of the temporary arrays is exhausted, comparing L[i] <= M[j] refers to an element beyond the boundary of either L or M.
q is not computed correctly in merge_sort: it should be q = (p + r) // 2
the test if len(a) <= 1: is incorrect, you should instead test if the slice has at least 2 elements and do nothing if it does not:
if p < r:
q = (p + r) // 2
merge_sort(a, p, q)
merge_sort(a, q + 1, r)
merge(a, p, q, r)
Here is a modified version with excluded upper bounds:
def merge(a, p, q, r):
L = a[p..q]
M = a[q..r]
i = 0
j = 0
for k in range(p, r):
if j >= len(M) or (i < len(L) and L[i] <= M[j]):
a[k] = L[i]
i += 1
else:
a[k] = M[j]
j += 1
def merge_sort(a, p, r):
if r - p > 1:
q = p + (r - p) // 2
merge_sort(a, p, q)
merge_sort(a, q, r)
merge(a, p, q, r)
a = [3,41,52,26,38,57,9,49]
merge_sort(a, 0, len(a))
for _ in range(len(a)):
print('%d', a[_])
I am getting List index out of range error.
I have also used GeeksforGeeks program as a reference but still got that error.
I get no error when I run this without using it inside Merge_Sort() function.
def Merge(arr, p, q, r):
n1 = q-p+1
n2 = r-q
L = [0]*n1
M = [0]*n2
for i in range(0, n1):
L[i] = arr[p+i-1]
for j in range(0, n2):
M[j] = arr[q+j]
i = 0
j = 0
for k in range(r-1):
if L[i] <= M[j]:
arr[k] = L[i]
i = i+1
else:
arr[k] = M[j]
j = j+1
def Merge_Sort(arr, p, r):
if p < r:
q = int((p+r)/2)
Merge_Sort(arr, p, q)
Merge_Sort(arr, q+1, r)
Merge(arr, p, q, r)
ar = [5, 3, 6, 1, 2, 9, 7, 8]
n = len(ar)
Merge_Sort(ar, 1, n)
print(ar)
Error:
line 14, in Merge
if L[i]<=M[j]:
IndexError: list index out of range
The code is incorrect: the is some confusion about index values and slice boundaries, and other mistakes too:
array indices start at 0 in python, so you should call Merge_sort(ar, 0, n)
the slice length n1 is off by one, it should be n1 = q - p
the test for recursion should compute the slice length and only recurse for slices with at least 2 elements.
the merge loop is incorrect: you should test if i and j are both inside the slices. An efficient way to do this is to replace the comparison with this test:
if i < n1 and (j == n2 or L[i] <= M[j]):
the merge loop should iterate for k from p to r excluded, not from 0 to r excluded
the increment code for j is misaligned, it should be indented one more step
It is much simpler to consider the first index to be included and the second to be excluded. There are far too many tutorials in the net in various languages that insist on other conventions, invariably causing confusion for newbie programmers.
Here is a corrected and simplified version:
def Merge(arr, p, q, r):
n1 = q - p
n2 = r - q
L = arr[p : q]
M = arr[q : r]
i = 0
j = 0
for k in range(p, r):
if i < n1 and (j == n2 or L[i] <= M[j]):
arr[k] = L[i]
i = i + 1
else:
arr[k] = M[j]
j = j + 1
def Merge_Sort(arr, p, r):
if r - p >= 2:
q = (p + r) // 2
Merge_Sort(arr, p, q)
Merge_Sort(arr, q, r)
Merge(arr, p, q, r)
ar = [5, 3, 6, 1, 2, 9, 7, 8]
Merge_Sort(ar, 0, len(ar))
print(ar)
Note that you can further simplify the MergeSort function with a single temporary array if you ensure that the left slice is always at least as large as the right slice:
def Merge(arr, p, q, r):
tmp = arr[p : q]
i = 0
n = q - p
while i < n:
if q == r or tmp[i] <= arr[q]:
arr[p] = tmp[i]
i += 1
p += 1
else:
arr[p] = arr[q]
q += 1
p += 1
def Merge_Sort(arr, p, r):
if r - p >= 2:
q = (p + r + 1) // 2
Merge_Sort(arr, p, q)
Merge_Sort(arr, q, r)
Merge(arr, p, q, r)
ar = [5, 3, 6, 1, 2, 9, 7, 8]
Merge_Sort(ar, 0, len(ar))
print(ar)
Your code differs from the GeeksforGeeks code. I corrected the merge function to match theirs. You need three loops:
Take the smaller of the first elements from L or M until either L or M is empty
Append the elements remaining in L (if any)
Append the elements remaining in M (if any)
You also need a variable that tracks the current index in arr (k in this case).
GeeksforGeeks code: https://www.geeksforgeeks.org/merge-sort/
Corrected python code:
def Merge(arr, p, q, r):
n1 = q-p+1
n2 = r-q
L = [0]*n1
M = [0]*n2
for i in range(0,n1):
L[i] = arr[p+i]
for j in range(0, n2):
M[j] = arr[q+1+j]
i = 0
j = 0
# result index
k = p
# take smallest element until either L or M are empty
while i < n1 and j < n2:
if L[i]<=M[j]:
arr[k] = L[i]
i = i+1
else:
arr[k] = M[j]
j = j+1
k = k+1
# write remaining elements from L
while i < n1:
arr[k] = L[i]
i = i+1
k = k+1
# write remaining elements from M
while j < n2:
arr[k] = M[j]
j = j+1
k = k+1
def Merge_Sort(arr, p, r):
if p < r:
q = int((p+r)/2)
Merge_Sort(arr, p, q)
Merge_Sort(arr, q+1,r)
Merge(arr, p, q, r)
ar = [5,3,6,1,2,9,7,8]
n = len(ar)
Merge_Sort(ar,0,n-1)
print(ar)
If you only want to use one loop you can combine all of the above like so (takes away from the readability though):
def Merge(arr, p, q, r):
n1 = q-p+1
n2 = r-q
L = [0]*n1
M = [0]*n2
for i in range(0,n1):
L[i] = arr[p+i]
for j in range(0, n2):
M[j] = arr[q+1+j]
i = 0
j = 0
for k in range(n1+n2):
if (i < n1 and j < n2 and L[i]<=M[j]) or j >= n2:
arr[p+k] = L[i]
i = i+1
else:
arr[p+k] = M[j]
j = j+1
def Merge_Sort(arr, p ,r):
if p < r:
q = int((p+r)/2)
Merge_Sort(arr, p, q)
Merge_Sort(arr, q+1,r)
Merge(arr, p, q, r)
ar = [5,3,6,1,2,9,7,8,]
n = len(ar)
Merge_Sort(ar,0,n-1)
print(ar)