Arranging by indexes vector - c++

I have two vectors: a vector and index vector. How can I make the vector be arranged by the indexes vector? Like:
Indexes 5 0 2 1 3 4
Values a b c d e f
Values after operation b d c e f a
The indexes vector will always contain the range [0, n) and each index only once.
I need this operation to be done in place because the code is going to be run on a device with low memory.
How can I do this in c++? I can use c++11

Since you know that your index array is a permutation of [0, N), you can do this in linear time and in-place (plus one temporary) by working cycle-by-cycle. Something like this:
size_t indices[N];
data_t values[N];
for (size_t pos = 0; pos < N; ++pos) // \
{ // } this loops _over_ cycles
if (indices[pos] == pos) continue; // /
size_t i = pos;
const data_t tmp = values[pos];
while (true) // --> this loops _through_ one cycle
{
const size_t next = indices[i];
indices[i] = i;
values[i] = values[next];
if (next == pos) break;
i = next;
}
values[i] = tmp;
}
This implementation has the advantage over using swap each time that we only need to use the temporary variable once per cycle.
If the data type is move-only, this still works if all the assignments are surrounded by std::move().

std::vector<int> indices = { 5, 0, 2, 1, 3, 4};
std::vector<char> values = {'a', 'b', 'c', 'd', 'e', 'f'};
for(size_t n = 0; n < indices.size(); ++n)
{
while(indices[n] != n)
{
std::swap(values[n], values[indices[n]]);
std::swap(indices[n], indices[indices[n]]);
}
}
EDIT:
I think this should be O(n), anyone disagree?

for(int i=0;i<=indexes.size();++i)
for(int j=i+1;j<=indexes.size();++j)
if(indexes[i] > indexes[j] )
swap(indexes[i],indexes[j]),
swap(values[i],values[j]);
It's O(N²) complexity, but should work fine on small number values.
You can also pass a comparison function to the C++ STL sort function if you want O(N*logN)

You can just sort the vector, your comparison operation should compare the indices. Of course, when moving the data around, you have to move the indices, too.
At the end, your indices will be just 0, 1, ... (n-1), and the data will be at the corresponding places.
As implementation note: you can store the values and indices together in a structure:
struct SortEntry
{
Data value;
size_t index;
};
and define the comparison operator to look only at indices:
bool operator< (const SortEntry& lhs, const SortEntry& rhs)
{
return lhs.index < rhs.index;
}

This solution runs in O(n) time:
int tmp;
for(int i = 0; i < n; i++)
while(indexes[i] != i){
swap(values[i], values[indexes[i]]);
tmp = indexes[i];
swap(indexes[i], indexes[tmp]);
}

This will run in O(n) time without any error.Check it on ideone
int main(int argc, char *argv[])
{
int indexes[6]={2,3,5,1,0,4};
char values[6]={'a','b','c','d','e','f'};
int result[sizeof(indexes)/4]; //creating array of size indexes or values
int a,i;
for( i=0;i<(sizeof(indexes)/4);i++)
{
a=indexes[i]; //saving the index value at i of array indexes
result[a]=values[i]; //saving the result in result array
}
for ( i=0;i<(sizeof(indexes)/4);i++)
printf("%c",result[i]); //printing the result
system("PAUSE");
return 0;
}

Related

How to efficiently permute an array in-place (using std::swap)

