Related
Consider an array. What is a good way to permute its elements according to another array that gives the new positions of elements (without making a copy of the array first)?
For example
int a[]={37,43,5,10}; //array to permute
int b[]={3,1,4,2}; //new position of each element
so a should become
{43,10,37,5}
I naturally thought about making a copy of a and then re allocate its element in the new positions. But is there a way to do it without making a copy of the array a (i.e. a more simple way)?
Note: If possible the way to do it should not use particular C++ headers but only <iostream>
It can be done in O(n) time with O(1) extra memory, by handling the cycles of the permutation array one at a time.
Note: this approach is more complicated than needed for this particular setting (a and b are both int arrays), but it has some benefits:
it can handle arbitrary datatypes (e.g. the permuted array a can be an array of strings).
it can retain the original values in b, the permutation array.
Consider the initial example:
int a[] = {37, 43, 5, 10}; // array to permute
int b[] = { 3, 1, 4, 2}; // new position of each element
The array b indicates that we want to make the following chain of assignments:
a[1] <-- a[3] <-- a[4] <-- a[2] <-- a[1].
The problem is that at the last assignment, we don't anymore have access to a[1] (it has already been replaced to a[3]).
However, the original value of the starting element can be saved in an auxiliary variable, so that we use it when we close the cycle (it is guaranteed that when we close the cycle we will reach precisely the element that we have started from - otherwise some element would be reachable in multiple ways, i.e. we would have b[i] = b[j]), for some i != j).
In general, the permutation may contain multiple cycles. After a cycle is processed, we need to start with an element that had not yet been updated (i.e. it was not part of a cycle processed so far).
Thus, we need to know which elements were not processed so far.
A possible approach is to temporarily modify the permutation vector b in order to keep track of which elements were updated, e.g. negating the value at the corresponding position in b when updating an element in a. This has the advantage that at the end, we can iterate through all elements of b and restore the initial values (by negating all of them again).
Below is an implementation of the previous ideas.
int main() {
int a[] = {11, 22, 33, 44};
int b[] = { 2, 1, 4, 3};
int aux, crtIdx, nxtIdx;
int n = sizeof(a) / sizeof(a[0]);
for (int i = 0; i < n; i++) {
// check whether the i'th element
// was already processed
if (b[i] < 0) {
continue;
}
// start processing of a new cycle;
// backup the first value to aux
aux = a[i];
crtIdx = i;
nxtIdx = b[i] - 1;
// advance along the cycle until we reach
// again the first element
while (nxtIdx != i) {
a[crtIdx] = a[nxtIdx];
// use the b array to mark that the
// element at crtIdx was updated
b[crtIdx] = -b[crtIdx];
crtIdx = nxtIdx;
nxtIdx = b[nxtIdx] - 1;
}
// finalize the cycle using the aux variable
a[crtIdx] = aux;
b[crtIdx] = -b[crtIdx];
}
// restore the original values of b[i]
for (int i = 0; i < n; i++) {
b[i] = -b[i];
}
}
Note: although the code contains two nested loops, the time complexity is O(n). This can be seen by considering the fact that each element is updated exactly once (the outer loop is immediately continued if we reach an element that was already processed).
I'll show here the main steps performed by the algorithm, using this example:
a = {11, 22, 33, 44}
b = { 2, 1, 4, 3}
Step 1.
We look at the first element (please see the outer for loop over i from the code). The first element is not part of an already processed cycle, thus we start the processing of a new cycle. We do so by storing in aux the initial value of this element.
a = {11, 22, 33, 44}
b = { 2, 1, 4, 3}
aux = 11
Step 2.
We go along this cycle, update elements, mark them as updated (by negating the corresponding element in the b array), until we reach again the first element.
a = {22, 22, 33, 44}
b = {-2, 1, 4, 3}
aux = 11
Step 3.
We reached again the first element of the cycle, and need its initial value in order to update the last element of the cycle. This is where we use the auxiliary variable. In this way, the first cycle is completely processed.
a = {22, 11, 33, 44}
b = {-2, -1, 4, 3}
aux = 11
Step 4.
We continue the outer loop (the for over i). We see that the second element was already processed (because b[1] is negative), thus we don't start a new cycle here. We continue, and start a new cycle at the third element (which was not yet processed).
Now we can reuse the same aux variable to backup the first element of this cycle (we no longer need to hold the value from the first cycle, because that cycle was completely resolved).
a = {22, 11, 33, 44}
b = {-2, -1, 4, 3}
aux = 33
Step 5.
The processing of the second cycle is performed in a similar manner described in the previous steps, resulting in the end in this:
a = {22, 11, 44, 33}
b = {-2, -1, -4, -3}
aux = 33
Step 6.
The loop over i continues, and no un-processed element is found.
Now, that we know that all elements were processed, we can negate each element in b in order to restore the original values.
a = {22, 11, 44, 33}
b = { 2, 1, 4, 3}
The simplest answer is to copy a into b, destroying b as you go:
for (i = 0; i < B_SIZE; ++i):
b[i] = a[b[i] - 1];
Then, if you must, just copy b back to a:
for (i = 0; i < B_SIZE; ++i):
a[i] = b[i];
Since a and b are both int arrays, you're not using up any excess memory in doing so. You end with the correct values in a, without using any more memory than what was given to you. This isn't maximally efficient (though it is O(n)), but it is simplest to understand.
When you want to avoid copying an array, it generally means limiting yourself to swaps.
If we use swaps to sort b[], and use the same swaps for a[], then a[] will end up permuted according to the values of b[].
I'm going to step through the algorithm below. For simplicity, I start array counting at 1, although in C arrays count starting at 0. You'll have to adjust for that in your code.
a[]={37, 43, 5, 10} //array to permute
b[]={3, 1, 4, 2} //new position of each element
i = 1; b[i] = 3
swap(a[1], a[3]); a[] = {5, 43, 37, 10}
swap(b[1], b[3]); b[] = {4, 1, 3, 2}
i = 1; b[i] = 4
swap(a[1], a[4]); a[] = {10, 43, 37, 5}
swap(b[1], b[4]); b[] = {2, 1, 3, 4}
i = 1; b[i] = 2
swap(a[1], a[2]); a[] = {43, 10, 37, 5}
swap(b[1], b[2]); b[] = {1, 2, 3, 4}
i = 1; b[i] = 1
++i
i = 2; b[i] = 2
++i
i = 3; b[i] = 3
++i
i = 4; b[i] = 4
++i
i = 5; i > 4
DONE
Note how we step through b[] at the end there. Consider the case that b[]={2, 1, 4, 3}
a[] = {37, 43, 5, 10}
b[] = {2, 1, 4, 3}
i = 1; b[i] = 2
swap(a[1], a[2]); a[] = {43, 37, 5, 10}
swap(b[1], b[2]); b[] = {1, 2, 4, 3}
i = 1; b[i] = 1
++i
i = 2; b[i] = 2
++i
i = 3; b[i] = 4
swap(a[3], a[4]); a[] = {43, 37, 10, 5}
swap(b[3], b[4]); b[] = {1, 2, 3, 4}
i = 3; b[i] = 3
++i
i = 4; b[i] = 4
++i
i = 5; i > 4
DONE
With every swap, one element of the array ends up in the correct position, meaning we perform at most N swaps.
I've got a C-style array called board that contains some char's. I'm trying to create a std::array or std::vector (either would be fine, although std::array would be preferable) to store all the indices of board that are a certain value (in my case, 0).
This code I wrote is functional and works well:
std::vector<int> zeroes;
zeroes.reserve(16);
//board has 16 elements, so zeroes.size() will never be larger than 16.
//I used this reserve for speedup - the compiler doesn't require it.
for (int i = 0; i < 16; ++i)
{
if (board[i] == 0)
{
zeroes.push_back(i);
}
}
However, from past experience, whenever a std function exists that could replace part of my code, it is terser and hence stylistically preferred and also faster. My function seems like a fairly basic operation - I know there is a standard function* to access the index of an array that contains a value when that value only occurs once** in the array. So, is there a standard function to create an array of the indices that contain a value, assuming that more than one such index exists?
* Technically, two nested function calls: int x = std::distance(board, std::find(board, board + 16, 0));. See the accepted answer here.
** Well, it still works if more than one index with the desired value is present, but it returns only the first such index, which isn't very useful in my context.
Edit:
As one of the answers misunderstood the question, I'll clarify what I'm seeking. Let's say we have:
char board[16] = {0, 2, 0, 4,
2, 4, 8, 2,
0, 0, 8, 4,
2, 0, 0, 2};
Now, the indices which I'm looking for are {0, 2, 8, 9, 13, 14} because board[0] = 0, board[2] = 0, board[8] = 0, etc. and these are the only numbers which satisfy that property.
Here's a solution using std::iota and std::remove_if:
#include <algorithm>
#include <iostream>
int main () {
const std::size_t board_size = 16;
char board [board_size] = {
0, 2, 0, 4,
2, 4, 8, 2,
0, 0, 8, 4,
2, 0, 0, 2
};
// Initialize a zero-filled vector of the appropriate size.
std::vector<int> zeroes(board_size);
// Fill the vector with index values (0 through board_size - 1).
std::iota(zeroes.begin(), zeroes.end(), 0);
// Remove the index values that do not correspond to zero elements in the board.
zeroes.erase(std::remove_if(zeroes.begin(), zeroes.end(), [&board] (int i) {
return board[i] != 0;
}), zeroes.end());
// Output the resulting contents of the vector.
for (int i : zeroes) {
std::cout << i << std::endl;
}
}
Output of the program (demo):
0
2
8
9
13
14
Lets say i have:
int array[9][9]= {
{1 , 2 , 3 , 4, 5, 6, 7, 8, 9},
{10, 11, 12, 13, 14, 15, 16, 17, 18},
{19, 20, 21, 22, 23, 24, 25, 26, 27},
{28, 29, 30, 31, 32, 33, 34, 35, 36},
{37, 38, 39, 40, 41, 42, 43, 44, 45},
{46, 47, 48, 49, 50, 51, 52, 53, 54},
{55, 56, 57, 58, 59, 60, 61, 62, 63},
{64, 65, 66, 67, 68, 69, 70, 71, 72},
{73, 74, 75, 76, 77, 78, 79, 80, 81}
};
how can i only apply some function to the first row (value 1 to 9 ) or the first column only (like value 1 to 73). lets say i want to say index 0 to 9 shall all have value 0.
is it possible to save this range in a variable?
Try to do like this:
for (int i = 0; i<10; i++)
array[0][i] = 0;
There are no true multidimensional arrays in C.
In a true multidimensional array, all dimensions are on equal standing. Whatever you can do with rows, you can also do with columns.
This is not the case with C++. The third row of your array is just
array[3]
It's an array on its own in every regard. A range of rows, like any other range, can be represented as a (start, end) pair, e.g. make_pair(array[3], array[7]).
Nothingl like that can be done with columns. The third column, unlike the third row, is not an array, it's just a virtual collection of elements not sitting under any standard data structure umbrella.
The closest thing to a multidimensional array slices are custom iterators, such that ++i moves to either the next element to the right or to the next element below. While you're at it, consider moving away from C style arrays to STL style containers.
To isolate the rows of the array, you could take a reference to a row of the array:
int (&row)[9] = array[2];
For example the above line takes a reference to the 3rd row of the array.
Live Demo
For the columns, is more complicated.
Alternatevely, you could do the following construct that returns a vector of reference wrappers to either a column or a row of a 2D array.
// if flg == true you get row at idx else if flg == false you get column at idx
template<typename T, int N, int M>
std::vector<std::reference_wrapper<T>>
getRange(T (&arr)[N][M], std::size_t const idx, bool const flg = true) {
if(flg) {
return typename std::vector<std::reference_wrapper<T>>(std::begin(arr[idx]), std::end(arr[idx]));
} else {
typename std::vector<std::reference_wrapper<T>> out;
out.reserve(N);
for(int i(0); i < N; ++i) out.push_back(arr[i][idx]);
return out;
}
}
Live Demo
For rows it's easy, as you can pass them like:
void foo(int * row, int cols) {
for (int col = 0; col < cols; ++col) {
int * x = row + col;
}
}
...
foo(array[3], 9);
...
For columns it's more difficult but you can thought about every column as something that have specific offset in the array:
void boo(int * col, int rows, int cols) {
for (int row = 0; row < rows; ++row) {
int * x = col + row * cols;
}
}
....
// process fourth column:
boo(array[0]+4, 9, 9);
Of course using sizeof instead of '9' and C++ vectors/array instead of C-style int[][] will make life more easy and code more readable and supportable.
Another way is to use boost::matrix e.g.:
using namespace boost::numeric::ublas;
matrix<double> m(9, 9);
matrix_row<matrix <double> > row(m, 5);
matrix_column<matrix <double> > col(m, 4);
You can do it by specifying indices (start and end range) with your function and mention whether it should be applied on row or column. Since you are using plain C style array it's trickier to deal with pointers. I recommend you to use vectors and pairs (for ranges).
An example for C style array
void some_function(int array[][9], bool row_or_column, size_t major, size_t start, size_t end){
if (row_or_column = true) {
for (int i = start; i < end; i++) {
cout << array[major][i]; //perform your operation on row
}
}
else {
for (int i = start; i < end; i++) {
cout << array[i][major]; //perform your operation on column
}
}
}
Set row_or_column as either true for row or false for column, major should specify the column number or row number and the ranges in start and end. Note: end is exclusive
For processing second row with range start = 0 and end = 5 i.e 10 to 14
some_function(array, true, 1, 0, 5)
For processing second column with range start = 0 and end = 5 i.e 2 to 38
some_function(array, false, 1, 0, 5)
For example, how can I move the 1st, 5th and 10th elements in array A to a new three-elements array B without assigning separately for three times?
In C, just declare and initialize a new array with the selected elements of your array. No assignment needed.
int main(void)
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int b[3] = {a[0], a[4], a[9]};
return 0;
}
Remember that initializers for arrays with automatic storage duration does not have to be constants.
Just do the three assignments! Why do you avoid it?
int ar1[10], ar2[10];
ar2[0] = ar1[0];
ar2[4] = ar1[4];
ar2[9] = ar1[9];
However, if you have lots of indices to move, perhaps you need another way.
I suggest this:
int ar1[1000], ar2[1000];
int indices[] = { 1, 3, 54, 6, 23, 35, 9, 42, 44, 995, 722, .... };
for (int i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
{
ar2[i] = ar1[i];
}
I stuck at one point and need some help.
I have a STL vector with the following values:
[1, 17, 2, 18, 3, 19, 1, 17, 2, 18, 3, 19, 1, 17, 2, 18, 3, 19].
note that first six values in a vector (i.e. 1, 17, 2, 18, 3, 19 ) can be considered as one block. So this vector has 3 blocks each with the values as described above.
Now, I want to organize this vector in a following way:
[1, 17, 1, 17, 1, 17, 2, 18, 2, 18, 2, 18, 3, 19, 3, 19, 3, 19]
.
So essentially I am picking first two values (i.e. 1, 17) from each block first and store them sequentially 3 times (basically # of blocks which in this case is 3). I then go on to pick next two values (i.e. 2, 18) and continue.
How do I achieve this..?
Any help will be greatly appreciated.
Thanks
Sound quite easy once you figure out the exact mapping. So external loop is the number of chunks in every block since that's the number of final groups, middle loop goes over each original block while inner loop just goes through every element of a chunk. Final result should be something like (untested):
std::vector organized;
organized.reserve(data.size());
const int blockSize = 6;
const int subBlockSize = 2;
assert(data.size()%blockCount == 0 && blockSize%subBlockSize == 0);
const int blockCount = data.size()/blockSize;
const int subBlockCount = blockSize/subBlockSize;
for (int i = 0; i < subBlockCount; ++i)
for (int j = 0; j < blockCount; ++j)
for (int k = 0; k < subBlockSize; ++k)
organized.push_back(subBlockSize*i + blockSize*j + k);
Just create a function shuffle(i) that takes an index into the new array, and returns an index from the original array:
#include <iostream>
#include <cstdlib>
using namespace std;
int list[] = { 1, 17, 2, 18, 3, 19, 1, 17, 2, 18, 3, 19, 1, 17, 2, 18, 3, 19 };
int shuffle( int i )
{
div_t a = div( i, 6 );
div_t b = div( a.rem, 2 );
return 2*a.quot + 6*b.quot + b.rem;
}
int main()
{
for( int i=0 ; i<18 ; ++i ) cout << list[shuffle(i)] << ' ';
cout << endl;
return 0;
}
This outputs:
1 17 1 17 1 17 2 18 2 18 2 18 3 19 3 19 3 19
Just allocate the new vector, and fill it from the old one:
new_vector[i] = list[shuffle(i)];