Proper Python SelectionSort - python

I am trying to learn the selection sort using python, but can't get my code to work. Some assistance would be appreciated.
def selection(seq):
for x in range(len(seq)):
temp = 0
for y in range(1, len(seq)):
if seq[y] < seq[temp]:
temp = y
if temp != 0:
seq[x], seq[temp] = seq[temp], seq[x]
return seq
selection([12, 38, 2, 18, 15, 1, 19])

You mixed indexes for both loops and initialisation of temp. You can fix it with this code:
def selection(seq):
for x in range(len(seq)):
temp = x
for y in range(x+1, len(seq)):
if seq[y] < seq[temp]:
temp = y
seq[x], seq[temp] = seq[temp], seq[x]
return seq
seq = [5, 3, 1, 2, 4]
print(selection(seq))

Related

Counting Shifts in Merge Sort Error with one array

I was trying to count the number of shifts that happen with merge sort when I ran into a problem. When I run the code with multiple arrays, for some reason one of the arrays states that 3 shifts happened when in reality its 4. I will greatly appreciate it if anyone can help me figure out what the problem is. Thanks
def mergeSort(arr):
count = x = y = 0
result =[]
arrayLength = len(arr)
if arrayLength <= 1:
return count
middle = arrayLength // 2
left = arr[:middle]
right = arr[middle:]
leftLength = len(left)
rightLength = len(right)
count += mergeSort(left)
count += mergeSort(right)
while x < leftLength and y < rightLength:
if left[x] <= right[y]:
result.append(left[x])
x += 1
else:
result.append(right[y])
y += 1
count += len(left[x:])-x
return count
arr = [1,20,6,4,5]
print(mergeSort(arr))
arr2 = [4,3,2,1]
print(mergeSort(arr2))
arr3=[1, 1, 1, 2, 2]
print(mergeSort(arr3))
arr4=[2, 1, 3, 1, 2]
print(mergeSort(arr4))
arr5 = [12,15,1,5,6,14,11]
print(mergeSort(arr5))
arr6=[3, 5, 7, 11, 9]
print(mergeSort(arr6))
result = mergeSort(arr)
print(result)
You have two bugs:
Your len(left[x:])-x subtracts x twice.
You're not actually sorting the given array but just building a result that you never use. The sorting is important for the upper call levels to count correctly.
Fixed and with better testing (Try it online!):
from itertools import combinations
def mergeSort(arr):
count = x = y = 0
arrayLength = len(arr)
if arrayLength <= 1:
return count
middle = arrayLength // 2
left = arr[:middle]
right = arr[middle:]
leftLength = len(left)
rightLength = len(right)
count += mergeSort(left)
count += mergeSort(right)
for write in range(arrayLength):
if y == rightLength or x < leftLength and left[x] <= right[y]:
arr[write] = left[x]
x += 1
else:
arr[write] = right[y]
y += 1
count += len(left) - x
return count
def naive(arr):
return sum(a > b for a, b in combinations(arr, 2))
def test(arr):
expect = naive(arr)
result = mergeSort(arr)
print(result == expect, expect, result, arr)
test([1, 20, 6, 4, 5])
test([4, 3, 2, 1])
test([1, 1, 1, 2, 2])
test([2, 1, 3, 1, 2])
test([12, 15, 1, 5, 6, 14, 11])
test([3, 5, 7, 11, 9])
I presume your question really isn't about counting the recursion and more about figuring out why your algorithm is not correct. When you're checking for while x < leftLength and y < rightLength: you are dropping items at the end of one of the lists. This should be an or not an and to make sure you are doing ALL items in both left and right lists. Something like this:
while x < leftLength or y < rightLength:
if x == leftLength:
result.append(right[y])
y += 1
continue
if y == rightLength:
result.append(left[x])
x += 1
continue
if left[x] <= right[y]:
result.append(left[x])
x += 1
else:
result.append(right[y])
y += 1
return result
and you can't return the counts like Frank said because you stop doing the merge sort, and writing back to arr doesn't work in python as it's not an in/out variable. You would have to have a global variable outside the class to do the counting.

Python for loop and function

