C++, Sorting Separate Arrays Simultaneously [duplicate] - c++

This question already has answers here:
Sorting zipped (locked) containers in C++ using boost or the STL
(5 answers)
Closed 8 years ago.
Consider the case where “rowPtr”, “colInd” and “values” in a struct are dynamically allocated with same number of elements. In this scenario, what is the fastest way (without copying if possible!!) to sort elements of colInd so that rowPtr and value elements are swapped or change positions based on how elements of colInd change positions.
struct csr
{
int rows;
int cols;
int nzmax;
int *rowPtr;
int *colInd;
double *values;
};
// A simple example without a struct. Just based on arrays
double values[10] = {0.2135, 0.8648, 7, 0.3446, 0.1429, 6, 0.02311, 0.3599, 0.0866, 8 };
int rowPtr[10] = { 0, 3, 6, 10, 2 -1, 24, -4, 1, 11 };
int colInd[10] = { 0, 2, 4, 1, 2, 3, 0, 1, 2, 4 };
// sort colInd and simultaneously change positions in rowPtr and values
//After sorting
Values = {0.214, 0.023, 0.345, 0.360, 0.865, 0.143, 0.087, 6.0};
rowPtr = {0, 24, 10, -4, 3, 2, 1, -1};
colInd = {0, 0, 1, 1, 2, 2, 2, 3};

I suggest putting the three arrays into an array of struct and sorting the array of struct.
struct csr_data
{
int rowPtr;
int colInd;
double value;
};
and
struct csr
{
int rows;
int cols;
int nzmax;
csr_data* data_array;
};
You can sort an array of csr_data using any of the three member variables. When they are sorted, all elements of csr_data will be rearranged regardless of which member you use to sort the data by.

Related

get length of multidimensional array with different length in c++?

I have a multidimensional array and i'm trying to get the length of each column. But it's returning 20 for all of them.
int buttons[16][5] = {{0, 4, 1},{1, 0, 2, 5},{2, 1, 3, 6},{3, 2, 7},{4,0,5,8},{5,1,4,6,9},{6,2,5,7,10},{7,3,6,11},{8,4,9,12},{9,5,8,10,13},{10,6,9,11,14},{11,7,10,15},{12,8,13},{13,9,12,14},{14,10,13,15},{15,11,14}};
sizeof(buttons[0]);
You are declaring an C-style array where each element is an array of 5 int. Therefore, with sizeof(buttons[0]), you are getting the size of 5 ints. Usually, ints have a size of 4 bytes, hence you get 20. Only apparently has buttons[0] 3 elements: in fact, in your code, you initialize only the first 3 elements of buttons[0].
If you want a multidimensional array, where each "column" has different size, you should better use std::vector which can hold array of variable size. Then size() gives you the actual number of element.
Example code:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> buttons[16] = {{0, 4, 1},{1, 0, 2, 5},{2, 1, 3, 6},{3, 2, 7},{4,0,5,8},{5,1,4,6,9},{6,2,5,7,10},{7,3,6,11},{8,4,9,12},{9,5,8,10,13},{10,6,9,11,14},{11,7,10,15},{12,8,13},{13,9,12,14},{14,10,13,15},{15,11,14}};
std::cout << buttons[0].size();
}
Even better, you could use a vector of vector:
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int>> buttons = {{0, 4, 1},{1, 0, 2, 5},{2, 1, 3, 6},{3, 2, 7},{4,0,5,8},{5,1,4,6,9},{6,2,5,7,10},{7,3,6,11},{8,4,9,12},{9,5,8,10,13},{10,6,9,11,14},{11,7,10,15},{12,8,13},{13,9,12,14},{14,10,13,15},{15,11,14}};
std::cout << buttons[0].size();
}
You can't do that with arrays. You can do that with vectors:
vector<vector<int> > buttons = ...;
for (auto const& button : buttons) cout << button.size() << '\n';

Update positions in subset of sorted vector

