A simple sorting algorithm - arrays

This is a simple sorting function that I wrote in Matlab:
function [matrix] = sorting(matrix)
for index = 1:length(matrix)-1
if matrix(index) > matrix(index + 1)
temp = matrix(index + 1);
matrix(index + 1) = matrix(index);
matrix(index) = temp;
end
end
check_sorted(matrix)
end
function [matrix] = check_sorted(matrix)
count = 0;
for index = 1:length(matrix)-1
if matrix(index) < matrix(index + 1)
count = count + 1;
end
end
if count+1 < length(matrix)
sorting(matrix);
end
end
The input for sorting function is a 1D array, e.g. [4 3 2 1], and it successfully returns the sorted array [1 2 3 4] for the first time I call it, but then it starts to return unsorted arrays?

You've got a missing semicolon that is causing the results of each call to check_sorted to be displayed, which is confusing things. If you add the semicolon, the output from sorting with the array [2 4 1 3] suggested in the comments is:
>> sorting([2 4 1 3])
ans =
2 1 3 4
Clearly this isn't sorted. The problem is that MATLAB passes function arguments by value, not by reference. Since you're not returning the re-sorted matrix from check_sorted or updating the return matrix in sorting the original matrix never gets updated. You need to change at least one line in each function (changed lines are commented):
function [matrix] = check_sorted(matrix)
count = 0;
for index = 1:length(matrix)-1
if matrix(index) < matrix(index + 1)
count = count + 1;
end
end
if count+1 < length(matrix)
matrix = sorting(matrix); % change: return re-sorted matrix
end
end
function [matrix] = sorting(matrix)
for index = 1:length(matrix)-1
if matrix(index) > matrix(index + 1)
temp = matrix(index + 1);
matrix(index + 1) = matrix(index);
matrix(index) = temp;
end
end
matrix = check_sorted(matrix); % change: return checked matrix
end
Now the matrix will be updated if it is not sorted on the first (or any subsequent) pass and the fully sorted matrix will be returned by sorting.
This is an odd sort of recursion that really isn't necessary. If you change check_sorted to return a boolean value, true for sorted, false for not sorted, you can change that recursion to a while loop around the for loop in sorting:
function [TF] = check_sorted2(matrix)
count = 0;
for index = 1:length(matrix)-1
if matrix(index) < matrix(index + 1)
count = count + 1;
end
end
TF = count+1 == length(matrix); % TF = true if matrix is sorted
% TF = false otherwise
end
function [matrix] = sorting2(matrix)
while ~check_sorted2(matrix) % keep going until matrix is sorted
for index = 1:length(matrix)-1
if matrix(index) > matrix(index + 1)
temp = matrix(index + 1);
matrix(index + 1) = matrix(index);
matrix(index) = temp;
end
end
end
end
Of course the whole thing can be optimized and vectorized, but this will at least get you going.

i tested your algorithms and it worked. so something else might be wrong. but this algorithm is very very inefficient. you may google sort and pick one that suits you.
if you really want to stick with the algorithm, you could improve it by shortening the two loops. for example, after first call to sorting, for each subsequent call to sorting, you could shorten the loop cycle by 1 because the first call to sorting would put the largest number to the end of the array, the second call would put the second largest to the second from the end, and so on. this is so called bubble sorting. also in check_sorted, you don't need to go through the entire length of the array to check if the array has been sorted. as soon as you see matrix(index) > matrix(index + 1), you can immediately exit the loop (after you set a flag to indicate the array hasn't been sorted).

Related

Removing rows from matrix