How can I apply a permutation in-place? My permutations are effectively size_t[] where perm[i] represents the target index for an input index i.
I know how to apply a permutation if I have an input and output array:
struct Permutation {
std::vector<size_t> perm;
template <typename T>
void apply(const T in[], T out[]) const
{
for (size_t i = 0; i < size(); ++i) {
out[i] = std::move(in[perm[i]]);
}
}
}
However, I would like to do this with only one array, similar to how std::sort works, so just using std::swap. My idea so far is:
struct Permutation {
std::vector<size_t> perm;
template <typename T>
void apply(T data[]) const
{
for (size_t i = 0; i < size(); ++i) {
std::swap(data[i], data[perm[i]]);
}
}
}
But this wouldn't work. For example:
Permutation perm = {2, 1, 0};
char data[] {'a', 'b', 'c'};
perm.apply(data);
// because I swap indices 0 and 2 twice, I end up with the input array
data == {'a', 'b', 'c'};
So how do I correctly permute an array in-place? It is okay if additional memory is allocated, as long as this happens in a pre-computation step when the Permutation is constructed. I want the in-place permutation to happen fast and from the looks of it, demanding that no additional memory is allocated at all will lead to some severe performance sacrifices.
I am specifically referencing Algorithm to apply permutation in constant memory space, where all of the provided answers either cheat by using negative-integer space to avoid an allocation or enter "nasty" nested loops which blow up the time complexity to O(n²).
Edits
Please pay attention before suggesting std::next_permutation. I am not trying to generate all possible permutations, which I could do with std::next_permutation. I am instead trying to apply a single particular permutation to an array.
The hint to find the cycles and permute each cycle worked for me. To sum up my approach, I find the start indices of all cycles in the constructor.
Then, in apply(), I permute each cycle by just repeatedly using std::swap.
struct Permutation {
private:
/// The single vector which stores both the permutation
/// AND the indices of the cycles starts.
std::vector<size_t> perm;
/// The size of the permutation / index of first cycle index.
size_t permSize;
public:
Permutation(std::vector<size_t> table)
: perm{std::move(table)}, permSize{perm.size()} {
findCycles();
}
template <typename T>
void apply(T data[]) const {
for (size_t cycle = permSize; cycle < perm.size(); ++cycle) {
const size_t start = perm[cycle];
for (size_t prev = start, next = perm[prev];
next != start;
prev = next, next = perm[next]) {
std::swap(data[prev], data[next]);
}
}
}
size_t size() const {
return permSize;
}
private:
void findCycles();
}
findCycles() is also easy to implement, but requires the temporary allocation of a bit-vector.
void Permutation::findCycles() {
std::vector<bool> visited(size());
for (size_t i = 0; i < size(); ++i) {
if (visited[i]) {
continue;
}
for (size_t j = i; not visited[j]; ) {
visited[j] = true;
j = perm[j];
}
perm.push_back(i);
}
}

C++ `std::sort` over pointer to 2D data without copying

I have a large amount of data (GiB to TiB) in a C-style array of 2D data. It is not an array-of-arrays but instead a pointer to data that is interpreted as 2D data. It is very large so I do not want to copy it to std::vectors or similar. I cannot control the source of the data, it comes from an external library.
I need to std::sort the rows of the data based on the data in the columns (not quite lex-sort, but similar concept).
I have figured out how to do it with a compile-time known number of columns. For example:
#define COLUMNS 4
struct Row {
double values[COLUMNS];
};
double* data = ...;
size_t n_rows = ...;
size_t n_cols = COLUMNS;
std::sort((Row*)data, ((Row*)data)+n_rows, comp);
I know I can template the struct for COLUMNS instead of using a macro and instead of using comp could define the operator< than in the Row struct but that doesn't change the compile-time nature of the number of columns*.
The only solution I can think of is to use a custom random-access iterator that knows the stride of each row. But before I make my own iterator (which is always a bit daunting to me) I want to make sure there is no other way.
*These design choices were made due to the fact I am actually writing this in Cython and not C++, but that shouldn't matter, I can't figure out how to do this with C++ without a custom iterator. I am willing to write solutions in C++ but prefer options that can be written Cython (I can convert).
Example code showing the reorder in place in O(n) time below. You'll need to change pa[i]-a which converts a pointer to index to deal with the actual structure for a[].
#include <algorithm>
#include <iostream>
bool compare(const double *p0, const double *p1)
{
return *p0 < *p1;
}
int main()
{
double a[8] = {8.0,6.0,1.0,7.0,5.0,3.0,4.0,2.0};
double *pa[8];
size_t i, j, k;
double ta;
// create array of pointers to a[]
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++)
pa[i] = &a[i];
// sort array of pointers to a[]
std::sort(pa, pa+sizeof(a)/sizeof(a[0]), compare);
// reorder a[] and pa[] according to pa[] in O(n) time
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++){
if(i != pa[i]-a){
ta = a[i];
k = i;
while(i != (j = pa[k]-a)){
a[k] = a[j];
pa[k] = &a[k];
k = j;
}
a[k] = ta;
pa[k] = &a[k];
}
}
for(i = 0; i < sizeof(a)/sizeof(a[0]); i++)
std::cout << a[i] << ' ';
std::cout << std::endl;
return 0;
}
The reorder in place works by undoing the "cycles" in pa[] sorted according to a[]. For this example code, a list of indices 0 to 7 followed by a list of pa[i]-a for i = 0 to 7 results in:
0 1 2 3 4 5 6 7 (i)
2 7 5 6 4 1 3 0 (pa[i] - a)
This shows the "cycles" in pa[] sorted according to a[]. Starting with the 0 in the (i) line, the index below it is 2. Looking at the 2 in the i line, the number below it is a 5. Below 5 is a 1. Below 1 is a 7. Below 7 is a 0, completing that cycle. Using -> to note the next index, there are 3 cycles in this case:
{0->2->5->1->7->0} {3->6->3} {4->4}
What the reorder in place does is undo the cycles for both a[] and pa[]. It finds the first cycle at pa[0] (i != pa[i]-a). Looking at a[], you have ta=a[0], a[0]=a[2], a[2] = a[5], a[5]=a[1], a[1]=a[7], at this point i == 0 == pa[7]-a, the last part of the cycle and it sets a[7] = ta. pa[] is updated in the same manner. The next cycle is ta=a[3], a[3]=a[6], a[6] = ta. The last cycle, 4->4 points to itself, so is skipped (i == pa[i]-a). The time complexity for this is O(n).
There's a youtube video about permutations and cycle notation (in this case it would be (0,2,5,1,7)(3,6) (the (4) is ignored since it's in place). You can do a web search for "permutation cycle" for other articles.
https://www.youtube.com/watch?v=MpKG6FmcIHk
This might do the trick. Define Row as a pointer to the beginning of a row, like so:
struct Row {
double* start;
static int columns;
Row(const Row& row) = default;
// Overload operator= to copy your data.
Row& operator=(const Row& rhs) {
memcpy(start, rhs.start, columns*sizeof(double));
}
Row operator<(const Row& rhs) const {
// your comparison function
}
};
Use like so:
double* data = ...;
size_t n_rows = ...;
size_t n_cols = COLUMNS;
Row::columns = n_cols;
std::vector<Row> rows(n_rows);
for(int i=0;i<n_rows;++i) {
rows[i].start = data + i*n_cols;
}
std::sort(rows.begin(), rows.end());
You'll need to create a std::vector<Row>. Hopefully you don't have so many rows so that's a performance issue.

