Merge sort for python - python

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)

Related

Need to optimize my mathematical py code with lists

Im not very sure if I will translate the assignment correctly, but the bottom line is that I need to consider the function f(i) = min dist(i, S), where S is number set of length k and dist(i, S) = sum(j <= S)(a (index i) - a(index j)), where a integer array.
I wrote the following code to accomplish this task:
n, k = (map(int, input().split()))
arr = list(map(int, input().split()))
sorted_arr = arr.copy()
sorted_arr.sort()
dists = []
returned = []
ss = 0
indexed = []
pop1 = None
pop2 = None
for i in arr:
index = sorted_arr.index(i)
index += indexed.count(i)
indexed.append(i)
dists = []
if (index == 0):
ss = sorted_arr[1:k+1]
elif (index == len(arr) - 1):
sorted_arr.reverse()
ss = sorted_arr[1:k+1]
else:
if index - k < 0:
pop1 = 0
elif index + k > n - 1:
pop2 = None
else:
pop1 = index - k
pop2 = index + k + 1
ss = sorted_arr[pop1:index] + sorted_arr[index + 1: pop2]
for ind in ss:
dists.append(int(abs(i - ind)))
dists.sort()
returned.append(str(sum(dists[:k])))
print(" ".join(returned))
But I need to speed up its execution time significantly.

I want to print only the fourth number in the combination function

I got a code from the Internet that prints a number of combinations of all cases.
arr = [1,2,3,4] and n = 4 and r=2
The number of cases that appear is as follows:
1 2
1 3
1 4
2 3
2 4
3 4
I want to print only the fourth number [2,3] here.
Can you help me?
def printCombination(arr, n, r):
data = [0] * r
combinationUtil(arr, n, r, 0, data, 0)
def combinationUtil(arr, n, r, index, data, i):
if (index == r):
for j in range(r):
print(data[j], end = " ")
print()
return
if (i >= n):
return
data[index] = arr[i]
combinationUtil(arr, n, r, index + 1, data, i + 1)
combinationUtil(arr, n, r, index, data, i + 1)
arr = [1,2,3,4]
r = 2
n = len(arr)
printCombination(arr, n, r)
Try this:
def printCombination(arr, n, r):
data = [0] * r
combinationUtil(arr, n, r, 0, data, 0)
def combinationUtil(arr, n, r, index, data, i):
if (index == r):
for j in range(r):
if (data[0] == arr[1] and data[1] == arr[2]):
print(data[j], end = " ")
print()
return
if (i >= n):
return
data[index] = arr[i]
combinationUtil(arr, n, r, index + 1, data, i + 1)
combinationUtil(arr, n, r, index, data, i + 1)
arr = [1,2,3,4]
r = 2
n = len(arr)
printCombination(arr, n, r)
Also, now that I think about it more clearly, I think that you can do it in a way that is much simpler. It seems that for a list that is 4 numbers long, you want to get the middle two numbers. So you could just do it like this:
def printMiddle(list):
print([list[1], list[2]])
list = [1,2,3,4]
printMiddle(list)

Getting List Index out of Range Error while using Merge Sort function

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)

Dynamic Programming: Rod cutting and remembering where cuts are made

So I have this code in python and currently it only returns the maximum value for cutting a rod. How can I modify this to also give me where the cuts were made? It takes a list of prices whose indices+1 correspond to the value of the rod at each length, and n, for length of the rod.
the problem:http://www.radford.edu/~nokie/classes/360/dp-rod-cutting.html
def cutRod(price, n):
val = [0 for x in range(n+1)]
val[0] = 0
for i in range(1, n+1):
max_val = 0
for j in range(i):
max_val = max(max_val, price[j] + val[i-j-1])
val[i] = max_val
return val[n]
If this is the question : Rod cutting
Assuming code works fine, You will have to add a condition instead of Max operation to check which of two was picked and push that one in an array :
def cutRod(price, n):
val = [0 for x in range(n+1)]
val[0] = 0
output = list()
for i in range(1, n+1):
max_val = 0
cur_max_index = -1
for j in range(i):
cur_val = price[j] + val[i-j-1]
if(cur_val>max_val):
max_val = cur_val #store current max
cur_max_index = j #and index
if cur_max_index != -1:
output.append(cur_max_index) #append in output index list
val[i] = max_val
print(output) #print array
return val[n]
I know this is old but just in case someone else has a look...I was actually just looking at this problem. I think the issue is here that these dp problems can be tricky when handling indices. The previous answer is not going to print the solution correctly simply because this line needs to be adjusted...
cur_max_index = j which should be cur_max_index = j + 1
The rest...
def cut_rod(prices, length):
values = [0] * (length + 1)
cuts = [-1] * (length + 1)
max_val = -1
for i in range(1, length + 1):
for j in range(i):
temp = prices[j] + values[i - j - 1]
if temp > max_val:
max_val = prices[j] + values[i - j - 1]
cuts[i] = j + 1
values[i] = max_val
return values[length], cuts
def print_cuts(cuts, length):
while length > 0:
print(cuts[length], end=" ")
length -= cuts[length]
max_value, cuts = cut_rod(prices, length)
print(max_value)
print_cuts(cuts, length)
Well, if you need to get the actual pieces that would be the result of this process then you'd probably need a recursion.
For example something like that:
def cutRod(price, n):
val = [0 for x in range(n + 1)]
pieces = [[0, 0]]
val[0] = 0
for i in range(1, n + 1):
max_val = 0
max_pieces = [0, 0]
for j in range(i):
curr_val = price[j] + val[i - j - 1]
if curr_val > max_val:
max_val = curr_val
max_pieces = [j + 1, i - j - 1]
pieces.append(max_pieces)
val[i] = max_val
arr = []
def f(left, right):
if right == 0:
arr.append(left)
return
f(pieces[left][0], pieces[left][1])
f(pieces[right][0], pieces[right][1])
f(pieces[n][0], pieces[n][1])
return val[n], arr
In this code, there is an additional array for pieces which represents the best way to divide our Rod with some length.
Besides, there is a function f that goes through all pieces and figures out the optimal way to divide the whole Rod.

Why won't this merge sort implementation work?

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.

Categories

Resources