Personalized sorting algorithm that operates on just half of the array. (in C) - arrays

I have a simple task but I found myself running in circles.
I need to "create" a sorting algorithm using already seen classic ones that will sort an array using the lowest possible number of memory accesses.
The generated array has some rules though:
the first half is generated like this A[i]=rand() % (n/10);, so we have small numbers spanning from 0 to 9.
the second half is like that A[i]=(n-i)*(n-i);, here we have bigger numbers, but they're generated in a descending order.
For the first half I found that using counting sort is very effective, giving me around 4.5k memory accesses. For the second half, the best way is to just reverse the array since it's already decreasing, but I do want it in an ascending order.
My idea was splitting the array in two sub arrays, sorting the first one, reversing the second one and then merging and printing them.
I wrote a split function:
void split(int* A, int* A1, int* A2, int q){
for(int i=0; i<q; i++){
A1[i]=A[i];
ct_op=ct_op+2; //ci perdo un 10k accessi
}
for(int i=q+1; i<q*2-1; i++){
A2[i]=A[i];
ct_op=ct_op+2;
}} //where q is the dim of the array /2
Then I apply the counting sort to my array A1 that works and gives me back my B array which is now ordered. Now, I can't seem to reverse the second half of the array (which should be contained in A2).
void reverse(int* A, int dim){
int i; int j; int temp;
for(i=n/2, j=n-1; i<j; i++,j--){
temp=A[i];
A[i]=A[j];
A[j]=temp;
}}
That doesn't work and the array doesn't get reversed.
Another problem that I have is that the A2 array doesn't start from the half of the A1 array. It's just a bunch (array dim/2) of 0s and then I get the second half of the arrays:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2500 2401 2304 2209 2116 2025 1936 1849 1764 1681 1600 1521 1444 1369 1296 1225 1156 1089 1024 961 900 841 784 729 676 625 576 529 484 441 400 361 324 289 256 225 196 169 144 121 100 81 64 49 36 25 16 0 0
why is that? I could just start printing from half of it, but that's not quite what I'm looking for.
I guess the TLDR is how do I properly split an array and how do I reverse the content of it?
Thank you.

I' ll just use the variables from your code and try to answer the TLDR, because your code is very inefficient.
The following picture shows the array A (which is just a pointer), the pointer A1 and the pointer A2.
As you can see here there is no need for splitting it with the for-loops you used. You just call your count sort algorithm with the pointer A or A1 and the length q and you pass the pointer A2 and the length q to a array reverse algorithm.
I found some implementations for such an array reverse algorithm here.

Related

2D array grouping 1's in C

