Is that Insertionsort? - python

I really need your help, I am learning sorting-algorithms and i tried to make an Insertionsort-Algorithm. So could you please tell me whether this is an Insertionsort-Algorithm or not?
def insertsort(l):
for k in range(len(l)):
for i in range(1,len(l)):
if l[i]<l[i-1]:
while l[i]<l[i-1]:
l.insert(i-1,l.pop(i))
return l

yes, it is insertion sort. The pseudocode is as follows:
1. for j = 2 to n
2. key ← A [j]
3. // Insert A[j] into the sorted sequence A[1..j-1]
4. j ← i – 1
5. while i > 0 and A[i] > key
6. A[i+1] ← A[i]
7. i ← i – 1
8. A[j+1] ← key

I do not think so. You used two nested for loops and a while. In the pseudocode provided by #dreadedHarvester and the implementation provided in RosettaCode just one for loop and one while are used.
def insertion_sort(l):
for i in xrange(1, len(l)):
j = i-1
key = l[i]
while (l[j] > key) and (j >= 0):
l[j+1] = l[j]
j -= 1
l[j+1] = key

Related

Why do i need a new variable in the while loop of this implementation of Insertionsort?

I have an implementation of the Insertionsort algorithm where in the lecture there is a new instance variable before the while loop.
def swap(l, i, j):
temp = l[i]
l[i] = l[j]
l[j] = temp
def ins_sort(l):
for i in range(len(l)):
j = i
while j > 0 and l[j - 1] > l[j]:
swap(l, j - 1, j)
j = j - 1
return l
In my testing and playing around the algorithm worked without it as well though and I do not understand why I would need to write an extra line of code if it is not necessary.
def swap(l, i, j):
temp = l[i]
l[i] = l[j]
l[j] = temp
def ins_sort(l):
for i in range(len(l)):
while i > 0 and l[i - 1] > l[i]:
swap(l, i - 1, i)
i = i - 1
return l
It looks like the original code is a translation from the c/c++ implementation where modifying i inside the loop would be persistent and affect the loop itself. However since in python, i will be reset each iteration, the second code will also work.
In short I don't think that line is necessary for a python implementation.
ref:Scope of python variable in for loop
You could also try the following program for Insertion sort where the use of the extra variable is not necessary:
l=[4,3,1,2]
for i in range(1,len(l)):
key=l[i]
for j in range(i-1,-1,-1):
if l[j]>key:
l[j+1]=l[j]
else:
j=j+1
break
l[j]=key
print(l)

How do I close the loop?

I am given an array of n numbers [a0,a1, a2, …, an-1] and I am supposed to write a function named sumOfThree that takes in the array and a number K as the only 2 arguments and outputs the number of unique unordered triplets in the array that sum to K. This is my code:
def sumOfArray(arr,K):
arr.sort()
s=set()
for i in range(len(arr)-2):
j=i+1
k=len(arr)-1
while j<k:
if arr[i]+arr[j]+arr[k]==K:
s.add((arr[i],arr[j],arr[k]))
elif arr[i]+arr[j]+arr[k]<K:
j+=1
else:
k-=1
return len(s)
However I am unable to find the answer. Any help please?
Just as MZ mentioned,
when arr[i]+arr[j]+arr[k]==K, the i,j,k never changed.
However, if you just add a single break as cewaphi mentioned, the while loop will stop at first match for every i loop, instead of walking through all the combinations.
Here is another way to solve the problem:
def sumOfArray(arr, K):
arr.sort()
s = set()
count = 0
for i in range(len(arr) - 2):
for j in range(i+1,len(arr)-1):
for k in range(j+1,len(arr)):
if arr[i] + arr[j] + arr[k] == K:
s.add((arr[i], arr[j], arr[k]))
print('Done')
length = print('length: ' + str(len(s)))
return length
As MZ stated, you are stuck in your if condition.
Either increment j or decrement k so that the condition j < k is met.
Or if you are done with increment i and want to continue with i+1, simply add a break:
if arr[i]+arr[j]+arr[k]==K:
s.add((arr[i],arr[j],arr[k]))
break

Merge sort in python: slicing vs iterating - impact on complexity

