Vectorising while loop MATLAB insertion sort - matlab

I need to use vectorization to remove the nested while loop inside my for loop, for making an insertion sort program. I am not allowed to have a while loop inside my for loop, I must do it "such that there are no while or for loops in your function except the outermost for loop."
Here is the code I have currently
function insertsort(array)
array = [2 1 3 2 1]
for i = 2:length(array)
value = array(i);
j = i - 1;
while (j >= 1) && (array(j) > value)
array(j+1) = array(j);
j = j-1;
end
array(j+1) = value;
end %forLoop
disp(array);
end %insertionSort

This will do it:
array = [2 1 3 2 1]
for i = 2:length(array)
value = array(i);
j = i - 1;
array_j=array(1:j);
array_j_indices=cumsum(array_j>value);
[~,n]=find(array_j_indices==1);
newArray=array;
array(n+1:i)=array_j(array_j>value);
j=j-max(array_j_indices);
array(j+1) = value;
end %forLoop
disp(array);
Explanation: First take elements from j to 1 in an array, since while loop will eventually scan through those elements. Find which of the elements are greater than the value and take its cumulative sum which will tell us how many elements are greater than the value. Because that is the amount we have to decrement j by. Now, find where the first 1 occurs (i.e. the first index at which the number is greater than value, since we have to shift every element to the right by 1 position from that index). After that, decrement j and put the value back. You are done.

Is there a reason you don't want to use the built in sort ?
ans=sort(array)
will do it.

Related

how to compare all vector indexes with a constant value and switch the value of another variable (0 1) based on that

I have a 1x24 vector (a). I should define a command in Matlab which compare all 24 values of a vector (a) with a certain value (mean (b)) and if the vector (a) item is greater than certain value (mean (b)), ''I'' sets 1 and if the vector item is less than certain value ''I'' sets 0. I wrote the below code:
for i=1:length(a)
if a(i) >= mean(b)
I = 1;
else
I = 0;
end
end
But it implements the comparison only for the last index of vector a and sets I=0. How can I fix the command that do the comparison for all indexes of vector a?
In MATLAB, you can use the following syntax to do so:
I = a >= mean(b);
If you want to use your code for doing so, you'll need to initialize I as a vector, and modify its indices as follows:
I = zeros(length(a),1)
for ii=1:length(a)
if a(ii) >= mean(b)
I(ii) = 1;
else
I(ii) = 0;
end
end
You should read about logical indexing in matlab. You don't need for loops for what you are doing. For example, if you have,
rng(5);
a = rand(1,10);
b = 0.5;
then, I = a > b; will return a logical array with zeros and ones, where one indicates the position in the array where the given condition is satisfied,
I =
0 1 0 1 0 1 1 1 0 0
Using these indices, you can modify your original array. For example, if you wish to change all values of a greater than b to be 10, you would simply do,
a(a > b) = 10;
Specifically, if you need indices where the condition is satisfied, you can use, find(a > b), which in this example will give you,
ans =
2 4 6 7 8

vectorising while loop insertion sort matlab

array = [2 1 3 2 1]
for i = 2:length(array)
value = array(i);
j = i - 1;
array_j=array(1:j);
array_j_indices=cumsum(array_j>value);
[~,n]=find(array_j_indices==1);
newArray=array;
array(n+1:i)=array_j(array_j>value);
j=j-max(array_j_indices);
array(j+1) = value;
end %forLoop
disp(array);
Hello,
I saw this code for vectorising while loop insertion code but i cannot seem to understand how it works.
How does cumsum(array_j>value) work? I understand and tested cumsum functions but i can't seem to understand how the rational operator of (array_j>value) works in the within a cumsum function under the for loop.
Also, i dont understand how [~,n]=find(array_j_indices==1) stores value for the matrix of n. Does it store it only in columns because there is a not (~) in the rows?
cumsum(array_j>value)?
array_j>value: due to the sorted nature of array_j, the result is always some zeros followed by some ones, e.g. [0 0 0 0 1 1 1 1]
cumsum(array_j>value) = [0 0 0 0 1 2 3 4]: at most one element will be equal to 1.
[~,n]=find(array_j_indices==1); ?
Because there is only one row, this is equal to n=find(array_j_indices==1);.
Fastest implementation?
Note that this 'vectorised' code is slower the following (easier) implementation:
for i = 2:length(array)
value = array(i);
j = i - 1;
n=find(array(1:j)>value,1);
array(n+1:i)=array(n:j);
array(n) = value;
end
and much slower than the built-in matlab sort method.

Push Values Onto a Vector in a Control Loop