2D array of 1s and 0s. How to label every group of 1s with a unique number?
I’m stuck on this problem for a while now. 1s can be grouped vertically, horizontally and diagonally. How can you go about solving this? For example,
0 0 1 1 0
0 1 1 0 0
0 0 0 0 1
0 0 0 1 0
Should be transformed to
0 0 x x 0
0 x x 0 0
0 0 0 0 y
0 0 0 y 0
x, y can be any unique numbers.
Appreciate it.
Here is what I have so far for iterative: https://i.imgur.com/oCmYC02.png
But the result is a bit off because it only checks for immediate adjacent 1's: https://i.imgur.com/DAtTBmM.png
Anyone have any idea how to fix this?
I'd do it like this:
Scan 2D array sequentially, row by row, column by column
If 1 found, use variation of the flood fill algorithm, which moves in 8 directions instead of 4, from that starting point (see normal 4-direction algorithm at https://en.wikipedia.org/wiki/Flood_fill), since you have diagonal example with "y", each time using new filler number.
Repeat 1 and 2 until no more ones left.

How to replace all occurences of elements of a two dimensional array in do loops in fortran

I've got stdin like that (elements are always > 10)
75 33 44 51
51 87 33 77
77 51 91 45
17 29 30 40
I would like to substitute 1 for one of the elements in each row (randomly - according to a random 1 =< n =< 4) and 0 for the others in the row, but so as to change equal elements throughout, i.e., 51 in the 1st, 2nd, and 3rd rows, 33 in in the 1st and 2nd rows, and 77 in the 2nd and 3rd rows but so that I don't get two 1s in a row. Assuming that n=4 for the 1st and 2nd row, and n=3 for the 3rd and 4th one, I should end up with
0 0 0 1
1 0 0 0
0 1 0 0
0 0 1 0
which is different from just putting n's in, i.e., I don't want
0 0 0 1
0 0 0 1
0 0 1 0
0 0 1 0
What I actually want is to change all occurrences of equal elements according to the values of their elements throughout. E.g., replacement 51 -> 1 should change 51 in the 1st, 2nd, and 3rd row to 1 as soon as 51 in the 1st row is changed to 1, but not their names. Their names c(i,j) in the array should, however, respond with their new value when called. Then, random n's should be overruled by already existing 0's and 1's in each next row, but should stay when a row is not so affected via links to the previous rows as the 4th row.
I didn't put in any Fortran specifics because I want to avoid the discussion being led astray. Constructive suggestions would be greatly appreciated.
You need to read about the WHERE construct. If I understand your description, this toy program should work for you.
program foo
implicit none
integer c(3,4), i, n
real u
c = transpose(reshape([75,33,44,51,51,87,33,77,77,51,91,45],[4,3]))
call prn ! Print original matrix
do i = 1, 3
call random_number(u)
n = 1 + floor(4*u)
print '(A,I0)', 'n = ', n
where(c(i,:) /= c(i,n)) c(i,:) = 0
where(c == c(i,n)) c = 1
call prn ! Print altered matrix
end do
contains
subroutine prn
integer i
do i = 1, 3
write(*,'(4(I0,1X))') c(i,:)
end do
print *
end subroutine prn
end program foo

Hungarian Algorithm - Wikipedia method doesn't work for this example

I'm trying to implement a Hungarian Algorithm in C.
I have the matrix:
35 0 0 0
0 30 0 5
55 5 0 10
0 45 30 45
And I'm up to the stage where I have to find the minimum amount of lines to cover all zeroes (making as many assignments as possible). Obviously, by inspection this is columns 1 and 3 and row 1.
Wikipedia suggests the following method:
Row 1 has three zeroes: pick any (I pick the first one) and assign it
Row 2: Assign the first zero
Row 3: Assign the 3rd zero
Row 4 is unassigned (since the only zero is in a col that already has an assigned zero)
If I follow this for my matrix above, I get:
35 0' 0 0
0' 30 0 5
55 5 0' 10
0 45 30 45
Where zero prime is the assigned zero. Then, following Wikipedia's instructions below, I mark row 4 (unassigned zero), column 1 (col with the unassigned zero), then row 2 (row with a zero in a marked col).
So that would suggest that the min lines to hit all zeroes are:
+--------
|
+--------
|
But this doesn't hit the zero at (2, 3). Relevant C code:
for (i = 0; i < M->size; i++) {
for (j = 0; j < M->size; j++) {
if (M->values[i][j] == 0) {
if (assigned_cols[j] == 0) {
assigned_cols[j] = 1; // We've assigned something in this col
assigned_rows[i] = 1; // We've assigned something in this row.
marked_rows[i] = 0;
total--;
break; // Go to the next row
} else {
marked_cols[j] = 1; // Then there exists a zero in this col in an unassigned row
mark_col(M, j); // marks all elements in column j
total++;
}
}
}
}
This code chooses which zeroes are zero prime (assigns zeroes).
Then this code marks all rows having assignments in newly-marked columns:
for (i = 0; i < M->size; i++) {
if (marked_cols[i] == 1) {
for (j = 0; j < M->size; j++) {
//iterating through rows
if (M->values[j][i] == 0) {
// then (j,i) is a zero in a marked col
// mark the row
if (marked_rows[j] != 1) {
total++;
marked_rows[j] = 1;
}
break; // no need to continue more
}
}
}
}
But this (and the wikipedia explanation) fails for my matrix above. How come?
Wikipedia is lacking explanation on the algorithm, the assignments will be done in the last step!
STEP 0
35 0 0 0
0 30 0 5
55 5 0 10
0 45 30 45
STEP 1-2
all rows-columns have at least one 0 so step 1 leaves array the same
35 0 0 0
0 30 0 5
55 5 0 10
0 45 30 45
STEP 3
All zeros in the matrix must be covered by marking as few rows and/or columns as possible
- - - -
| |
| |
| |
Note that no assignments are done thus far and you need to cover all zeros. Your cover left zero (2,3) uncovered!!
Now take min element that is not covered e.g 5 (take the 5 at position (2,4))
-Reduce (by 5) all elements that where not covered.
-Increase (by 5) all elements crossed by two lines.
-Rest remain same
So the array:
40 0 5 0
0 25 0 0
55 0 0 5
0 40 30 40
Now check again for min required lines: now you need 4 lines (equal to size n=4 of rows of array, so we stop).
Finally assignment:
Start from lines with only one zero this will surely be assigned:
40 0 5 _
0 25 _ 0
55 _ 0 5
_ 40 30 40
Multiple assignments exist (I use _ for assignment).
More specifically two assignments we get: (one stated above with total cost 5) and:
40 _ 5 0
0 25 0 _
55 0 _ 5
_ 40 30 40
With also cost 5!
EDIT
Based on comment it seems that I didn't get the exact part that op was asking so I will answer this specific part keeping the general description of the algorithm above.
The mistake (due to bad Wikipedia description) is here:
Where zero prime is the assigned zero. Then, following Wikipedia's
instructions below, I mark row 4 (unassigned zero), column 1 (col with
the unassigned zero), then row 2 (row with a zero in a marked col).
Totally agree till now but...it's not complete!!!
When correctly marking row2 you need to go to step 2 (of Wikipedia)
and check again for columns with zeros in this case column 3 should
also been marked, this also causes the row 3 to be marked as well (due to assigned zero in the newly marked column 3) and
there you stop (no other rows or columns should be marked)!!
So overall the marked columns and rows:
+ +
35 0' 0 0
0' 30 0 5 +
55 5 0' 10 +
0 45 30 45 +
And the lines you get by choosing the marked columns and unmarked lines:
- - - -
| |
| |
| |
which is the right one as described in the first part of answer and leads to right results in next stages (also explained above).
One very similar post that states literally same thing can be found on mathstackexchange:
finding the minimum number of lines to cover all zeros in an assignment probem

how to generate an image in the format of the mnist database?

I need to make a handwritten image to be tested with a neural network in Matlab. When I see the data contained in the training images from the MNIST I see that it is an array of different gray scales like:
Columns 343 through 351
0 -0.0240 0.4002 0.6555 0.0235 -0.0062 0 0 0
Columns 352 through 360
0 0 0 0 0 0 0 0 0
Columns 361 through 369
0 0 0 -0.0079 0.1266 0.3272 -0.0233 0.0005
corresponding to a 20x20 image, unrolled into a 1*400 dimensional array.
I have downloaded an image in jpeg format and did the following:
im=imread('image.jpg');
gi=rgb2gray(im);
gi=gi(:);
gi=gi';
that generates me an array gi that says <1*400 uint8>, the last part of uint8 does not appear in the MNIST samples when I put it in Matlab. When I check it up my array it appear the following values:
Columns 289 through 306
58 105 128 133 142 131 76 21 1 0 3 0 2 4 17 12 7 0
Columns 307 through 324
1 15 42 75 97 105 98 73 31 4 1 0 0 0 0 2 4 3
Columns 325 through 342
0 0 1 4 21 37 55 59 46 26 9 0 0 0 0 0 0 0
Columns 343 through 360
1 1 0 0 0 1 7 14 21 21 14 5 0 0 0 0 0 0
Columns 361 through 378
0 0 0 0 0 0 0 0 0 1 2 1 0 0 0 2 0 0
when I visualize them all is fine, but when I want to run my program the following message appears:
??? Error using ==> mtimes
MTIMES is not fully supported for integer classes. At least one input must be scalar.
Error in ==> predict at 15
h1 = sigmoid([ones(m, 1) X] * Theta1');
Error in ==> ex4 at 241
pred = predict(Theta1, Theta2, gi);
situation that does not occur when I test my program even with one random sample ofc the MNIST data; any help?
You could try something like this:
imfile = 'image.jpg';
im = double(rgb2gray(imread(imfile))); % double and convert to grayscale
im = imresize(im,[20,20]); % change to 20 by 20 dimension
im = im(:); % unroll matrix to vector
im = im./max(im);
Note the MNIST dataset is intended to be a good dataset to require minimal preprocessing and the images were actually originally black and white (bilevel) whereas you are using color image. Also they do normalisation and other preprocessing to make nice 28 by 28 image dataset, my brief snippet of code above is unlikely to be anywhere near as good as MNIST dataset and is just intended to attempt to fix your error.
Your specific error is likely because you don't use double().
You may also get further errors because your code needs right dimensions, which can be achieved using imresize.
More information on MNIST dataset here:
http://yann.lecun.com/exdb/mnist/

Average of dynamic row range

I have a table of rows which consist of zeros and numbers like this:
A B C D E F G H I J K L M N
0 0 0 4 3 1 0 1 0 2 0 0 0 0
0 1 0 1 4 0 0 0 0 0 1 0 0 0
9 5 7 9 10 7 2 3 6 4 4 0 1 0
I want to calculate an average of the numbers including zeros, but starting from the first nonzero value and put it into column after tables end. E.g. for the first row first value is 4, so average - 11/11; for the second - 7/13; the last one is 67/14.
How could I using excel formulas do this? Probably OFFSET with nested IF?
This still needs to be entered as an array formula (ctrl-shift-enter) but it isn't volatile:
=AVERAGE(INDEX(($A2:$O2),MATCH(TRUE,$A2:$O2<>0,0)):$O2)
or, depending on location:
=AVERAGE(INDEX(($A2:$O2);MATCH(TRUE;$A2:$O2<>0;0)):$O2)
The sum is the same no matter how many 0's you include, so all you need to worry about is what to divide it by, which you could determine using nested IFs, or take a cue from this: https://superuser.com/questions/671435/excel-formula-to-get-first-non-zero-value-in-row-and-return-column-header
Thank you, Scott Hunter, for good reference.
I solved the problem using a huge formula, and I think it's a bit awkward.
Here it is:
=AVERAGE(INDIRECT(CELL("address";INDEX(A2:O2;MATCH(TRUE;INDEX(A2:O2<>0;;);0)));TRUE):O2)

Resources