I have a question above removing rows from a matrix. I have the code below which removes the rows I want, but the problem is each time a row is removed it changes the size of the matrix. When the size of the matrix changes, the for loops can no longer run through the original size of the matrix because it has changed. Does anyone know how to get around this? Thanks.
for i = 1:NT
for j = 1:NP
for k = 1:NP
if ContactPartData((i-1)*(NP*(NP-1)) + ((j-1)*NP + k),2) == 0
ContactPartData((i-1)*(NP*(NP-1)) + ((j-1)*NP + k),:) = [];
else
end
end
end
end
For these cases, it is typically easier to record which rows you want to remove, and then remove them all at once at the end. This is more efficient than repeatedly removing a single row. And it solves your problem at the same time!
toremove = false(size(ContactPartData,1),1);
for i = 1:NT
for j = 1:NP
for k = 1:NP
if ContactPartData((i-1)*(NP*(NP-1)) + ((j-1)*NP + k),2) == 0
toremove((i-1)*(NP*(NP-1)) + ((j-1)*NP + k)) = true;
end
end
end
end
ContactPartData(toremove,:) = [];
Of course, in this particular case, the loop is not needed at all:
toremove = ContactPartData(:,2) == 0;
ContactPartData(toremove,:) = [];
Additionally, it might be more efficient to do it the other way around, selecting which rows to preserve (time the code to find out!):
tokeep = ContactPartData(:,2) ~= 0;
ContactPartData = ContactPartData(tokeep,:);

Trouble understanding one line in Insertion Sort (Python 3)

I was looking through the other threads concerning the Insertion Sort but didn't find the answer that relates to the specific part of it which I do not understand.
My full Insertion Sort algorithm can be seen below. It works as intended, but I cannot figure out the purpose of that last line.
array[position] = value
Let me explain through an example:
When the 'for' loop starts, index = 1.
=> value = array[1] = 3
=> position = 1
=> Since 4 > 3, the item at index 1, is swapped with the item at index 0.
=> position -= 1
=> position = 0
We now get to the line which confuses me:
array[0] = value
=> value = array[index] = array[0] = 3
However, when the 'for' loop goes through its second iteration, index = 2.
And so immediately value = array[2] and position = 2 ?
Even though I know that this last line of code is necessary I just cannot see what purpose it serves.
Could someone please explain to me this final logical step?
Thank you in advance for your time and help.
array = [4,3,5,6,12,9,8,6]
for index in range (1, len(array)):
value = array[index]
position = index
while position > 0 and array[position - 1] > value:
array[position] = array[position - 1]
position -= 1
array[position] = value
The position variable represents (at the end) where you will eventually insert the number. Without the last line, you are not inserting the number at 'position' at the correct place (it will result in the 1 index after). Below is my code for insertion sort.
def insertionSort(arr):
length = len(arr)
for i in range(1, length):
currNum = arr[i]
j = i - 1
while j >= 0 and currNum < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j+1] = currNum
return arr
You wouldn't have really swapped the numbers without that line, would you?
index 1:
-> [4,3,5,6,12,9,8,6] (enters while loop)
-> [4,4,5,6,12,9,8,6] ("pushes" 4 to position 1)
-> <waits for while loop to finish>
-> [3,4,5,6,12,9,8,6] (assigns 3 to position 0 since there are no other elements > 3)
index 2:
...
I think is not really needed at start in for loop, because it was used to index inside the loop. Looks the picture

adjacentElementsProduct function in ruby

I'm stuck on an algorithm for a function called adjacentElementsProduct that accepts an array as the argument. It's supposed to return the largest product of adjacent numbers in the array. For example, if the argument is [2,4,1,3,2,6] it would return 12 because of the pair of 2 and 6.
my code is
def adjacentElementsProduct(inputArray)
idx1 = 0
idx2 = 1
while idx2 < inputArray.length
pair = [inputArray[idx1], inputArray[idx1 + 1]]
next_pair = [inputArray[idx2], inputArray[idx2 + 1]]
if next_pair.reduce(:+) > pair.reduce(:+)
pair = next_pair
idx1 += 1
idx2 += 1
else
idx1 += 1
idx2 += 1
end
end
pair.reduce(:+)
end
I just can't figure out where my code is not working. I'm just looking for a push in the right direction because I know just being given the answer won't help me as much. Can anyone help me?
The code makes no sense :).
You are using + instead of *
And in the loop you always assign pair = [inputArray[idx1], inputArray[idx1 + 1]].
So you always return the last pair or the previous. If the maximum product is at the beginning, you still keep advancing the pair variable until the end of the loop.
Besides, the solution is quite complicated.
def adjacentElementsProduct(inputArray)
index = 0
length = inputArray.length
max = 0
while index < length-1 do
result = inputArray[index] * inputArray[index+1]
max = result if result > max
index += 1
end
max
end