In MATLAB is there a way to define a variable say runningValue and push values onto it in succession an unknown number of times?
What I have been doing is something like this:
runningValue = 0;
for j=1:length(someVector)
...
runningValue(end+1) = (some value);
...
endfor
But this forces a leading 0. I know that after all is done I could just put j(1) = []; but I was wondering if there is a more elegant way to do this.
Note that the length of the runningValue variable is not a priori known; in particular, we are not populating length(someVector) elements, referring to the pseudocode above, and the j index is no of use.
Aside from initializing runningValue to empty, you might as well try reducing the number of appendition, which is an O(n) operation. Instead of appending an element on every loop, you can double the size of the array when it is full. This way, you reduce the number of appendition from n to log(n):
runningValue = [];
len = 0;
for j = 1:n
if (j > len)
runningValue = [runningValue zeros(size(runningValue))];
len = length(runningValue);
end
runningValue(j) = (some value);
end
runningValue(j+1:len) = []; % If you need to remove the extra zeros
You can simply construct a new vector using an existing vector plus another element:
runningValue = [];
for j=1:5
runningValue = [runningValue i]; % i can be the element you want to append to the vector
end
This code will output:
runningValue =
1 2 3 4 5

Find the number of pairs whose sum is divisible by k?

Given a value of k. Such that k<=100000
We have to print the number of pairs such that sum of elements of each pair is divisible by k.
under the following condition first element should be smaller than second, and both element should be less than 109.
I've found a solution, let a and b numbers such that (a+b)%k=0 then we have to find that pairs (a,b), where a<b, so let's count how many pairs (a,b) satisfy the condition that a+b=k, for example if k=3 0+3=3, 1+2=3, 2+1=3, 3+0=3 there are 4 pairs but only 2 pairs which is (K+1)/2 (integer division) so similar for find the pairs (a,b) which sum is 2k, 3k,.. nk, and the solution will be (k+1)/2 + (2k+1)/2 + (3k+1)/2 + ... + (nk+1)/2, and that is equal to (k*n*(n+1)/2 + n)/2 with time complexity O(1), take care in the case if n*k=2*10^9, because a can't be more than 10^9 for the given constraint.
Solution in O(N) time and O(N) space using hash map.
The concept is as follows:
If (a+b)%k=0 where
a=k*SOME_CONSTANT_1+REMAINDER_1
b=k*SOME_CONSTANT_2+REMAINDER_2
then (REMAINDER_1 +REMAINDER_2 )%k will surely be 0
so for an array (4,2,3,31,14,16,8) and k =5 if you have some information like below , you can figure out which all pairs sum %k =0
Note that, Bottom most row consist of all the remainders from 0 to k-1 and all the numbers corresponding to it.
Now all you need to do is move both the pointer towards each other until they meet. If both the pointers locations have number associated with it their sum%k will be 0
To solve it, you can keep track of all the remainder you have seen so far by using hash table
create a hash map Map<Integer, List>.
Pre-populate its keys with 0 to k-1;
iterate over array and put remainder of each number in the map with Key = remainder and put the actual number in the list,
Iterate over the key set using two pointers moving each other. And sum += listSizeAsPointedByPointer1 * listSizeAsPointedByPointer2
One way is brute force:
int numPairs = 0;
for (i = 0; i < 10e9; i++)
{
for (j = i+1; j < 10e9; j++)
{
int sum = i + j;
if (sum % k == 0) numPairs++;
}
}
return numPairs;
I'll leave it up to you to optimize this for performance. I can think of at least one way to significantly speed this up.
Some psuedo-code to get you started. It uses the brute-force technique you say you tried, but maybe something was wrong in your code?
max = 1000000000
numberPairs = 0
for i = 1 to max - 2 do
for j = i + 1 to max - 1 do
if (i + j) mod k = 0 then
numberPairs = numberPairs + 1
end if
end do
end do

How can I shift array element using a for loop in Matlab?

I'm trying to shift all the elements of an array to the left, so that the first element would become the last element, the second becomes the first, the third the second, etc. I know about the circshift commands, but I would like to do this using a for loop.
Here's what I did.
old=[]
n=length(old)
for i=1;i<(n-1);i=i+1;
for j=2;j<n;j=j+1;
new(j)=old(i)
end
end
But it of course didn't work. I'm having trouble figuring out to make an array of n elements, without specifying n, which is why I used old=[], but I think that created an array of 0 elements.
How can I make this code work?
If you want to avoid specifying the n length of the array, you have to give it as an input argument in a function.
For example you can do something like this:
function new = shiftLeft(old)
n = length(old);
for i =1:n
new(i) = old(mod(i,n)+1);
end
return
So with this one, if you have an array for example old = [1 2 3 4]; you can will get something like new = [2 3 4 1];
mod(a,b) is the modulo operator, you can find more information if you type help mod.
So your irst step is to learn how to specify a for loop in Matlab, what you have is like C syntax. This is not Matlab syntax at all.
The following is how to do it using forloops but this is not good matlab programming. You could easily do it without loops too.
vec = 1:10;
temp = [];
shiftby = 2;
for ii = 1:shiftby %Each iteration shifts by one
temp = vec(end); %Store the last element of vec
for jj = size(vec, 2):-1:2; %inner loop must shift each element from the end to element 2
vec(jj) = vec(jj-1);
end
vec(1) = temp; %put the old end value at the beginning
end
but you could also just do this which is a much more Matlabesque way to code it:
vec = [vec(end - shiftby + 1: end), vec(1:end - shiftby)]