Related
This is another question (I posted one other one, go look!) from my computer science final study guide. I am not sure how to get the value of x[2] or x[5] without a computer (No computers used during the exam). Can someone please explain how to figure out these values just by reading the code? Thanks!
int x[SIZE] = {5, 3, 4, 5, 2, 4, 3, 5, 1, 2};
int i;
int j;
for(i = 0; i < SIZE / 2; i++)
{
for(j = x[i]; j < SIZE; j++)
{
x[j]++;
}
}
printf("x[2] = %d\n", x[2]);
printf("x[5] = %d\n", x[5]);
Firstly, the array is
int x[SIZE] = {5, 3, 4, 5, 2, 4, 3, 5, 1, 2};
and SIZE is 10 ( or I'll assume it is 10 ).
The outer for loop is
for(i = 0; i < SIZE / 2; i++)
so it iterates from i=0 to i=4.
Now, let's look at the inner for loop
for(j = x[i]; j < SIZE; j++)
{
x[j]++;
}
The value assigned for j is x[i].
Firstly, at i=0, the value of j would be x[0] which is 5. So, the inner for loop executes from j=5 to j=9. In the loop, it does x[j]++, that is, x[5]++, which is 4++, which gives 5. Now on the next iteration of the inner loop, j=6, and x[6]++, so 3++, hence gives 4. So, all the values of the array from x[5] to x[9] are incremented once.
So, the array now becomes
5 3 4 5 2 5 4 6 2 3
If you look at this pattern, you will notice that to for the value of x[2] to change, j must become 2 and for that x[i] must be 2, but looking at the the way the loop will progress, you can see that the values of x[0], x[1] and x[2] will not change. So, x[2] will remain as 4.
Now, moving on to the next iteration of the outer loop, i=1, so j=x[1], so from j=3 to j=9, increment the values of x[j], so the array becomes
5 3 4 6 3 6 5 7 3 4
For the next iteration at i=2, the inner loop iterates from j=4 to j=9, so the array becomes
5 3 4 6 4 7 6 8 4 5
For the next iteration at i=3, the inner loop iterates from j=6 to j=9, and hence the array becomes
5 3 4 6 4 7 7 9 5 6
And now, for the last iteration of the outer loop, at i=4 , the inner loop iterates from j=4 to j=9, and the array becomes
5 3 4 6 5 8 8 10 6 7
So, the output of the program would be
x[2] = 4
x[5] = 8
This is how to interpret programs like these without a compiler.
x is an array. An array has a group of elements in it. The elements are indexed by a number. In C the index starts from 0. So the first element has an index 0, second one's index is 1 and so on.
So if you are looking for x[2] that means the element at index 2 or position 3 which is 4 in the given code. But wait, there is a nested loop between the array definition and the printing of that value. This means that the original values in the array changes. So, you need to figure out what changes the loop makes to the array by manually iterating through it on a piece of paper. I'll leave that part to you.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
The following code is an algorithm for searching for the maximum occurrence of an element in an array. This solution assumes that an element ranges from 0 to n-1.
void MaxRepetitions( int A[], int n ) {
int i=0; max=0, maxIndex;
for(i=0, i<n, i++)
A[A[i]%n] +=n;
for( i=0, i<n, i++)
if (A[i]/n > max) {
max = A[i]/n;
maxIndex=i;
}
return maxIndex;
}
How is A[A[i]%n] +=n; expanded?
Is A[A[i]%n] = A[A[i]%n] + n correct?
--
Edit
For the example where A = [2, 4, 7, 5, 4, 11], where n=6
A[0]%n = 2
A[1]%n = 4
A[2]%n = 1
A[3]%n = 5
A[4]%n = 4
A[5]%n = 5
After this loop:
for(i=0, i<n, i++)
A[A[i]%n] = A[A[i]%n] + n;
Iteration 1:
A[A[0]%n] = A[A[0]%n] + 6 --> A[2] = A[2] + 6 --> A[2] = 13
The array is now: A = [2, 4, 13, 5, 4, 11]
Iteration 2:
A[A[1]%n] = A[A[1]%n] + 6 --> A[4] = A[4] + 6 --> A[4] = 10
The array is now: A = [2, 4, 13, 5, 10, 11]
Iteration 3:
A[A[2]%n] = A[A[2]%n] + 6 --> A[1] = A[1] + 6 --> A[1] = 10
The array is now: A = [2, 10, 13, 5, 10, 11]
Iteration 4:
A[A[3]%n] = A[A[3]%n] + 6 --> A[5] = A[5] + 6 --> A[5] = 17
The array is now: A = [2, 10, 13, 5, 10, 17]
Iteration 5:
A[4] now is 10
A[A[4]%n] = A[A[4]%n] + 6 --> A[4] = A[4] + 6 --> A[4] = 16
The array is now: A = [2, 10, 13, 5, 16, 17]
Iteration 6:
A[5] now is 17
A[A[5]%n] = A[A[5]%n] + 6 --> A[5] = A[5] + 6 --> A[5] = 23
The array is now: A = [2, 10, 13, 5, 16, 23]
Now, once the second loop runs, A[i]/n for each of the elements is: A [0, 1, 2, 0, 2, 3 ]
It looks like this algorithm will choose 11 as the element with most occurrences which isn't true. Any help?
As others have said, <anything> += <value> is equivalent to <anything> = <anything> + <value> except that <anything> is evaluated only once.
Your analysis of the running of the algorithm is correct, but the problem is that the input violates the stated constraint that all elements are between 0 and n-1. In effect, since 11 % 6 = 5, the answer produced by the algorithm isn't completely wrong (modulo 6, the value 5 occurs the same number of times as the value 4). However, there is a further problem in that because the input constraint is violated, the counts are off for reasons that I explain in a comment below.
The best way to understand how this works is to look at another algorithm which, while seemingly quite different, is actually the same thing. This other algorithm is:
Allocate a separate array C[n]. (C for "count".)
Loop through each element A[i] of A and set C[A[i]] += 1. It's not too hard to see that, since each A[i] is between 0 and n-1, when this step finishes, C[j] for any j will be the number of times that the value j occurs among all the A[i].
Thus, the position of the largest element of C is the most frequently occurring value in A (with ties being resolved arbitrarily). Simply loop through C to find where this occurs and return the result.
Now the algorithm you posted is exactly that, but cleverly making use of two facts, both of which rely on the original values of A[i] being between 0 and n-1:
The value of A[i]%n will be exactly equal to the original value of A[i] regardless of how many times n has been added to A[i].
The value of A[i]/n will be exactly equal to the number of times n has been added to A[i], regardless of the original value of A[i].
So if we modify the second algorithm by adding n instead of 1, and by using %n and /n as is done in your posted algorithm, we can make A serve for both holding the original values and for holding the counts.
This:
A[A[i]%n] +=n
Is expanded to be equivalent to this:
A[A[i]%n] = A[A[i]%n] + n
Except that side-effects are only evaluated once. In other words, if the left expression had employed operators with side-effects like ++ and --, then these side-effects would only occur once, contrary to what had happened if you had actually written out the whole x = x + y expression, where side-effects in x would be evaluated twice.
A[A[i]%n] +=n
A[i] : value contained in array A at position i
A[i]%n : remainder of dividing this value by n (used to not allow this index go beyond the size of A
A[A[i]%n] : the value contained in that new position
A[A[i]%n] += n : add n to this value
Numerical example :
A[3] = {7, 10, 24}
n = 3
i = 0
A[A[0]%3] = A[7%3] // 7 = 2*3 + 1
= A[1]
= 10
add 3 ==> A[1] = 13
i = 1
A[A[1]%3] = A[13%3] // 13 = 4*3 +1
= A[1]
= 13
add 3 ==> A[1] = 16
i = 2
A[A[2]%3] = A[24%3] // 24 = 8*3 + 0
= A[1]
= 7
add 3 ==> A[1] = 10
In C
we have
int B[2][3] = { {1, 2, 3}, {4, 5, 6} };
It is stored in memory as
1 2 3 4 5 6
int A[6]={1,2,3,4,5,6};
It is also stored in memory as
1 2 3 4 5 6
we can access A[6] by A[i] where i=0,2,3..
but we cannot access B[2][3] by B[i ] where i=0,1,2..
I know there are other techniques by which we can access elements of multidimentional arrays
but we cannot access multidimentional arrays like single dimentional arrays why?
You can interpret them:
int B[2][3] = { {1, 2, 3}, {4, 5, 6} };
int* b = ( void* )B ;
for( int i = 0 ; i < 6 ; i++ )
printf("%d " , b[i] ) ;
The same goes for single arrays:
int A[6]={1,2,3,4,5,6};
int (*a)[3] ;
a = ( void* )A ;
for( int i = 0 ; i < 2 ; i++ )
for( int j = 0 ; j < 3 ; j++ )
printf("%d " , a[i][j] ) ;
You can access using another pointer to the array as below,
#include <stdio.h>
int main()
{
int i;
int a[2][3] = {{1,2,3}, {4,5,6}};
int *b = (int *)a;
for (i = 0; i < 6; i++)
printf("%d\n", b[i]);
return 0;
}
It has, amongst others, to do with the types of what you access.
B is a int[2][3]. That means, it has 6× the size of an int and consists of 2 successive int[3].
If you do [i], i being an integer, you get away the first level of indexing. That will give you an expression of type int[3], i. e. an array of 3 ints. That is not the same as an int and needs further indexing.
But there is another solution: dereferencing B with [0] gives you the first array. While this is limited in length, you can use it to access the whole array. So you can achieve your goal with B[0][5].
As said, B is a int[2][3], meaning that it is an array of 2 arrays of 3 ints. In memory, that looks like
offs 0 offs 1 offs 2 offs 3 offs 4 offs 5
B[0][0] B[0][1] B[0][2] B[1][0] B[1][1] B[1][2]
======================= =======================
B[0] B[1]
===============================================
B
B[0] is a 1D-array and as such degrades into a pointer as well. It points to the first element as well, but has a different type. So B[0] is of type int[2] and cannot be used as an int at the same time.
If I consider B[1], it even has a different address. See above how B[1] means the 2nd half of all data. B[0] and B[1] both have 3 times the size of an integer, meaning that the address of B[1] is 3*sizeof int positions away from B[0].
B[0] is, as said, the first array shown above. It degrades into a pointer to its first element (to B[0][0]) under most circumstances. A pointer, OTOH, can be accessed like an array: B[0][0] points to the first element, B[0][1] to the 2nd, and so on.
You are allowed to access the whole big array using this pointer, so you can go up to B[0][5]. Accessing B[0][6] is undefined behaviour in this case, meaning that you access something completely different - or even an area you aren't even allowed to read.
That is how arrays work. Making them work the way you intend to at the same time wouldn't work (how should it?).
If you want to learn more about pointers, have a look at a good C tutorial or book.
There are lots of recursion questions and I basically understand some simple recursion algorithm such as sum of array elements. However, my friend gave me this code which reverses an array:
void r(int a[], int s)
{
if(s <=2 ) return;
int t = a[0];
a[0] = a[s-1];
a[s-1] = t;
r(&a[1], s-2); // this line confused me, why &a[1]
}
I know how to reverse an array using a normal for loop. But this code really confused me about recursion.
Can anyone explain the above line of code?
It is equvalent to
void r(int *arr, size_t len)
{
for ( ; len >= 2; arr+=1,len-=2 ) {
int t = arr[0];
arr[0] = arr[len-1];
arr[len-1] = t;
}
}
, where the recursive call is replaced by the loop. Ihe "increment" part of the loop (arr+=1,len-=2) is exactly the same as the parameters for the recursive call; the end condition (len >= 2) is equivalent to the recursion stopper (which was wrong in the original).
The idea behind this algorithm is at each step:
-: to swap the last a[s-1] and first a[0] elements of the array:
int t = a[0];
a[0] = a[s-1];
a[s-1] = t;
-: and to swap the middle recursively:
r(&a[1], s-2);
To understand the syntax, keep in mind that &a[n] is address of the n+1th element of the given array. If you have int *b = &a[1], then b[0] == a[1], b[1] == a[2], etc.
So:
&a[1] refers to an array starting at the second element of array a.
s - 2 means that the length of the array you pass recursively is shorter by 2 elements.
If you have an array [1 2 3 4 5 6 7 8 9 10], here's what happens as the recursion progresses:
[1 2 3 4 5 6 7 8 9 10] // r(&a[0], 10)
10 [2 3 4 5 6 7 8 9] 1 // r(&a[1], 8
10 9 [3 4 5 6 7 8] 2 1 // r(&(&a[1])[1], 6)
10 9 8 [4 5 6 7] 3 2 1 // r(&(&(&a[1])[1])[1], 4)
10 9 8 7 [5 6] 4 3 2 1 // r(&(&(&(&a[1])[1])[1])[1], 2)
Cool thing is that this analysis shows us that the terminating condtion s <= 2 is wrong: the innermost 2 elements in an even-sized array will never get swapped. It should be changed to s < 2.
Simplified Crazy walk trough;
void reverse(int a[], int s)
{
int temp; /* temporary value */
if (s <= 2) return; /* trigger done */
t = a[0]; /* temp = first index of a */
a[0] = a[s - 1]; /* a[0] = a[end - 1] (end including \0) */
a[s - 1] = t; /* a[end - 1] = temp */
r(&a[1], s - 2); /* pass address of a[1] and end - 2 */
}
Given the char array "ABCDEFG"
Simplified memory table could be:
Address Value
7 A
8 B
9 C
a D
b E
c F
d G
/* Or as used here: */
789abcd <- Simplified memory address
ABCDEFG
We get; main() calls reverse(ABCDEFG, 7)
List 1
Address ref. to A are pushed on to the stack (A{BCDEFG})
7 are pushed on to the stack
return address for caller is pushed onto the stack
etc.
function called
And something like
#::::::::::::::::::::::::::::::::::::::::::::::::::::
reverse(ABCDEFG, 7); # Push to STACK 0xB (As List 1)
#====================================================
789abcd <- Memory address.
ABCDEFG <- Values.
0123456 <- Indexes for a in recursion 1.
if (7 <= 2) return;
temp = A
+ .
a[0] = a[6] => ABCDEFG = GBCDEFG
+
a[6] = temp => GBCDEFG = GBCDEFA
reverse(BCDEFA, 5); # Push to STACK 0xC (As in List 1)
#====================================================
7 89abcd <- Memory addresses.
[G]BCDEFA <- Values
012345 <- Indexes for a in recursion 2.
if (5 <= 2) return;
temp = B
+ .
a[0] = a[4] => BCDEFA = FCDEFA
+
a[4] = temp => FCDEFA = FCDEBA
reverse(CDEBA, 3); # Push to STACK 0xD (As in List 1)
#====================================================
78 9abcd <- Memory addresses.
[GF]CDEBA <- Values.
01234 <- indexes for a in recursion 3.
if (3 <= 2) return;
temp = C
+ .
a[0] = a[2] => CDEBA = EDEBA
+
a[2] = temp => EDEBA = EDCBA
reverse(DCBA, 1); # Push to STACK 0xE (As in List 1)
#====================================================
789 abcd <- Memory addresses.
[GFE]DCBA <- Values.
0123 <- Indexes for a in recursion 4.
if (1 <= 2) return; YES!
#:::: roll back stack ::::
Pop STACK 0xE
Pop STACK 0xD
Pop STACK 0xC
Pop STACK 0xB
We are back in main() and memory region 789abcd has
been altered from ABCDEFG to GFEDCBA.
The important thing to realize is that a is a pointer to the first element of the array, so a is the same as &a[0]. &a[1] is a pointer to the second element of the array. So if you call the function with &a[1] as its argument, it works on the subarray that starts with the second element.
&a[1] is equivalent to a + 1, i.e. a pointer to the second element of the array. The function call reverses the "middle" s-2 elements of the array.
The function has to be called with:
A pointer to the first element of the array. In C it can be referenced by using the name of the array.
The size of the array.
The first 'if' checks that the array has as least two elements. Next, what the function does is to exchange the position of the first and the last element of the array.
The recursive call changes the bounds at which the next step has to work. It increments the beginning of the array by one position, and also decreases the end of the array by one position; since these two elements have been reversed in this iteration.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Zero sum SubArray
An array contains both positive and negative elements, find the
subarray whose sum equals 0.
This is an interview question.
Unfortunately, I cannot read the accepted answer to this question, so I am asking it again: how to find the minimal integer subarray with zero sum?
Note, this is not a "zero subset problem". The obvious brute-force solution is O(N^2) (loop over all subarrays). Can we solve it in O(N)?
This algorithm will find them all, you can easily modify it to find the minimal subarray.
Given an int[] input array, you can create an int[] tmp array where tmp[i] = tmp[i - 1] + input[i]; so that at each element of tmp will store the sum of the input up to that element.
Now if you check tmp, you'll notice that there might be values that are equal to each other. Let's say that this values are at indexes j an k with j < k, then the subarray with sum 0 will be from index j + 1 to k. NOTE: if j + 1 == k, then k is 0 and that's it! ;)
NOTE: The algorithm should consider a virtual tmp[-1] = 0;
The implementation can be done in different ways including using a HashMap as suggested by BrokenGlass but be careful with the special case in the NOTE above.
Example:
int[] input = {4, 6, 3, -9, -5, 1, 3, 0, 2}
int[] tmp = {4, 10, 13, 4, -1, 0, 3, 3, 5}
Note the value 4 in tmp at index 0 and 3 ==> sum tmp 1 to 3 = 0, length (3 - 1) + 1 = 4
Note the value 0 in tmp at index 5 ==> sum tmp 0 to 5 = 0, length (5 - 0) + 1 = 6
Note the value 3 in tmp at index 6 and 7 ==> sum tmp 7 to 7 = 0, length (7 - 7) + 1 = 1
An array contains both positive and negative elements, find the
subarray whose sum equals 0.
Yes that can be done in O(n). If the sum of the elements within a subarray equals zero that means the sum of elements up to the first element before the sub array is the same as the sum of elements up to the last element in the subarray.
Go through the array and for each element K put the sum up to K and the index K in a hashtable, if the sum up to the current element exists already check the index of that element and the current element, if the delta is lower than the minimum subarray length, update the minimum. Update the hashtable with (sum, current index K).