C++ sort ascending non-zero values

I'm a bit rusted with c++ and after one day of thinking I coulnd't come out with an efficient way of computing this problem.
Suppose I have an array of 5 float values
lints[5]={0, 0.5, 3, 0, 0.6};
I would like to introduce a new array:
ranks[5] that contains the ascending rank of the non-0 values of the array lints.
in this case the answer would read
ranks[1]=0;
ranks[2]=1;
ranks[3]=3;
ranks[4]=0;
ranks[5]=2;
In this example the 0 values returns rank 0 but they're not relevant since i only need the rank of positive values.
Thanks in advance
edit:
Thanks to everybody for help, this is what I found suiting my needs in case you have the same task :)
double lengths[5], ranks[5];
double temp;
int i,j;
lengths[0] = 2,lengths[1] = 0,lengths[2] = 1,lengths[3] = 0,lengths[4] = 4;
ranks[0] = 1, ranks[1] = 2, ranks[2] = 3, ranks[3] = 4, ranks[4] = 5;
for(i=0;i<4;i++){
for(j=0;j<4-i;j++){
if((lengths[j]>lengths[j+1] && lengths[j+1]) || lengths[j]==0){
// swap lenghts
temp=lengths[j];
lengths[j]=lengths[j+1];
lengths[j+1]=temp;
// swap ranks
temp=ranks[j];
ranks[j]=ranks[j+1];
ranks[j+1]=temp;
}
}
}
cheers.
You can use any sorting algorithm with a simple addition. When swapping 2 values you can swap index values too.
Create index values for initial indexes
ranks[5] = {1,2,3,4,5}; //or 0,1,2,3,4
for (int i = 0 ; i < 5 ; i++){
for(int j = 0 ; j < 5 ; j++){
//if array[i] < array[j]
//swap array[i] - array[j]
//swap ranks[i] - ranks[j]
}
}
As #cokceken said (I know answers shouldn't refer to other answers but I'm not a high enough Stack Overflow rank to comment on answers :/ ), use any simple sorting algorithm, and simply add in your own functionality for any special cases, such as values of 0 or negative values in your example.
For example, assuming you don't actually want to sort the original array and just create a new array that links indices in the array to their sorted rank,
array[arraySize] = // insert array here;
ranks[arraySize];
for (int i = 0; i < arraySize; i++){
int indexRank = 0;
for (int j = 0; j < arraySize; j++){
if (array[j] < array[i]){
indexRank++;
}
}
if (array[i] <= 0) {
ranks[i] = -1 // or whatever implementation you want here
} else {
ranks[i] = indexRank;
}
}
(note that arraySize must be a value and not a variable, since C++ does not let you statically define an array with a variable size)
I found this was easier if you keep separate values for the value, original position and the rank in a class:
#include <vector>
#include <iostream>
#include <algorithm>
struct Item {
float value;
int original_position;
int rank;
};
int main() {
float lints[5] = {0, 0.5, 3, 0, 0.6};
std::vector<Item> items{};
int index{};
for(auto i : lints)
items.push_back(Item{i,index++,0}); // assign index to original_position
std::sort(items.begin(), items.end(), [](auto& l, auto& r) {return l.value < r.value; }); // sort by float value
auto it = std::find_if(items.begin(), items.end(), [](auto& i) {return i.value > 0; }); // find first non-zero position (as iterator)
int new_rank_value{1}; // start numbering non-zero numbers from 1
std::for_each(it, items.end(), [&new_rank_value](auto& i) {i.rank = new_rank_value++; }); // assign non-zero numbers a rank value
std::sort(items.begin(), items.end(), [](auto& l, auto& r) {return l.original_position < r.original_position ; }); // sort by original position again
for(auto i : items)
std::cout << "ranks[" << i.original_position << "]=" << i.rank << ";\n";
}
Output:
ranks[0]=0;
ranks[1]=1;
ranks[2]=3;
ranks[3]=0;
ranks[4]=2;

