Here\'s a Python implementation of insertion sort, I tried to follow the values on paper but once the counting variable i gets bigger than len(s) I don\'t know what to do, h
Or, this one:
def ins_sort(k):
for i in range(1,len(k)): #since we want to swap an item with previous one, we start from 1
j = i #bcoz reducing i directly will mess our for loop, so we reduce its copy j instead
temp = k[j] #temp will be used for comparison with previous items, and sent to the place it belongs
while j > 0 and temp < k[j-1]: #j>0 bcoz no point going till k[0] since there is no seat available on its left, for temp
k[j] = k[j-1] #Move the bigger item 1 step right to make room for temp
j=j-1 #take k[j] all the way left to the place where it has a smaller/no value to its left.
k[j] = temp
return k
Simple way to sort an array.
# Mutate the constant input
# loop into the array
# check if the array[j] have to be greater than 0 and a[j] is less than a[j - 1]
# then swap values and decrease the value swapped.
def insertionSort(array):
a = array
for i in range(0,len(a)):
j = i
while j > 0 and a[j] < a[j - 1]:
a[j], a[j - 1] = a[j - 1], a[j]
j -= 1
return a
# input-> [2,1,3] then array[j] > 0 and array[j] < array[j - 1] -> swap -> decrease j
There are a few pieces of information that help to understand insertion sort.
First of all, i
never gets bigger than len(s)
. In fact, it never is equal to it, either. What range(1, len(s))
does is produces an immutable sequence over which you can iterate. What you will have underneath the following statement (let's assume len(s) = 3
):
for i in range(1, len(s)):
...
is something like this:
for i in (1, 2):
...
You can verify that yourself:
>>> list(range(1, 3))
>>> [1, 2]
So you will iterate two times, first time with i = 1
, and the second time with i = 2
.
Second, it helps to remind yourself that a list you are sorting consists, in essence, of two parts: the part that is sorted (list[0:i-1]
), and the part that is yet to be sorted ([list[i:]
). What you are trying to achieve with insertion sort on every iteration is finding a place to put a current value inside a sorted list. We'll get to that shortly.
Third, the algorithm can be thought of as doing two quite distinct tasks. First one is to iterate over all members in a list and ensure that the list is sorted. That's the part that outer loop concerns itself with (of course, inner loop is involved in actual checks, but it helps to make that simplification). The other one is to find appropriate positions for elements in a list so that a list would be sorted. I.e., if you have a list letters = ['a', 'b', 'd', 'c']
, 'c'
should obviously go to letters[2]
and 'd'
needs to take 'c'
's former place if the list is to be sorted in ascending order. That is the part that inner while
loop does.
How the while loop (and s[j+1] = val
statement) ensures that list is sorted is quite clever, actually. First, it makes sure that we're not overreaching (j >= 0
condition). That is, that we're not selecting s[-1]
element, which in Python would be the last element in the list, and other languages, like Java, ArrayIndexOutOfBounds
exception. Then, it asks: is the number that I'm holding lower than the one before it? If so, it means the list is not sorted and we need to move the bigger number one place towards the end of a list (to the right if you will). Note, the element with which we are comparing other elements remains the same. We are holding it in val
variable. So we need not concern ourselves with accidentally losing it by overwriting it when moving values.
Now, once we move the bigger value to the right, we decrement j
and ask the same question again: is the value at s[j]
bigger than the one that we have in val
? We continue to do so until we find the value that's lower than what we have in val
, or we reach s[0]
without finding lower value. That means that what we hold is the lowest number in a list. Either way, we break out of the while
loop and overwrite s[j+1]
with a value that we have, so that we do not lose value in val
.
To see how it looks in practice, consider a list: [2, 3, 4, 5, 1]
. Let's say we iterate until we reach number 1
, at which point we enter while loop, since 5 > 1
. The steps taken would be:
2, 3, 4, 5, 1 # val = 1, s[j] = 5, j = 3 5 > 1
2, 3, 4, 5, 5 # val = 1, s[j] = 4, j = 2 4 > 1
2, 3, 4, 4, 5 # val = 1, s[j] = 5, j = 1 3 > 1
2, 3, 3, 4, 5 # val = 1, s[j] = 5, j = 0 2 > 1
2, 2, 3, 4, 5 # val = 1, s[j] = 5, j = -1 break out of while
1, 2, 3, 4, 5 # val = 1, s[j] = 5, j = -1 put val into s[0]
And that's basically it. Iterate over the loop, check that values before the current one are lower than the one we're holding, and if not, move those values to the right to make space for our value. And there you have it - insertion sort.
Edit: there is a very nice, visual explanation on code review if you're still finding it hard to see how it works.
def ins(l):
for i in range(1, len(l)):
current_index = i
current_value = l[i]
while current_index > 0 and current_value < l[current_index - 1]:
l[current_index] = l[current_index - 1]
current_index -= 1
l[current_index] = current_value
print(l)
To see how that implementation works, check it out visualized here: http://goo.gl/piDCnm
However, here is a less confusing implementation of insertion sort:
def insertion_sort(seq):
for i in range(1, len(seq)):
j = i
while j > 0 and seq[j - 1] > seq[j]:
seq[j - 1], seq[j] = seq[j], seq[j - 1]
j -= 1
def insertSort(list):
for i in range(0, len(list)):
index = list[i] // index holder for swapAt position
while i > 0 and index < list[i - 1]:
list[i] = list[i - 1]
i = i - 1
list[i] = index
return list
print(insert([3,3,6,1,7,2,8])) -> [1, 2, 3, 3, 6, 7, 8]