def rwSteps(start, low, hi):
n=0
while low <= start <= hi:
print (start-low-1)*" " + "#" + (hi-start)*" ", n
start+=random.choice((-1,1))
n+=1
return "%d steps" % (n-1)
print rwSteps(10, 5, 15)
The above function is the function that I need to rewrite in a recursive fashion. The function takes in a starting point integer, and a low and a high point. From the starting point, the function should either do +1 or -1 from the starting point randomly until either the high limit or the low limit is reached. Here is what I have so far.
def RandomWalkSteps(start, low, hi):
count = 0
count = count + 1
if(low <= start <= hi):
count = count + 1
start+=random.choice((-1,1))
newStart = start
RandomWalkSteps(newStart, low, hi)
return count
I feel like I'm pretty close, but I'm running into trouble of where to put the "count" statement so that it increments properly at every instance of recursion. Any help would be appreciated and feel free to yell at me if I left out any crucial piece of information.
def RandomWalkSteps(start, low, hi):
if low < start < hi:
return 1 + RandomWalkSteps(random.choice((-1,1)), low, hi)
return 0
def RandomWalkSteps(start, low, hi, count=0):
if low < start < hi:
return RandomWalkSteps(start+random.choice((-1,1)), low, hi, count+1)
return count
print RandomWalkSteps(10, 5, 15)
I believe this is what you are looking for
def RandomWalkSteps(count, start, low, hi):
if low <= start <= hi:
start+=random.choice((-1,1))
newStart = start
return RandomWalkSteps(count+1, newStart, low, hi)
else:
return count
call RandomWalkSteps(0, x, y, z) instead of RandomWalkStep(x, y, z)
Related
I'm trying to implement a recursive quicksort algorithm using two methods (swap, partition) while running the main algorithm using recursion in a lambda expression. I'm getting an infinite recursion error and honestly I can't find the syntax error. Can someone help me out? Thanks :)
def swap(array, a, b):
array[a], array[b] = array[b], array[a]
def partition(array, high, low):
pivot = array[high]
i = low
for x in range(low, high-1):
if array[x] < pivot:
i+=1
swap(array, array[x], array[high])
return i
g = lambda array, low, high: g(array,low,partition(array,high,low)-1)+g(array,partition(array,high,low)+1,high) if low < high else print("not sorted")
There are several issues in partition:
The call to swap is passing values from your list, instead of indices.
Even when the previous mistake is corrected, it will either move the pivot value to the low+1 index, or it will not move at all.
The returned index i, should be the one where the pivot was moved. In a correct implementation that means i is the last index to which a value was moved, which was the value at index high. This is not what is happening, as already with the first swap the pivot value is moved.
The swap should be of the current value with the value at i, so that all values up to the one at index i are less or equal to the pivot value.
Here is the corrected partition function:
def partition(array, high, low):
pivot = array[high]
i = low - 1
for x in range(low, high+1):
if array[x] <= pivot:
i+=1
swap(array, x, i)
return i
These are the issues in the function g:
It is supposed to perform the sort in-place, so the + operator for lists should not occur here, as that would create a new list. Moreover, the base case (in else) does not return anything, so the + operator will fail with an error
partition(array,high,low) is called twice, which is not only a waste, but the second call will in most cases return a different result, because the pivot can be different. This means the second call of g will potentially not work with an adjacent partition, but will either leave an (unsorted) gap, or work on an overlapping partition.
Here is a correction for the function g:
def g(array, low, high):
if low < high:
i = partition(array, high, low)
g(array, low, i-1)
g(array, i+1, high)
You should also consider using a better name than g, and change the order of the high/low parameters for partition: that reversed order is a good way to confuse the readers of your code.
Here is Hoare's quicksort algorithm implemented in Python -
def quicksort(A, lo, hi):
if lo >= 0 and hi >= 0 and lo < hi:
p = partition(A, lo, hi)
quicksort(A, lo, p)
quicksort(A, p + 1, hi)
def partition(A, lo, hi):
pivot = A[(hi + lo) // 2]
i = lo
j = hi
while True:
while A[i] < pivot:
i += 1
while A[j] > pivot:
j -= 1
if i >= j:
return j
swap(A, i, j)
def swap(A, i, j):
A[i], A[j] = A[j], A[i]
You can write g using lambda if you wish, but I would recommend to define an ordinary function instead -
g = lambda a: quicksort(a, 0, len(a) - 1)
Given a sample input, x -
x = [5,0,9,7,4,2,8,3,1,6]
g(x)
print(x)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
See this related Q&A if you would like to count the number of comparisons and swaps used.
I know people will say this is a duplicate, but the code I found doesn't work and I have no idea how to fix it, so this not a duplicate because I'm asking how to fix MY code, not do the problem itself. Here's the code:
def partition(array, start, end):
pivot = array[start]
low = start + 1
high = end
while True:
while low <= high and array[high] >= pivot:
high = high - 1
while low <= high and array[low] <= pivot:
low = low + 1
if low <= high:
array[low], array[high] = array[high], array[low]
else:
break
array[start], array[high] = array[high], array[start]
return high
def qsort(array):
start = min(array)
end = max(array)
if start >= end:
return
p = partition(array, start, end)
qsort(array, start, p-1)
qsort(array, p+1, end)
Everytime I try to use it, I get a crash. I made qsort a one variable function, then set the end to the max, and the start to the min. The crash I get when trying to use it says as follows:
qsort([1,5,1,6])
>>>Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "main.py", line 88, in qsort
p = partition(array, start, end)
File "main.py", line 73, in partition
while low <= high and array[high] >= pivot:
IndexError: list index out of range
I know this means I exceeded the max, or had a stackoverflow (lol) but I'm not sure how to fix it in my code. Help!
Apart from logic, what i can see from your code is that your start and end are containing array values, it should be indices. start should be initialized as 0 and end as len(array)-1
The code needs an entry function or a change in the calling code to use a recursive function with parameters start and end
def partition(array, start, end):
pivot = array[start]
low = start + 1
high = end
while True:
while low <= high and array[high] >= pivot:
high = high - 1
while low <= high and array[low] <= pivot:
low = low + 1
if low <= high:
array[low], array[high] = array[high], array[low]
else:
break
array[start], array[high] = array[high], array[start]
return high
def qsortr(array, start, end): # recursive function
if start >= end:
return
p = partition(array, start, end)
qsortr(array, start, p-1)
qsortr(array, p+1, end)
def qsort(array): # entry function
qsortr(array, 0, len(array)-1); # fix
A = [1,5,1,6]
qsort(A)
print(A)
alternate test code to sort 512K ints
import random
from time import time
# test sort
a = [random.randint(0, 2147483647) for r in xrange(512*1024)]
s = time()
qsort(a)
e = time()
print e - s
# check to see if data was sorted
f = 0
for i in range (1, len(a)): # use xrange for python 2.x
if(a[i-1] > a[i]):
f = 1
break
if(f == 0):
print("sorted")
else:
print("error")
I'm trying to test the computation time of multiple sorting algorithms on increasingly larger sets of data. Quicksort has a memory error when it reaches 7000.
I have set the recursion limit to 10**6 in order to combat the maximum recursion depth when using timsort
from random import randint
import time
import math
start = 1000
finish = 10000
inc = 1000
import sys
sys.setrecursionlimit(10**6)
def generateNew(z):
listt = []
for o in range(z):
listt.append(randint(0, z))
return listt
...
def partition(arr,low,high):
i = ( low-1 )
pivot = arr[high]
for j in range(low , high):
if arr[j] <= pivot:
i = i+1
arr[i],arr[j] = arr[j],arr[i]
arr[i+1],arr[high] = arr[high],arr[i+1]
return ( i+1 )
def quickSort(arr,low,high):
if low < high:
pi = partition(arr,low,high)
quickSort(arr, low, pi-1)
quickSort(arr, pi+1, high)
def quickSortTimer(unsorted):
start = time.time()
array = unsorted
quickSort(array,0,len(array)-1)
end = time.time()
print("Quick Sort: "+str(end - start))
...
def runAll():
for h in range(start, finish+1, inc):
print("\n\nCurrent: "+str(h))
unsorted = generateNew(h)
oddEvenSortTimer(unsorted)
#stoogeSortTimer(unsorted)
gnomeSortTimer(unsorted)
#bogoSortTimer(unsorted)
binaryInserionSortTimer(unsorted)
pancakeSortTimer(unsorted)
bitonicSortTimer(unsorted)
cocktailSortTimer(unsorted)
cycleSortTimer(unsorted)
pigeonholeSortTimer(unsorted)
combSortTimer(unsorted)
timSortTimer(unsorted)
shellSortTimer(unsorted)
bucketSortTimer(unsorted)
radixSortTimer(unsorted)
heapSortTimer(unsorted)
quickSortTimer(unsorted)
mergeSortTimer(unsorted)
selectionSortTimer(unsorted)
insertionSortTimer(unsorted)
bubbleSortTimer(unsorted)
I expect the program to continue running but instead I get the error: MemoryError: Stack overflow. This question got marked as a duplicate of another question explaining how to increase the recursion depth, but this is another error. I want to maintain the recursion depth but avoid the stack overflow error.
To avoid stack overflow, use recursion on the smaller (or equal) part, then iterate back to handle the larger part.
def quicksort(a, lo, hi):
while(hi - lo > 0):
pivot = a[hi]
i = lo
for j in xrange(lo, hi):
if a[j] <= pivot:
a[i],a[j] = a[j],a[i]
i += 1
a[i],a[hi] = a[hi],a[i]
if(i - lo <= hi - i):
quicksort(a, lo, i-1)
lo = i+1
else:
quicksort(a, i+1, hi)
hi = i-1
I am trying to solve a binary search problem, however, I keep getting an infinite loop, since the values of lo hi and mid do not change as they suppose to. I am trying to search for a minimum mid value where function count_lines(mid,k) >= n. I have spent hours debugging this code but I still couldn't figure out what is wrong with the values of lo hi and mid. Could someone please look at my code and show me why this happen? Many thanks!
Failed testing case where: n=9 k=2
Here is my code:
def count_lines(v,k):
...
...
return count_lines #count_lines is an integer`
def binarySearch_v(n, k):
lo = 0
hi = n
mid = (lo + hi)//2
while (lo <= hi):
if (count_lines(mid, k) < n):
lo = mid
elif (count_lines(mid, k) > n):
hi = mid
elif (count_lines(mid, k) >= n and count_lines(mid-1, k) < n):
return mid
mid = (lo + hi) // 2
def main():
print(binarySearch_v(n,k)) # Failed at n=9 & k=2
main()
Here's your termination condition:
while (lo <= hi):
And here's where lo and hi can possibly change values:
lo = mid
...
hi = mid
The logical conclusion is that, if this code loops enough times, you'll end up with lo == hi. mid will then be set to the average of the two, which is equal to both of them, and that's where all three variables will stay. And as such, the loop will not terminate. There are two possible solutions: either change the way you're reassigning lo or hi, or change the termination condition to < instead of <=.
I have a list of sorted numbers. [1,2,4,6,10,12]
I want to find a number within the list. If I cannot find it, I want to return the next lowest number.
For instance, n = 8. I search for 8 but cannot find it. I will then return 6 because it is the next lowest number.
I have some code but I can't seem to get the indexing correct:
def search_val(data, n):
low = 0
high = len(data) - 1
if data[-1] <= n:
return data[-1]
if data[0] >= time:
return
while low < high:
mid = (low + high) / 2
if data[mid] == n:
return data[n]
if data[mid] > n:
high = mid -1
if data[mid] < n:
low = mid + 1
if data[low] < n:
return data[low]
else:
return data[low - 1]
This will fix all your problems, and should be a little faster:
def search_val(data, n):
low = 0
high = len(data) - 1
while low <= high:
mid = (low + high) // 2
if data[mid] > n:
high = mid -1
elif data[mid] < n:
low = mid + 1
else:
return data[mid]
# Now low > high
if high >= 0:
return data[high]
# All values are > n. Just return the first. Could
# be changed to return None.
return data[0]
Note that, in the case where all values are > n, it returns the first value. You could of course change it to return None instead if desired.
Also note that it assumes len(data) is >= 1. If that isn't always the case, you could add a check at the top and return None if data is the empty list.
Is the list guaranteed to be in order? If not, try this:
data = [1,2,4,6,10,12]
result = max((n for n in data if n <= 8))