Find order of an array using minimum memory and time

Let's say i have an array of 5 elements. My program knows it's always 5 elements and when sorted it's always 1,2,3,4,5 only.
As per permutations formula i.e n!/(n-r)! we can order it in 120 ways.
In C++ using std::next_permutation I can generate all those 120 orders.
Now, my program/routine accepts an input argument as a number in the range of 1 to 120 and gives the specific order of an array as output.
This works fine for small array sizes as i can repeat std::next_permutation until that matches input parameter.
The real problem is, How can i do it in less time if my array has 25 elements or more? For 25 elements, the number of possible orders are : 15511210043330985984000000.
Is there a technique that I can easily find the order of numbers using a given number as input?
Thanks in advance :)
This is an example c++ implementation of the algorithm mentioned in this link:
#include <vector>
#define ull unsigned long long
ull factorial(int n) {
ull fac = 1;
for (int i = 2; i <= n; i++)
fac *= i;
return fac;
}
std::vector<int> findPermutation(int len, long idx) {
std::vector<int> original = std::vector<int>(len);
std::vector<int> permutation = std::vector<int>();
for (int i = 0; i < len; i++) {
original[i] = i;
}
ull currIdx = idx;
ull fac = factorial(len);
while (original.size() > 0) {
fac /= original.size();
int next = (currIdx - 1) / fac;
permutation.push_back(original[next]);
original.erase(original.begin() + next);
currIdx -= fac * next;
}
return permutation;
}
The findPermutation function accepts the length of the original string and the index of the required permutation, and returns an array that represents that permutation. For example, [0, 1, 2, 3, 4] is the first permutation of any string with length 5, and [4, 3, 2, 1, 0] is the last (120th) permutation.
I have had a similar problem where I was storing lots of row in a Gtk TreeView and did not want to go over all of them every time I want to access a row by its position and not by its reference.
So, I created a map of the positions of the row so I could easily identify them by the parameter I needed.
So, my suggestion to this is you go over all permutations once and map every std::permutation in an array (I used a std::vector), so you can access it by myVector[permutation_id].
Here is my way I have done the mapping:
vector<int> FILECHOOSER_MAP;
void updateFileChooserMap() {
vector<int> map;
TreeModel::Children children = getInterface().getFileChooserModel()->children();
int i = 0;
for(TreeModel::Children::iterator iter = children.begin(); iter != children.end(); iter++) {
i++;
TreeModel::Row row = *iter;
int id = row[getInterface().getFileChooserColumns().id];
if( id >= map.size()) {
for(int x = map.size(); x <= id; x++) {
map.push_back(-1);
}
}
map[id] = i;
}
FILECHOOSER_MAP = map;
}
So in your case you would just iterate over the permutations like this and you can map them in a way that allows you accesing them by their id.
I hope this helps you :D
regards, tagelicht