Am new to python and I have been trying to solve this problem but it does not seem to work as intended. your help is highly appreciated:
Given two numbers X and Y, write a function that:
returns even numbers between X and Y, if X is greater than Y
else returns odd numbers between x and y
.
def number(x,y):
if x > y:
for i in range(x,y):
if i%2 == 0:
list = []
return list.append[i]
else:
for i in range(x,y):
if i%2 == 1:
list = []
return list.append[i]
print(number(10,2))
Try this code it's working as per your need.
def number(x,y):
num= []
if x > y:
for i in range(y,x):
if i%2 == 0:
num.append(i)
else:
for i in range(x,y):
if i%2 == 1:
num.append(i)
return num
print(number(2,10))
print(number(10,2))
The outputs are:
[3, 5, 7, 9]
[2, 4, 6, 8]
Let me know if this doesn't serve your purpose.
And it is done. Basically if x > y, you need to switch the first range. You append the items normally(using () instead of []), and then return the full list, got it?
def number(x,y):
list = []
if x > y:
for i in range(y,x):
if i%2 == 0:
list.append(i)
else:
for i in range(x,y):
if i%2 == 1:
list.append(i)
return list
print(number(10,2))
Working sample: https://py3.codeskulptor.org/#user302_nwBq00w56n_1.py
Instead of testing for oddness/evenness all the time, use range(start,stop[,step]) with a step of 2 starting with a (corrected, known) odd/even number:
def number(x,y):
if x > y:
if y%2 == 1: # y is smaller && odd
y += 1 # make even
return list(range(y,x,2)) # x is > y - start from y to x
else: # this is strictly not needed - but more verbose intention-wise
if x%2 == 0: # is even
x += 1 # make odd
return list(range(x,y,2))
print(number(10,32))
print(number(10,2))
You need to also switch x and y if x > y
you do not need to iterate a range and add its element to a list iteratively - simply stuff the range-sequence into the list(sequence) constructor and return it
Output:
[11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31]
[2, 4, 6, 8]
It's so easy to do, and there are several ways to do what do you want, so i show you two ways to do that, first an understandable way and second an easy way ok let's start:-
First example
def number(x,y):
list = [] #firstly create a list
if x > y: #if x was greater than y
for num in range(y, x): # a loop for searching between them
if(num % 2 == 0): # if the number was even add it to list
list.append(num)
elif y > x: #if y was greater than x
for num in range(x, y): # a loop for searching between them
if(num % 2 != 0): # if the number was not even add it to list
list.append(num)
return list
print(number(10, 20))
print(number(20, 10))
#[11, 13, 15, 17, 19]
#[10, 12, 14, 16, 18]
Second example
number = lambda x, y : [n for n in range(y, x) if n%2 == 0] if x > y else [n for n in range(x, y) if n%2 != 0]
print(number(10, 20))
print(number(20, 10))
#[11, 13, 15, 17, 19]
#[10, 12, 14, 16, 18]
Note : But be sure that in both of my answers the x number is inclusive(exists in searching function) and the y number is exclusive, so if you wanted to make both of them inclusive so make loops ...(x, y+1)... and if you wanted to make both of them exclusive just change loops to ...(x+1, y)....
Knowing that 2 % 2 == 0 we then can just use if not 2 % 2 for evens since not 0 will evaluate to true, here it is with comprehension and in extended form
def something(x, y):
if x > y:
l = [i for i in range(y, x) if not i % 2]
else:
l = [i for i in range(x, y) if i % 2]
return l
print(something(10, 2))
print(something(2, 10))
~/python/stack$ python3.7 sum.py
[2, 4, 6, 8]
[3, 5, 7, 9]
Full loop:
def something(x, y):
l = []
if x > y:
for i in range(y, x):
if not i % 2:
l.append(i)
else:
for i in range(x, y):
if i %2:
l.append(i)
return l
Here in this i use the list comprehensions.list comprehension is a easy and readable technique in python.In this i include both x and y
def fun(x,y):
if x>y:
l=[i for i in range(y,x-1) if i%2==0]
return l.reverse()
else:
l=[i for i in range(x,y+1) if i%2!=0]
return l

Python Selection sort with nested while loop

I know that I can sort arrays using selection sort with a nested for loop as follows:
def selection_sort(arr):
for k in range(len(arr)):
cur = k
for i in range(cur, len(arr)):
if arr[cur] > arr[i]:
cur = i
temp = arr[cur]
arr[cur] = arr[k]
arr[k] = temp
But can this be done with a while loop nested in a for loop? I'm curious because I saw it mentioned that the syntax for this selection sort function could be similar to an insertion sort function, such as the one that follows:
def insertion_sort(arr):
for k in range(1, len(arr)):
cur = arr[k]
j = k
while j > 0 and arr[j-1] > cur:
arr[j] = arr[j-1]
j = j - 1
arr[j] = cur
Am I overlooking something simple? It has been a while since I've used python, but it just seems simpler to use a for loop instead of a while loop, doesn't it? Nevertheless, I'm confused on how it can be done.
Firstly, your code is wrong.You can try to put the array your function.
array = [1, 4, 7, 2, 0, 4, 6, 7, 8, 1, 3, 4]
Then, if you use for loop
def selectSort_for(list):
if list != None:
for i in range(len(list)):
min = i
for j in range(i + 1, len(list)):
if list[min] > list[j]:
min = j
if min != i:
list[min], list[i] = list[i], list[min]
return list
if you use while, the code as following
def selectSort_while(list):
if list != None:
for i in range(len(list)):
min = i
x = i
while x + 1 < len(list):
x += 1
j = x
if list[min] > list[j]:
min = j
if min != i:
list[min], list[i] = list[i], list[min]
return list
Oh, your code is wrong because you miss the equal condition.By the way,
temp = arr[cur]
arr[cur] = arr[k]
arr[k] = temp
It's not a pythonic styling.
Your code may be should like this
def selection_sort(arr):
for k in range(len(arr)):
cur = k
for i in range(cur+1, len(arr)):
if arr[cur] > arr[i]:
cur = i
if cur != k:
arr[cur], arr[k] = arr[k], arr[cur]
I am going more with python style:
def sel_sort(arr):
for k in range(len(arr)):
sublist = arr[k:len(arr)+1]
min_index = sublist.index(min(sublist))
sublist[min_index], sublist[0] = sublist[0], sublist[min_index]
arr = arr[0:k]+sublist
return arr
print sel_sort([5,1,4,7,5,2,8,1,4,6,9,3])
There is actually two nested loop but the second loop is done by the built in function min().
The output is [1, 1, 2, 3, 4, 4, 5, 5, 6, 7, 8, 9]
as almost, python has fewer code line than others.
While loop nested in a for loop -
def selectionsort(l):
i = 0
while i < len(l) - 1 :
for j in range(i+1 , len(l)):
if l[i] > l[j]:
(l[i], l[j]) = (l[j], l[i])
i += 1
return(l)
selectionsort([74, 32, 89, 55, 21, 64])
The output is [21, 32, 55, 64, 74, 89]

