I was trying to implement the insertion sort algorithm in python and was able to code it as below, I am not getting the whole array sorted and was wondering if this implementation has the proper thought process behind it, if not I would greatly appreciate if someone can help me in understanding it as the function is considering the sorted part of the array when inserting an element from the unsorted part. Also, in your review kindly consider if the implementation is correct and if so what can make my solution output correct.
def insertion_sort(array):
for i in range(1, len(array)):
for j in reversed(range(1, i)):
if array[j-1] > array[j]:
temp = array[j-1]
array[j-1] = array[j]
array[j] = temp
return array
to_sort = [4, 3, 1, 5, 6, 2]
print(insertion_sort(to_sort))
This is the output I got:
[1, 3, 4, 5, 6, 2]
tl;dr:
Insertion Sort algorithm not giving perfect output. Is implementation correct and what can be done to fix the output.
The goal of your function would be to shift array[i] into the sorted partition, but it actually does that for array[i-1], because the inner loop starts with j equal to i-1.
So the easy fix is to change:
for j in reversed(range(1, i)):
to:
for j in reversed(range(1, i + 1)):
Improvements
More Pythonic would be to use the capability of range to produce a descending range:
for j in range(i, 0, -1):
When the if condition is not true, it is useless to continue the inner loop, as then it is guaranteed that the if condition will never be true in the rest of the inner loop's iterations. So add a break:
if array[j-1] <= array[j]:
break
temp = array[j-1]
array[j-1] = array[j]
array[j] = temp
As these swaps will always move the same value to the left, i.e. array[j] will always be the value that originally was at array[i], it is less costly to first find the index where array[i] should be moved to, and then perform a single rotation to get it there.
def insertion_sort(array):
for i in range(1, len(array)):
temp = array[i]
for k in range(i - 1, -1, -1):
if array[k] <= temp:
break
else:
k = -1
# rotate
array[k+2:i+1] = array[k+1:i]
array[k+1] = temp
return array
I used k here, so not to confuse it with the meaning of j in the original code: k is j - 1.
This search for k (or j) can be done with a call to next:
def insertion_sort(array):
for i in range(1, len(array)):
temp = array[i]
j = 1 + next((k for k in range(i - 1, -1, -1) if array[k] <= temp), -1)
array[j+1:i+1] = array[j:i]
array[j] = temp
return array
You are never touching the last element of the array, I suggest changing len(array) with len(array)+1, i.e.,
def insertion_sort(array):
for i in range(1, len(array)+1):
for j in reversed(range(1, i)):
if array[j-1] > array[j]:
temp = array[j-1]
array[j-1] = array[j]
array[j] = temp
return array
This is because i has maximum value len(array)-1 and j has as maximum value i-1, which is len(array)-2.
However, the last element in the array has index len(array)-1.
my method for sorting an array written in python:
array = [3, 2, 1]
for i in range(len(array)):
minVal = array[i]
for j in range(i + 1, len(array)):
if (array[j] < array[i]):
if (array[j] <= minVal):
minVal = array[j]
if i < len(array) - 1:
array[i + 1] = array[i]
array[i] = minVal
print(array)
how do i think it works?
the first cycle will be executed 3 times
first iteration:
#i will check number 3 with numbers 2 and 1
#expected output:
minVal = 1
array = [1, 3, 2]
second iteration:
#i will check number 3 with number 2
#expected output:
minVal = 2
array = [1, 2, 3]
last iteration:
#I do not know if he is needed.
#perhaps it is worth writing `range(len(array) - 1)` in the first loop?
#and because of this iteration, I also added the check `if i <len (array) - 1:`
expected output at the end: [1, 2, 3]
what i got: [1, 1, 3]
Think about your logic: You find the minimum value and then replace the i item with it but only advance the i item one index ahead to i+1. By doing so, after the first iteration you have the list as [1, 3, 1]. Let's break it down:
you start with [3, 2, 1]
minVal = array[i] = 3
After the j loop we find that minVal = 1
Now we do array[i + 1] = array[i] -> array[1] = 3. So now we have [3, 3, 1].
Now we do array[i] = minVal -> array[0] = 1. So now we have [1, 3, 1].
The element 2 has disappeared from the list!
To fix this, you need to save the minVal's index and replace the two items, not override another item:
array = [3, 2, 1]
for i in range(len(array)):
minIndex = i
for j in range(i + 1, len(array)):
if (array[j] < array[i]):
if (array[j] <= array[minIndex]):
minIndex = j
minVal = array[minIndex]
if i < len(array) - 1:
array[minIndex] = array[i]
array[i] = minVal
print(array)
Now there are some points to simplify and improve your code:
There is no need to check that array[j] < array[i] on every iteration - in the first iteration it is equal to minVal/array[minIndex] anyway, so you can remove one if.
There is no need for the last if - instead of checking every iteration if we got to the last element, just remove it from the loop - for i in range(len(array)-1).
The replacement can be done in one line without the need to even save minVal - see this SO question.
So the improved version according to the above can be:
array = [3, 2, 1]
for i in range(len(array)-1):
minIndex = i
for j in range(i + 1, len(array)):
if array[j] < array[minIndex]:
minIndex = j
array[minIndex], array[i] = array[i], array[minIndex]
print(array)
You are currently searching an array for the minimum value including and past the current index. This is an O(N^2) approach, and quite robust. However, you need to implement it correctly.
The check
if (array[j] < array[i]):
if (array[j] <= minVal):
is redundant. You shouldn't restrict your test by the original minimum value, although it does no harm, since minVal <= array[i] in all cases.
You don't really care about the value of minVal as much as you do about its location. You more-or-less correctly identify minVal as array[j], but then you swap it out as array[i + 1] = array[i]. Where is the correct j recorded?
Here is the same idea, but without the extra check, and using minJ to illustrate the caching of j vs the value:
array = [3, 2, 1]
for i in range(len(array) - 1): # Don't bother iterating the last element
min_j = i # Only record indices
for j in range(i + 1, len(array)):
if array[j] < array[min_j]: # Only test current minimum
min_j = j
array[i], array[min_j] = array[min_j], array[i]
print(array)
Couple of small tweaks:
You don't need to iterate over the last element, so shorten the outer range by one.
The idiomatic way to swap two quantities in python is x, y = y, x. If you're going to use a temporary variable anyway, it may as well be a tuple that enhances legibility.
I have recently started python. I have written a function for bubble sort. It works fine. It have only one problem when I use two minimum values. The second one is not sorted correctly.
def bubble_sort(arr):
flag = True
for i in range(len(arr) - 1):
if flag == False:
return arr
flag = False
for j in range(i, len(arr) - 1):
if arr[j] > arr[j + 1]:
print(arr[j], arr[j + 1])
temp = arr[j + 1]
arr[j + 1] = arr[j]
arr[j] = temp
flag = True
return arr
print(bubble_sort([1, 5, 3, 2, 5, 1, 6])) //[1, 2, 1, 3, 5, 5, 6]
I expect the two 1s in the start but the second is at third position.
You should not increment the start index each loop, but decrement the end index, like:
def bubble_sort(arr):
flag = True
for i in range(1, len(arr)):
if not flag:
return arr
flag = False
for j in range(len(arr) - i):
if arr[j] > arr[j+1]:
arr[j+1], arr[j] = arr[j], arr[j+1]
flag = True
return arr
Each iteration you move the cursor from left to right. That means that if the cursor finds the maximum value, it will move that value to the right end of the list. But the same does not hold for the minimum value. If the cursor finds the minimum value, it will only move it one position to the left. That is why you should keep starting from the start of the list each iteration.
This may seem like a simple question but when I attempted to implement selection sort in Python, I do not get a sorted list. Is there something wrong with my implementation? The subsetting may be a problem.
source = [4,2,1,10,5,3,100]
for i in range(len(source)):
mini = min(source[i:]) #find minimum element
min_index = source[i:].index(mini)-1 #find index of minimum element
source[i:][min_index]= source[i:][0] #replace element at min_index with first element
source[i:][0] = mini #replace first element with min element
print source
I think there were a couple issues.
First, when your do source[i:], I believe that returns a new array of the sub-elements requested and not part of the original array, thus if you modify it, your don't modify the original. Second, you were subtracting 1 from an index when you shouldn't.
source = [4,2,1,10,5,3,100]
for i in range(len(source)):
mini = min(source[i:]) #find minimum element
min_index = source[i:].index(mini) #find index of minimum element
source[i + min_index] = source[i] #replace element at min_index with first element
source[i] = mini #replace first element with min element
print source
This gives:
[1, 2, 3, 4, 5, 10, 100]
Here is how I would rewrite your code. Of course in Python I would just use list.sort() to sort a list, but here is a selection sort in Python.
We make a generator expression that returns tuples of (value, i) for a value and its index from the list. Then when min() evaluates to find minimum, it finds the lowest tuple value; since the value comes first in the tuple before the index, the value will be the important part, and min() will find the lowest value. (If there is a tie, min() will use the second part of the tuple, the index, as a tie-breaker. But for sort we don't care how ties are broken.)
Now, instead of searching through the sub-list to find the min value, and then searching through it again to figure out the index, we search through it once and get both min value and index.
But we don't actually care about the min value; we care about the index. So after min() is done, we just throw away the actual value but keep the index. Adjust the index to be correct in the whole list (not in the slice of the list) and then we can swap.
We use the standard Python idiom for swapping two values. Python will build a tuple object to be the intermediate, then unpack this tuple into the left-hand-side.
lst = [4,2,1,10,5,3,100]
for i_sortpos in range(len(lst)):
# Make a generator expression to return (value, i) pairs.
genexp = ((n, i) for i, n in enumerate(lst[i_sortpos:]))
# Use genexp with min() to find lowest and its index.
# (Use '_' for variable name for the actual value; we don't use it.)
_, i_min = min(genexp)
# Adjust index to be correct in full list.
i_min += i_sortpos
# Swap the number at i_sortpos with the lowest found.
lst[i_sortpos], lst[i_min] = lst[i_min], lst[i_sortpos]
print(lst)
EDIT: And here is a refinement of the above. A slice from a list actually allocates a new list; our code here doesn't need a new list, it just needs a convenient way to examine a sublist. The itertools module offers a function, islice(), that returns an iterator that iterates over a slice of a list. This avoids repeatedly creating and destroying lists as we examine each sublist.
I believe this is the most efficient way to do selection sort in Python. (You could get rid of the part where we bind the generator expression to the name genexp and save a few microseconds... just make the call to min() a long one-liner. But it's not really worth the loss of readability.)
import itertools as it
lst = [4,2,1,10,5,3,100]
for i_sortpos in range(len(lst)):
# Make a generator expression to return (value, i) pairs.
# Use it.islice() for to look at sublist.
genexp = ((n, i) for i, n in enumerate(it.islice(lst, i_sortpos, len(lst))))
# Use genexp with min() to find lowest and its index.
# (Use '_' for variable name for the actual value; we don't use it.)
_, i_min = min(genexp)
# Adjust index to be correct in full list.
i_min += i_sortpos
# Swap the number at i_sortpos with the lowest found.
lst[i_sortpos], lst[i_min] = lst[i_min], lst[i_sortpos]
print(lst)
def selectionSort(List_):
for i in range(len(List_)):`
#track the current smallest value
smallIndex = i
#loop from the current smallest value
for j in range(i+1,len(List_))
if List_[j] < List_[smallIndex]:
#if new value is less that our smallest value,change
#smallest value to this
smallIndex = j
if smallIndex != i:
#swap the values
List_[smallIndex],List_[i] = List_[i],List_[smallIndex]
#return sorted list
return List_
def ss(l):
for i in range(0,len(l)):
d=l.index(min(l[i:]))
c=l[i]
l[i]=min(l[i:])
l[d]=c
print(l) #it prints each step of selection sort
y=[10,9,1,5,0,6]
ss(y)
def selSort(L):
"""
Find the smallest element in the list and put it (swap it) in the first location,
Find the second element and put it (swap it) in the second locaiton, and so on.
"""
for i in range(len(L) - 1):
minIndx = i
minVal= L[i]
j = i + 1
while j < len(L):
if minVal > L[j]:
minIndx = j
minVal= L[j]
j += 1
temp = L[i]
L[i] = L[minIndx]
L[minIndx] = temp
return L
Call:
print( selSort([120,11,0,1,3,2,3,4,5,6,7,8,9,10]) )
Output
[0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 120]
s = [1,8,4,9,3,6,2]
for i in range(len(s)):
maxi = max(s[0:len(s)-i]) #find max element
tempi = s.index(maxi) # find index of max element
temp = s[len(s)-1-i] #assign last element as temp
s[len(s)-1-i] = maxi #put max element in last position
s[tempi] = temp # put the element initially at last in its new
print s
Find the position(first and last), swap the elements if last is lower.
nums = [4,2,1,10,5,3,100]
def sort(nums):
###Find the position and now first 0th element is sorted and rest is unsorted
#Second iteration first 2 element is sorted
for i in range(len(nums)-1):
miniposition = i
for j in range(i,len(nums)):
if nums[j] < nums[miniposition]:
miniposition = j
temp = nums[i]
nums[i] = nums[miniposition]
nums[miniposition] = temp
sort(nums)
print (nums)
First iteration(swapped 4 and 1)
[1, 2, 4, 10, 5, 3, 100]
[1, 2, 4, 10, 5, 3, 100]
[1, 2, 3, 10, 5, 4, 100]
[1, 2, 3, 4, 5, 10, 100]
[1, 2, 3, 4, 5, 10, 100]
[1, 2, 3, 4, 5, 10, 100]
Other way
nums = [4,2,1,10,5,3,100]
i = 0
while i<len(nums):
#smallest element in the sublist
smallest = min(nums[i:])
#index of smallest element
index_of_smallest = nums.index(smallest)
#swapping
nums[i],nums[index_of_smallest] = nums[index_of_smallest],nums[i]
i=i+1
print (nums)
a slight variation of the solution provided
def selection_sort(l):
i = 0
while i < len(l):
minium_value = min(l[i:]) # minium value at ith iteration
minium_value_index = l[i:].index(minium_value) # minium value index at i th iteration
if minium_value < l[i]: # if the current value already min, skip
l[i + minium_value_index] = l[i] # put current value in min value's index - swap 1
l[i] = minium_value # set current value with min value- swap 2
i += 1
return l
def selection_sort_min(): # sorting number
for i in range(len(num)-1):
current_min_index = i
for j in range(i+1,len(num)):
if num[j] < num[current_min_index] :
current_min_index = j
num[i],num[current_min_index] = num [current_min_index],num[i]
print(num)
num = [23,89,12,0,3,7,33]
selection_sort_min()
here is what I think is a good way to sort a list of numbers and I hope it helps:
list=[5,4,3,1,6,8,10,9]
listsorted=[]
for i in range(len(list)):
x=min(list)
list.remove(x)
listsorted.append(x)
print listsorted
and the result will be [1, 3, 4, 5, 6, 8, 9, 10]
I think the "accepted" answer here is unhelpful. If we look at e.g.
mini = min(source[i:]) #find minimum element
min_index = source[i:].index(mini) #find index of minimum element
not only is this inefficient in terms of creating list slices unnecessarily, but they are searched unnecessarily. It's reasonably concise but I don't think it's the best solution.
def Selection_Sort(Sarray):
length = len(Sarray)
i = 0
j = 0
for i in range(length):
j = i+1
for j in range(length):
if Sarray[i] < Sarray[j]
t = Sarray[i]
Sarray[i] = Sarray[j]
Sarray[j] = t
j = j+1
i = i+1
return Sarray
Code of select sort from MIT online course .
def selSort(L):
for i in range(len(L) - 1):
minIndx = i
minVal = L[i]
j = i+1
while j < len(L):
if minVal > L[j]:
minIndx = j
minVal = L[j]
j += 1
if minIndx != i:
temp = L[i]
L[i] = L[minIndx]
L[minIndx] = temp
def selectSort(L):
for i in range(len(L)):
print L
minIndex = i
minValue = L[i]
j = i + 1
while j < len(L):
if minValue > L[j]:
minIndex = j
minValue = L[j]
j +=1
temp = L[i]
L[i] = L[minIndex]
L[minIndex] = temp