C++ Sort based on other int array

suppose i have two vector
std::vector<int>vec_int = {4,3,2,1,5};
std::vector<Obj*>vec_obj = {obj1,obj2,obj3,obj4,obj5};
How do we sort vec_obj in regard of sorted vec_int position?
So the goal may look like this:
std::vector<int>vec_int = {1,2,3,4,5};
std::vector<Obj*>vec_obj = {obj4,obj3,obj2,obj1,obj5};
I've been trying create new vec_array:
for (int i = 0; i < vec_int.size(); i++) {
new_vec.push_back(vec_obj[vec_int[i]]);
}
But i think it's not the correct solution. How do we do this? thanks
std library may be the best solution,but i can't find the correct solution to implement std::sort
You don't have to call std::sort, what you need can be done in linear time (provided the indices are from 1 to N and not repeating)
std::vector<Obj*> new_vec(vec_obj.size());
for (size_t i = 0; i < vec_int.size(); ++i) {
new_vec[i] = vec_obj[vec_int[i] - 1];
}
But of course for this solution you need the additional new_vec vector.
If the indices are arbitrary and/or you don't want to allocate another vector, you have to use a different data structure:
typedef pair<int, Obj*> Item;
vector<Item> vec = {{4, obj1}, {3, obj2}, {2, obj3}, {1, obj4}, {5, obj5}};
std::sort(vec.begin(), vec.end(), [](const Item& l, const Item& r) -> bool {return l.first < r.first;});
Maybe there is a better solution, but personally I would use the fact that items in a std::map are automatically sorted by key. This gives the following possibility (untested!)
// The vectors have to be the same size for this to work!
if( vec_int.size() != vec_obj.size() ) { return 0; }
std::vector<int>::const_iterator intIt = vec_int.cbegin();
std::vector<Obj*>::const_iterator objIt = vec_obj.cbegin();
// Create a temporary map
std::map< int, Obj* > sorted_objects;
for(; intIt != vec_int.cend(); ++intIt, ++objIt )
{
sorted_objects[ *intIt ] = *objIt;
}
// Iterating through map will be in order of key
// so this adds the items to the vector in the desired order.
std::vector<Obj*> vec_obj_sorted;
for( std::map< int, Obj* >::const_iterator sortedIt = sorted_objects.cbegin();
sortedIt != sorted_objects.cend(); ++sortedIt )
{
vec_obj_sorted.push_back( sortedIt->second );
}
[Not sure this fits your usecase, but putting the elements into a map will store the elements sorted by key by default.]
Coming to your precise solution if creation of the new vector is the issue you can avoid this using a simple swap trick (like selection sort)
//Place ith element in its place, while swapping to its position the current element.
for (int i = 0; i < vec_int.size(); i++) {
if (vec_obj[i] != vec_obj[vec_int[i])
swap_elements(i,vec_obj[i],vec_obj[vec_int[i]])
}
The generic form of this is known as "reorder according to", which is a variation of cycle sort. Unlike your example, the index vector needs to have the values 0 through size-1, instead of {4,3,2,1,5} it would need to be {3,2,1,0,4} (or else you have to adjust the example code below). The reordering is done by rotating groups of elements according to the "cycles" in the index vector or array. (In my adjusted example there are 3 "cycles", 1st cycle: index[0] = 3, index[3] = 0. 2nd cycle: index[1] = 2, index[2] = 1. 3rd cycle index[4] = 4). The index vector or array is also sorted in the process. A copy of the original index vector or array can be saved if you want to keep the original index vector or array. Example code for reordering vA according to vI in template form:
template <class T>
void reorder(vector<T>& vA, vector<size_t>& vI)
{
size_t i, j, k;
T t;
for(i = 0; i < vA.size(); i++){
if(i != vI[i]){
t = vA[i];
k = i;
while(i != (j = vI[k])){
// every move places a value in it's final location
vA[k] = vA[j];
vI[k] = k;
k = j;
}
vA[k] = t;
vI[k] = k;
}
}
}
Simple still would be to copy vA to another vector vB according to vI:
for(i = 0; i < vA.size(); i++){
vB[i] = vA[vI[i]];