Python quicksort - one list - swaps

**I need to make a quicksort algorithm but so that it uses only one list and does swaps inside of it. I managed to make it "sort" or position the first element but now i don't know how to implement the recursion. The biggest problem I'm having is how to recursively work on a part of the list instead of making the new one. Here is my code:
-------------------------------------------------------------------------------**
New code, same problem.
Here is my code. It does the job but gets stuck in the loop.
def qsort(n,l,g):
if l is None:
l=0
if g is None:
g=len(n)
if g-l<=1:
return n
print g-l
p=n[l]
i=1+l
j=1+l
for x in n[l+1:g]:
if x<p:
n[i],n[j]=n[j],n[i]
i+=1
j+=1
n[l],n[i-1]=n[i-1],n[l]
ls=0
le=i-1
gs=i
ge=j
print n
qsort(n,ls,le)
qsort(n,gs,ge)
Can someone give me any suggestions, I'm lost. Can't find whats wrong or how to fix it.
Know its messy but cant do better atm :D
Write it like this:
def qsort(li, lo=None, hi=None):
if lo is None:
lo = 0
if hi is None:
hi = len(li) - 1
...
...
if hi - lo > 1:
qsort(## left half ##)
qsort(## right half ##)
lo and hi are the smallest and largest indexes you should look at in li, respectively.
Swap version of quicksort.
quicksort([10, 0, 9, 1, 8, 2, 7, 3, 6, 4, 5]) >> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
quicksort([0, 4, 2, 3, 6]) >> [0, 2, 3, 4, 6]
def quicksort(seq):
if len(seq) <= 1:
return seq
pivot_index = len(seq)-1
i = 0
while i < pivot_index:
if seq[i] > seq[pivot_index] and pivot_index-1 == i:
seq[i], seq[pivot_index] = seq[pivot_index], seq[i]
pivot_index -= 1
i = 0
elif seq[i] > seq[pivot_index] and pivot_index > 1:
seq[pivot_index-1], seq[pivot_index] = seq[pivot_index], seq[pivot_index-1]
seq[i], seq[pivot_index] = seq[pivot_index], seq[i]
pivot_index -= 1
i = 0
else:
i += 1
return quicksort(seq[:pivot_index]) + [seq[pivot_index]] + quicksort(seq[pivot_index+1:])

Python Coin change SO CLOSE

I am doing the coin-change problem. I have finished the problem in that it prints out how many coins I need to make the least amount of change possible, but how do I change my program so that it also prints those coins??
Here is a sample I/O:
input: coin_change(48, [1, 5, 10, 25, 50])
output: [6, [25, 10, 10, 1, 1, 1]]
Currently my code only returns the 6.
by the way, this must be done with recursion only. no loops are allowed
Code:
def change(C, V):
def min_coins(i, aC):
if aC == 0:
return 0
elif i == -1 or aC < 0:
return float('inf')
else:
return min(min_coins(i-1, aC), 1 + min_coins(i, aC-V[i]))
return min_coins(len(V)-1, C)
A different version of your program:
def change(C, V, res=None):
res = [] if res is None else res
if len(V) == 0:
return len(res), res
maxx = max(V)
V.remove(maxx)
ans = C//maxx
if ans == 0 and maxx < C :
res += [maxx] * ans
return len(res), res
else:
res += [maxx] * ans
return change(C % maxx, V, res)
print change(48,[1, 5, 10, 25, 50])
print change(30,[25, 10, 2, 3, 1])
output:
(6, [25, 10, 10, 1, 1, 1])
(3, [25, 3, 2])
PS: I'll add an explanation if you want.

Categories

Resources