I want to check that my understanding of how python handles slices is correct.
Here's my implementation of merge sort:
def merge_sort(L):
def merge(a, b):
i, j = 0, 0
c = []
while i < len(a) and j < len(b):
if a[i] < b[j]:
c.append(a[i])
i += 1
elif b[j] < a[i]:
c.append(b[j])
j += 1
if a[i:]:
c.extend(a[i:])
if b[j:]:
c.extend(b[j:])
return c
if len(L) <= 1:
return L
else:
mid = len(L) // 2
left = merge_sort(L[:mid])
right = merge_sort(L[mid:])
return merge(left, right)
Am I right in thinking that I could replace this:
if a[i:]:
c.extend(a[i:])
if b[j:]:
c.extend(b[j:])
With this:
while i < len(a):
c.append(a[i])
i += 1
while j < len(b):
c.append(b[j])
j += 1
And have the exact same level of complexity? My understanding of slicing is that its complexity is equivalent to slice length? Is that correct?
Does the fact that I'm calling a slice twice (first in the condition, second time inside of it) make it 2x complexity?
Your implementation of mergesort has problems:
in the merge function's main loop, you do nothing if the values in a[i] and b[j] are equal, or more precisely if you have neither a[i] < b[i] nor a[i] > b[i]. This causes an infinite loop.
there is no need to define merge as a local function, actually there is no need to make it a separate function, you could inline the code and save the overhead of a function call.
Here is a modified version:
def merge_sort(L):
if len(L) <= 1:
return L
else:
mid = len(L) // 2
a = merge_sort(L[:mid])
b = merge_sort(L[mid:])
i, j = 0, 0
c = []
while i < len(a) and j < len(b):
if a[i] <= b[j]:
c.append(a[i])
i += 1
else:
c.append(b[j])
j += 1
if a[i:]:
c.extend(a[i:])
else:
c.extend(b[j:])
return c
Regarding performance, slicing or iterating has no impact on complexity since both operations have linear time cost.
Regarding performance, here are directions to try:
replace the test if a[i:] with if i < len(a). Creating the slice twice is costly.
perform the sort in place, avoiding the append operations
restructure the main loop to have a single test per iteration
Here is a modified version:
def merge_sort(L):
if len(L) <= 1:
return L
else:
mid = len(L) // 2
a = merge_sort(L[:mid])
b = merge_sort(L[mid:])
i, j, k = 0, 0, 0
while True:
if a[i] <= b[j]:
L[k] = a[i]
k += 1
i += 1
if (i == len(a)):
L[k:] = b[j:]
return L
else:
L[k] = b[j]
k += 1
j += 1
if (j == len(b)):
L[k:] = a[i:]
return L

Insertion Sort in python using Key

def insertion_sort2(A):
for i in range(1,len(A)):
key = A[i]
j = i-1
for j in range(i-1,0,-1):
if A[j] > key :
A[j+1] = A[j]
else:
A[j+1] = key
break
for i in range(1, len(arr)):
key = arr[i]
j = i-1
while j >=0 and key < arr[j] :
arr[j+1] = arr[j]
j -= 1
arr[j+1] = key
Hello I have tried both methods to do simple Insertion Sort in c++ it works but in python it is not working,but both of them are giving answers like
1st one:
[56, 77, 77, 77, 77, 77, 77, 99]
2nd one:
does not sort even
Note:The second one starts after break and I have not run them both together,I commented out one and then run the other one
First of all you don't go upto the 0th element in the array in the inner loop. In python's range function, the range is counted uptil one before the second term. On putting range(i-1,-1,-1) the range becomes i-1 to 0.
Secondly, you are not swapping the two consecutive elements , just assigning (j)th element a value of (j+1)th element. But what about assigning jth value to (j-1)th element.
Third, there's no meaning of doing A[j+1] = key as it already is key.
def insertion_sort2(A):
for i in range(1,len(A)):
key = A[i]
j = i-1
for j in range(i-1,-1,-1):
if A[j] > key :
A[j+1], A[j] = A[j], A[j+1]
else:
break

Having difficulty in implementing QuickSort

I have been trying to implement quicksort for like 2 days now (Looks like my programming skills are getting rusty). I do not know what I am doing wrong. I was about to give up so I thought I should consult the discussion forum.
here is the code that I am trying to implement in python. But it is not giving the desired result. Anyone can please point out what I am doing wrong?
def QuickSort(A,p,r):
if p < r:
pivotIndex = Partition(A,p,r)
QuickSort(A,p,pivotIndex-1)
QuickSort(A,pivotIndex+1,r)
return A
def Partition(A,p,r):
m = A[p]
i = p+1
for j in range( p+1 , r ):
if A[j] < m:
A[j] , A[i] = A[i] , A[j]
i+=1
A[p], A[i-1] = A[i-1] , A[p]
return i-1
The output for test input is:
>>>QuickSort([9,8,7,6,5,4,3,2,1],0,9)
[1, 3, 5, 6, 7, 4, 8, 2, 9]
I will be very thankful if anyone help me in implementing this.
Regards
Slicing doesn't return a view of the original list; it makes a new list out of data from the old list. That means the recursive calls to QuickSort don't change the original list.
You can try this implementation in one line of code:
def QuickSort(list):
return [] if list==[] else QuickSort([x for x in list[1:] if x < list[0]]) + [list[0]] + QuickSort([x for x in list[1:] if x >= list[0]])
print QuickSort([9,8,7,6,5,4,3,2,1])
I have figured out the answer. It appeared that I was passing one-less to the QuickSort method
def QuickSort(A,p,r):
if r-p <= 1: return
pivotIndex = Partition(A,p,r)
QuickSort(A,p,pivotIndex)
QuickSort(A,pivotIndex+1,r)
return A
def Partition(A,p,r):
m = A[p]
i = p+1
for j in range( p+1 , r ):
if A[j] < m:
A[j] , A[i] = A[i] , A[j]
i= i + 1
A[p], A[i-1] = A[i-1] , A[p]
return i-1
It is the correct implementation
It seems that you wanted to keep the pivot on the left side and skip it, but that didn't turn out well, so I just moved it to the end of the array and reduced the iteration index accordingly and then reversed the post-partition swap (to take into consideration the pivot movement).
def Partition(A,p,r):
m = A[p]
A[p], A[r] = A[r], A[p]
i = p
for j in range( p, r ):
if A[j] < m:
A[j] , A[i] = A[i] , A[j]
i+=1
A[r], A[i] = A[i] , A[r]
return i
I think that you could do it with the pivot on the left side, but then you would have to change the loop direction I guess, but I am not sure.
EDIT: Sorry I forgot to add the call is then QuickSort([9,8,7,6,5,4,3,2,1],0,8), since the indices are inclusive now.

Categories