QuickSort - Median Three - algorithm

I am working on the QuickSort - Median Three Algorithm.
I have no problem with the first and last element sorting. But, when comes to the Median-three, I am slightly confused. I hope someone could help me on this.
Would be appreciate if someone could provide me some pseudocode?
My understanding is to get the middle index by doing this. (start + end) / 2 , then swap the middle pivot value to the first value, after all these done it should goes well with the normal quick sort ( partitioning and sorting).
Somehow, I couldn't get it works. Please help!
#Array Swap function
def swap(A,i,k):
temp=A[i]
A[i]=A[k]
A[k]=temp
# Get Middle pivot function
def middle(lista):
if len(lista) % 2 == 0:
result= len(lista) // 2 - 1
else:
result = len(lista) // 2
return result
def median(lista):
if len(lista) % 2 == 0:
return sorted(lista)[len(lista) // 2 - 1]
else:
return sorted(lista)[len(lista) // 2]
# Create partition function
def partition(A,start,end):
m = middle(A[start:end+1])
medianThree = [ A[start], A[m], A[end] ]
if A[start] == median(medianThree):
pivot_pos = start
elif A[m] == median(medianThree):
tempList = A[start:end+1]
pivot_pos = middle(A[start:end+1])
swap(A,start,pivot_pos+start)
elif A[end] == median(medianThree):
pivot_pos = end
#pivot = A[pivot_pos]
pivot = pivot_pos
# swap(A,start,end) // This line of code is to switch the first and last element pivot
swap(A,pivot,end)
p = A[pivot]
i = pivot + 1
for j in range(pivot+1,end+1):
if A[j] < p:
swap(A,i,j)
i+=1
swap(A,start,i-1)
return i-1
count = 0
#Quick sort algorithm
def quickSort(A,start,end):
global tot_comparisons
if start < end:
# This to create the partition based on the
pivot_pos = partition(A,start,end)
tot_comparisons += len(A[start:pivot_pos-1]) + len(A[pivot_pos+1:end])
# This to sort the the left partition
quickSort(A,start,pivot_pos -1)
#This to sort the right partition
quickSort(A,pivot_pos+1,end)

Related

Is there any way to use the return value as an argument to the same function during the previous recursion in merge sort

I am coding the Merge sort algorithm but somehow got stuck with a problem. The problem is that I need to use the return value of the merge function as an argument as an previous recursive call of the same merge function. Sorry for not being clear.
Here is my code:
a = [10,5,2,20,-50,30]
def mergeSort(arr):
l = 0
h = len(arr)-1
if h > l:
mid = (l+h) // 2
left = arr[l:mid+1]
right = arr[mid+1:]
mergeSort(left)
mergeSort(right)
merge(left, right)
def merge(l, r):
subarr = []
lc = 0
rc = 0
loop = True
while loop:
if lc > len(l)-1 and rc <= len(r)-1:
for i in range(rc, len(r)):
subarr.append(r[i])
loop = False
elif lc <= len(l)-1 and rc > len(r)-1:
for i in range(lc, len(l)):
subarr.append(l[i])
loop = False
elif l[lc] < r[rc]:
subarr.append(l[lc])
lc += 1
loop = True
elif r[rc] < l[lc]:
subarr.append(r[rc])
rc += 1
loop = True
elif l[lc] == r[rc]:
subarr.append(l[lc])
subarr.append(r[rc])
lc += 1
rc += 1
loop = True
mergeSort(a)
Any help will be appreciated thank you :)
First you need to actually return the result. Right now you return nothing so get None back.
Secondly, just assign to the same variable. left = mergeSort(left) and so on.
UPDATE:
Here is a debugged version.
a=[10,5,2,20,-50,30]
def mergeSort(arr):
l=0
h=len(arr)-1
if h>l:
mid=(l+h)//2
left=arr[l:mid+1]
right=arr[mid+1:]
# Capture the merge into variables here.
left=mergeSort(left)
right=mergeSort(right)
# Need a return of the merge.
return merge(left,right)
# Need to return arr if arr has 0 or 1 elements.
else:
return arr
def merge(l,r):
subarr=[]
lc=0
rc=0
loop=True
while loop:
if lc>len(l)-1 and rc<=len(r)-1:
for i in range(rc,len(r)):
subarr.append(r[i])
loop=False
elif lc<=len(l)-1 and rc>len(r)-1:
for i in range(lc,len(l)):
subarr.append(l[i])
loop=False
elif l[lc]<r[rc]:
subarr.append(l[lc])
lc+=1
loop=True
elif r[rc]<l[lc]:
subarr.append(r[rc])
rc+=1
loop=True
elif l[lc]==r[rc]:
subarr.append(l[lc])
subarr.append(r[rc])
lc+=1
rc+=1
loop=True
# Need to return the results of merge.
return subarr
# Need to actually try calling the function to see the result.
print(mergeSort(a))
I also indented more sanely. Trust me, it matters.
There are multiple problems in our code:
you do not return the sorted slice from mergeSort nor merge. Your implementation does not sort the array in place, so you must return subarr in merge and the return value of merge in mergeSort or arr if the length is less than 2.
your code is too complicated: there are many adjustments such as mid+1, len(l)-1, etc. It is highly recommended to use index values running from 0 to len(arr) excluded. This way you do not have to add error prone +1/-1 adjustments.
the merge function should proceed in 3 phases: merge the left and right arrays as long as both index values are less than the array lengths, then append remaining elements from the left array, finally append remaining elements from the right array.
there is no need to make 3 different tests to determine from which of the left and right array to take the next element, a single test is sufficient.
also use a consistent amount of white space to indent the blocks, 3 or 4 spaces are preferable, tabs are error prone as they expand to different amount of white space on different devices, mixing tabs and spaces, as you did is definitely a problem.
Here is a modified version:
def mergeSort(arr):
# no need to use l and h, use len(arr) directly
if len(arr) > 1:
# locate the middle point
mid = len(arr) // 2
# left has the elements before mid
left = arr[:mid]
# right has the elements from mid to the end
right = arr[mid:]
# sort the slices
left = mergeSort(left)
right = mergeSort(right)
# merge the slices into a new array and return it
return merge(left, right)
else:
# return the original array (should actually return a copy)
return arr
def merge(l, r):
subarr = []
lc = 0
rc = 0
# phase1: merge the arrays
while lc < len(l) and rc < len(r):
if l[lc] <= r[rc]:
subarr.append(l[lc])
lc += 1
else:
subarr.append(r[rc])
rc += 1
# phase2: copy remaining elements from l
while lc < len(l):
subarr.append(l[lc])
lc += 1
# phase3: copy remaining elements from r
while rc < len(r):
subarr.append(r[rc])
rc += 1
# return the merged array
return subarr
a = [10, 5, 2, 20, -50, 30]
print(mergeSort(a))

K product array

I am working on an algorithms problem. You have an array numbers, size of array t , number number_of_elements and number multiplication_value. You have to find any set of number_of_elements indexes of the elements of the array , which product will be equal to multiplication_value. It is guaranteed, that such set of indexes exists
That problem looks like 2 sum, but I can't extrapolate it to my case.
I have tried naive algorithm for O(n), but it fails, when you have bad first number in an array. I think there is a way to use recursion in here. I guess it is well-known problem, but I couldn't find the solution
Example in:
t = 7
number_of_elements = 2
multiplication_value = 27
numbers = [9,1,1,27,3,27,3]
Example out:
1 3
My code ideas:
def return_index_values(numbers,multiplication_value,number_of_elements):
cur_number = int(multiplication_value)
list_of_indexes = []
values = []
for i in range(len(numbers)):
if ((cur_number == 1) and (len(values) == number_of_elements)):
print(values)
#finishing if everything worked
break
else:
if (cur_number % int(numbers[i]) == 0):
if(len(values) < number_of_elements):
#pushing values if possible
values.append(int(numbers[i]))
list_of_indexes.append(i)
cur_number = int(cur_number / int(numbers[i]))
print(cur_number)
else:
pass
if(len(values) == number_of_elements):
if mult_check(values,int(multiplication_value)):
#mult_check checks if the array's element multiplication gives a value
break
else:
#started dealing with bad cases, but it doesn't work properly
values.sort()
val_popped = values.pop()
cur_number = cur_number * val_popped
Bad case for my code
numbers = [9,3,1,27,3,27,3]
Here is one implementation. Not necessarily the best solution but it gives you some sense of how it can be done.
It first sorts the numbers by the element keeping the indices information. Then it performs recursion calls.
number_of_elements = 2
multiplication_value = 27
numbers = [9,1,1,27,3,27,3]
def preprocess(numbers, multiplication_value, number_of_elements):
l = []
for i, num in enumerate(numbers):
l.append((num, i))
return sorted(l, key = lambda tup: tup[0])
def subroutine(numbers, multiplication_value, number_of_elements, idx_start, result):
if idx_start >= len(numbers):
return False
if number_of_elements == 0:
return True if multiplication_value == 1 else False
for i in range(idx_start, len(numbers)):
num = numbers[i][0]
if num <= multiplication_value:
if multiplication_value % num == 0:
idx = numbers[i][1]
result.append(idx)
found = subroutine(numbers, multiplication_value / num, number_of_elements - 1, i + 1, result)
if not found:
del result[-1]
else:
return True
else:
return False
return False
result = []
processed_numbers = preprocess(numbers, multiplication_value, number_of_elements)
subroutine(processed_numbers, multiplication_value, number_of_elements, 0, result)
print(result)
You can use itertools.combinations() (https://www.geeksforgeeks.org/itertools-combinations-module-python-print-possible-combinations/) to select number_of_elements entries from your list in all possible ways, then check each whether they multiply to the required number.

R - Using a While() loop inside a FOR() loop

I am rebuilding a VBA code inside R, that counts transitions from a rating to another based on different conditions:
It is as follows:
## attach the relevant data table
attach(cohort)
# define the matrices that will contain all the counting information
ni = matrix(0,nrow = 1, ncol = classes - 1)
nij = matrix(0, nrow = classes-1, ncol = classes+1)
for (k in 1:obs)
{
# define the year of the kth observation
t = apply(data.frame(date[k],ystart),1,max, na.rm = F)
#t = year(as.Date(t))
while (t < yend)
{
# if this observation and the second one belong to the same id and year, break and move to the next one
if (id[k] == id[k+1] & date[k] == date[k+1]) {break}
# if the rating of this observation is 0 (not rated) or in default, then leave it
if (rating[k] == classes | rating[k] == 0) {break}
# add to the group of customers with rating = rating_k, 1 observation
rating_k = rating[k]
ni[rating_k] = ni[rating_k]+1
# determine the rating from end of next year
if (id[k] != id[k+1] | date[k+1] > (t+1))
{newrat = rating_k}
else
{
kn = k +1
while (date[kn]==date[kn+1] & id[kn]==id[kn+1])
{
if (rating[kn]==classes) {break}
Kn = kn+1
}
newrat = rating[kn]
}
nij[rating_k, newrat] = (nij[rating_k, newrat] + 1)
if(newrat!=rating[k]) {break}
else
{t = (t+1)}
}
print (k)
}
At the end of my code, if the condition " if(newrat!=rating[k]) " is met, i want my code to break and move to the next K. Else, if the condition is not met, i have t = t + 1, where the code will go back to the condition inside the while(t
I added in the end "print(k)" to understand at which "for k ..." step the code stops, and it always stops at k = 9 while k = 1 to 8 are printed. In total, i have 4000 observations but only 8 are considered, though the loop never stops and R keeps running.

Modification to Selection Sort. Theoretically seems correct but doesn't give the results

I am learning ruby and the way I am going about this is by learning and implementing sort algorithms. While working on selection sort, I tried to modify it as follows:
In every pass, instead of finding the smallest and moving it to the top or beginning of the array, find the smallest and the largest and move them to both ends
For every pass, increment the beginning and decrease the ending positions of the array that has to be looped through
While swapping, if the identified min and max are in positions that get swapped with each other, do the swap once (otherwise, two swaps will be done, 1 for the min and 1 for the max)
This doesn't seem to work in all cases. Am I missing something in the logic? If the logic is correct, I will revisit my implementation but for now I haven't been able to figure out what is wrong.
Please help.
Update: This is my code for the method doing this sort:
def mss(array)
start = 0;
stop = array.length - 1;
num_of_pass = 0
num_of_swap = 0
while (start <= stop) do
num_of_pass += 1
min_val = array[start]
max_val = array[stop]
min_pos = start
max_pos = stop
(start..stop).each do
|i|
if (min_val > array[i])
min_pos = i
min_val = array[i]
end
if (max_val < array[i])
max_pos = i
max_val = array[i]
end
end
if (min_pos > start)
array[start], array[min_pos] = array[min_pos], array[start]
num_of_swap += 1
end
if ((max_pos < stop) && (max_pos != start))
array[stop], array[max_pos] = array[max_pos], array[stop]
num_of_swap += 1
end
start += 1
stop -= 1
end
puts "length of array = #{array.length}"
puts "Number of passes = #{num_of_pass}"
puts "Number of swaps = #{num_of_swap}"
return array
end
The problem can be demonstrated with this input array
7 5 4 2 6
After searching the array the first time, we have
start = 0
stop = 4
min_pos = 3
min_val = 2
max_pos = 0 note: max_pos == start
max_val = 7
The first if statement will swap the 2 and 7, changing the array to
2 5 4 7 6
The second if statement does not move the 7 because max_pos == start. As a result, the 6 stays at the end of the array, which is not what you want.

Knapsack 0-1 with fixed quanitity

I'm writing a variation of knapsack 0-1 with multiple constraints. In addition to a weight constraint I also have a quantity constraint, but in this case I want to solve the knapsack problem given that I'm required to have exactly n items in my knapsack, with a weight less than or equal to W. I'm currently implementing a dynamic programming ruby solution for the simple 0-1 case based off of the code at Rosetta Code at http://rosettacode.org/wiki/Knapsack_problem/0-1#Ruby.
What's the best way to implement the fixed quantity constraint?
You could add a third dimension to the table: Number of items. Each item included adds both weight in the weight-dimension, and count in the count-dimension.
def dynamic_programming_knapsack(problem)
num_items = problem.items.size
items = problem.items
max_cost = problem.max_cost
count = problem.count
cost_matrix = zeros(num_items, max_cost+1, count+1)
num_items.times do |i|
(max_cost + 1).times do |j|
(count + 1).times do |k|
if (items[i].cost > j) or (1 > k)
cost_matrix[i][j][k] = cost_matrix[i-1][j][k]
else
cost_matrix[i][j][k] = [
cost_matrix[i-1][j][k],
items[i].value + cost_matrix[i-1][j-items[i].cost][k-1]
].max
end
end
end
end
cost_matrix
end
To find the solution (which items to pick), you need to look at the grid cost_matrix[num_items-1][j][k], for all values of j and k, and find the cell with maximum value.
Once you find the winning cell, you need to trace backwards towards the start (i = j = k = 0). On each cell you examine, you need to determine if item i was used to get here or not.
def get_used_items(problem, cost_matrix)
itemIndex = problem.items.size - 1
currentCost = -1
currentCount = -1
marked = Array.new(cost_matrix.size, 0)
# Locate the cell with the maximum value
bestValue = -1
(problem.max_cost + 1).times do |j|
(problem.count + 1).times do |k|
value = cost_matrix[itemIndex][j][k]
if (bestValue == -1) or (value > bestValue)
currentCost = j
currentCount = k
bestValue = value
end
end
end
# Trace path back to the start
while(itemIndex >= 0 && currentCost >= 0 && currentCount >= 0)
if (itemIndex == 0 && cost_matrix[itemIndex][currentCost][currentCount] > 0) or
(cost_matrix[itemIndex][currentCost][currentCount] != cost_matrix[itemIndex-1][currentCost][currentCount])
marked[itemIndex] = 1
currentCost -= problem.items[itemIndex].cost
currentCount -= 1
end
itemIndex -= 1
end
marked
end

Resources