Vectorizing a code that requires to complement some elements of a binary array

I have a matrix A of dimension m-by-n composed of zeros and ones, and a matrix J of dimension m-by-1 reporting some integers from [1,...,n].
I want to construct a matrix B of dimension m-by-n such that for i = 1,...,m
B(i,j) = A(i,j) for j=1,...,n-1
B(i,n) = abs(A(i,n)-1)
If sum(B(i,:)) is odd then B(i,J(i)) = abs(B(i,J(i))-1)
This code does what I want:
m = 4;
n = 5;
A = [1 1 1 1 1; ...
0 0 1 0 0; ...
1 0 1 0 1; ...
0 1 0 0 1];
J = [1;2;1;4];
B = zeros(m,n);
for i = 1:m
B(i,n) = abs(A(i,n)-1);
for j = 1:n-1
B(i,j) = A(i,j);
end
if mod(sum(B(i,:)),2)~=0
B(i,J(i)) = abs(B(i,J(i))-1);
end
end
Can you suggest more efficient algorithms, that do not use the nested loop?
No for loops are required for your question. It just needs an effective use of the colon operator and logical-indexing as follows:
% First initialize B to all zeros
B = zeros(size(A));
% Assign all but last columns of A to B
B(:, 1:end-1) = A(:, 1:end-1);
% Assign the last column of B based on the last column of A
B(:, end) = abs(A(:, end) - 1);
% Set all cells to required value
% Original code which does not work: B(oddRow, J(oddRow)) = abs(B(oddRow, J(oddRow)) - 1);
% Correct code:
% Find all rows in B with an odd sum
oddRow = find(mod(sum(B, 2), 2) ~= 0);
for ii = 1:numel(oddRow)
B(oddRow(ii), J(oddRow(ii))) = abs(B(oddRow(ii), J(oddRow(ii))) - 1);
end
I guess for the last part it is best to use a for loop.
Edit: See the neat trick by EBH to do the last part without a for loop
Just to add to #ammportal good answer, also the last part can be done without a loop with the use of linear indices. For that, sub2ind is useful. So adopting the last part of the previous answer, this can be done:
% Find all rows in B with an odd sum
oddRow = find(mod(sum(B, 2), 2) ~= 0);
% convert the locations to linear indices
ind = sub2ind(size(B),oddRow,J(oddRow));
B(ind) = abs(B(ind)- 1);

Mapping An Array To Logical Array In Matlab

Let's say an array a=[1,3,8,10,11,15,24], and a logical array b=[1,0,0,1,1,1,0,0,0,1,1,1,1,1], how to get [1,1,3,1,3,8,1,3,8,1,2,3,8,10], see where logic becomes 1 in b, the array index of a resets so it starts from the beginning, also the same where the logic becomes 0 a array starts from beginning and continues as 1,3,8,10..etc.
you can use diff to find where b changes, then use arrayfun to generate indexes for a:
a=[1,3,8,10,11,15,24];
b=[1,0,0,1,1,1,0,0,0,1,1,1,1,1];
idxs = find(diff(b) ~= 0) + 1; % where b changes
startidxs = [1 idxs];
endidxs = [idxs - 1,length(b)];
% indexes for a
ia = cell2mat(arrayfun(#(x,y) 1:(y-x+1),startidxs,endidxs,'UniformOutput',0));
res = a(ia);
You can use a for loop and track the state (0 or 1) of the b array:
a = [1,3,8,10,11,15,24];
b = [1,0,0,1,1,1,0,0,0,1,1,1,1,1];
final = []
index = 0;
state = b(1);
for i = 1:numel(b)
if b(i) ~= state
state = b(i);
index = 1;
else
index = index+1;
end
final = [final, a(index) ];
end

Resources