I am working on a problem in C++ that involves calculations on arrays of objects sorted along different attributes. Suppose I have an array of 5 objects with 3 different attributes (A, B, and C), and I sort the array according to each attribute individually. This gives me three arrays that tell me for each object where its position would be if I were to sort them along the corresponding attribute.
std::vector<int> A_Order = { 1, 3, 0, 2, 4 };
std::vector<int> B_Order = { 2, 4, 3, 1, 0 };
std::vector<int> C_Order = { 0, 2, 4, 3, 1 };
Now I want to split the objects into 2 subsets, always picking a position N in one of the orderings, where all objects at position x <= N go into the first subset, and all x > N go into the next subset. If I do this on attribute A at N = 2, I get the following:
std::vector<int> A_OrderSub0 = { 1, 0, 2 };
std::vector<int> B_OrderSub0 = { 2, 3, 1 };
std::vector<int> C_OrderSub0 = { 0, 4, 3 };
std::vector<int> A_OrderSub1 = { 3, 4 };
std::vector<int> B_OrderSub1 = { 4, 0 };
std::vector<int> C_OrderSub1 = { 2, 1 };
To perform the next iteration of calculations efficiently, I once again need the subsets to be ordered along the attributes and get the resulting positions (in the example above, I need B_OrderSub1 = { 4, 0 } to become B_OrderSub1 = { 1, 0 }). What is the most efficient way for me to reuse the "global positions", which I only have to get once at the start, to then get the "locally ordered positions" for the objects each time I split them into subsets?

Is there any efficient way to do "shuffling" of vector

I have a large size unsorted array, each element contains a unique integer number,
std::vector<size_t> Vec= {1, 5, 3, 7, 18...}
I need to shuffle the vector in such a way, given a specific number, look for it and then swap it with the number in a new desired position. This swapping needs to be done many times.
Currently I use anther vector PositionLookup to remember&update the positions after every swapping. And I'm wondering is there any more efficient way/data structure that can help do this?
Current solution,
//look for a specific number "key" and swap it with the number in desired position "position_new"
void shuffle(key, position_new)
{
size_t temp = Vec[position_new]; // main vector
size_t position_old = PositionLookup[key]; // auxiliary vector
Vec[position_old] = temp;
PositionLookup[temp] = position_old;
Vec[position_new] = key;
PositionLookup[key] = position_new;
}
A couple microoptimizations to start with: If the vector has a fixed size, you could use a std::array or a plain C array instead of a std::vector. You can also use the most compact integer type that can hold all the values in the vector (e.g. std::int8_t/signed char for values in the interval [-128,127], std::uint16_t/unsigned short for values in the interval [0,65535], etc.)
The bigger optimization opportunity: Since the values themselves never change, only their indexes, you only need to keep track of the indexes.
Suppose for simplicity's sake the values are 0 through 4. In that case we can have an array
std::array<std::int8_t, 5> indices{{2, 3, 1, 4, 0}};
Which represents the index of its indices in an imaginary array, here 4, 2, 0, 1, 3. Or in other words indices[0] is 2, which is the index of 0 in the imaginary array.
Then to swap the positions of 0 and 1 you only need to do
std::swap(indices[0], indices[1]);
Which makes the indices array 3, 2, 1, 4, 0 and the imaginary array 4, 2, 1, 0, 3.
Of course the imaginary array's values might not be the same as its indices.
If the (sorted) values are something like -2, -1, 0, 1, 2 you could obtain the value from the index by adding 2, or if they're 0, 3, 6, 9, 12 you could divide by 3, or if they're -5, -3, -1, 1, 3 you could add 5 then divide by 2, etc.
If the values don't follow a defined pattern, you can create a second array to look up the value that goes with an index.
std::array<std::int8_t, 5> indices{{2, 3, 1, 4, 0}};
constexpr std::array<std::int8_t, 5> Values{{1, 3, 5, 7, 18}};
// Imaginary array before: 18, 5, 1, 3, 7
std::swap(indices[0], indices[1]);
// Imaginary array after: 18, 5, 3, 1, 7
const auto index_to_value = [&](decltype(indices)::value_type idx) noexcept {
return Values[idx];
};
const auto value_to_index = [&](decltype(Values)::value_type val) noexcept {
return std::lower_bound(Values.begin(), Values.end(), val)
- Values.begin();
};
It's the same thing if the values aren't known until runtime, just obviously the values lookup table can't be const or constexpr.
std::array<std::int8_t, 5> indices{{2, 3, 1, 4, 0}};
std::array<std::int8_t, 5> values; // Not known yet at compile-time
// ... set `values` at runtime to e.g. -93, -77, -64, 8, 56
// Imaginary array before: 56, -64, -93, -77, 8
std::swap(indices[0], indices[1]);
// Imaginary array after: 56, -64, -77, -93, 8
const auto index_to_value = [&](decltype(indices)::value_type idx) noexcept {
return values[idx];
};
const auto value_to_index = [&](decltype(values)::value_type val) noexcept {
return std::lower_bound(values.cbegin(), values.cend(), val)
- values.cbegin();
};

Standard library function to create array of indices whose corresponding value is a given number

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

In C and C++, how to move some elements in an array into a new array?

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];
}