What is the most efficient algorithm to shift array elements at specified indices left and right by one position?
For example shift indices [1,3,5] of [a,b,c,d,e,f] to the left to get [b,a,d,c,f,e]
I don't want it to rotate if the new index is out of bounds, if that makes sense.
I am using C++ std::vector for array storage.
I'm interpreting your question as to swap the two adjacent entries of an array based on index. If this is wrong, then please clarify your question with an example for which this is not correct.
void swapElements(const std::vector<int>& indexes, std::vector<int>& array){
for(auto i : indexes){
if (i < 1 || i >= array.size()){
continue;
}
std::swap(array[i-1], array[i]):
}
}
I think the simplest way is to use std::swap with the element with the given index and the element that preceds it.
For the first element you can use
std::swap( v.front(), v.back() );
Here is an example
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<char> v = { 'a', 'b', 'c', 'd', 'e', 'f' };
for ( char c : v ) std::cout << c << ' ';
std::cout << std::endl;
for ( size_t i : { 1, 3, 5 } )
{
if ( i == 0 ) std::swap( v.front(), v.back() );
else if ( i < v.size() ) std::swap( v[i], v[i-1] );
}
for ( char c : v ) std::cout << c << ' ';
std::cout << std::endl;
return 0;
}
The output is
a b c d e f
b a d c f e
If you do not want to rotate the vector then you can sibstitute the if statement for the following
for ( size_t i : { 1, 3, 5 } )
{
if ( 0 < i && i < v.size() ) std::swap( v[i], v[i-1] );
}
Related
Exercise: The vector A[1 to N] and a value s is given. Build the program that writes backwards every group of s elements. If s divided by N has a remainder, then the remaining values should be unchanged. If s is bigger than N (the nr of elements of the vector) than there will be no modification.
Lets say s = 4 and A = (1, 2, 3, 4, 5, 6, 7, 8)then after execution the values will be A = (4, 3, 2, 1, 8, 7, 6, 5)
My teacher requires this kind of vector: int n, A[n] where n is a value given by the user. And i think this is what is causing my program to crash when i read the final values. If not, where is the problem?
#include <iomanip>
using namespace std;
int ordering(int s, int n, int A[]);
int main()
{
int n, A[n];
int s;
cout << "Vlera e s: ";
cin >> s;
if (s <= 0)
{
return 1;
}
cout << "\nN: ";
cin >> n;
if (n <= 0)
{
return 1;
}
cout << "\nVector:";
for (int i = 0; i < n; i++)
{
A[i] = i + 1;
cout << " " << A[i] << " ";
}
if (s > n)
{
cout << "\nNo change\n";
return 0;
}
else
{
ordering(s, n, A);
}
cout << "\nNew vector:";
for (int i = 0; i < n; i++)
{
cout << " " << A[i] << " ";
}
return 0;
}
int ordering(int s, int n, int A[])
{
int counter = 0;
for (int i = 0, divider = n / s; i < divider; i++)
{
int decrease = 0;
for (int j = counter, a = counter + s; j < a; j++)
{
A[j] = a - decrease;
decrease++;
}
counter += s;
}
return 0;
}
This program using a compiler extension to allow variable sized arrays in the form myArray[variableSize]. Whilst not standard, it does work on some compilers.
You are using this feature here:
int n, A[n];
However, n is uninitialised at this point. This is undefined behaviour even on the compilers that support such variable sized arrays. One possible (but not the only) outcome of undefined behaviour is your program crashing.
Undefined behaviour can do anything in theory, but the realistic set of things in can do in reality is smaller. Some of the likely implications of the undefined behaviour here:
n has some huge number in it, from whatever last used that bit of memory. As a result, A is huge.
n is 0. You can't have a 0 sized array. If the compiler doesn't notice this, you could end up trashing memory.
Since n is uninitialised, the optimiser for the compiler (they usually do very some optimisations, even when on -O0) assumes that undefined behaviour cannot occur, which is violated here, leading to strange behaviour.
n is a reasonable value, just by luck, but because it is later updated it no longer matches the size of the array and you end up reading / writing memory off the end of the array, trashing memory.
There are other possibilities, but this gives an idea of the kind of things that can happen as a result of this specific instance of undefined behaviour. If you're interested to know more, using a debugger to step through the code in assembly (you only need learn a little to understand the output, it looks more scary than it need be) will show you what's actually happening.
Variable length arrays is not a standard C++ feature.
int n, A[n];
Moreover in the above declaration the variable n was not initialized. So in any case the program has undefined behavior.
Instead of an array you could use the standard class template std::vector.
The program can look simpler and more safer is to use standard algorithms such as, for example, std::reverse.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <numeric>
void reorder( std::vector<int> &v, size_t s )
{
if ( not ( s < 2 ) )
{
for ( auto last = std::end( v );
not (std::distance( std::begin( v ), last ) < s ); )
{
auto first = std::prev( last, s );
std::reverse( first, last );
last = first;
}
}
}
int main()
{
std::cout << "Vlera e s: ";
size_t s = 0;
std::cin >> s;
std::cout << "N: ";
size_t n = 0;
std::cin >> n;
std::vector<int> v( n );
std::iota( std::begin( v ), std::end( v ), 1 );
putchar( '\n' );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
reorder( v, s );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
return 0;
}
The program output might look like
Vlera e s: 4
N: 10
1 2 3 4 5 6 7 8 9 10
1 2 6 5 4 3 10 9 8 7
But it seems you need write the corresponding code yourself using loops. In this case the program can look like
#include <iostream>
#include <vector>
void reorder( std::vector<int> &v, size_t s )
{
if ( not ( s < 2 ) )
{
for ( auto n = v.size(); !( n < s ); n -= s )
{
for ( size_t i = 0; i < s / 2; i++ )
{
int value = v[n - s + i];
v[n - s + i] = v[n - i - 1];
v[n - i - 1] = value;
}
}
}
}
int main()
{
std::cout << "Vlera e s: ";
size_t s = 0;
std::cin >> s;
std::cout << "N: ";
size_t n = 0;
std::cin >> n;
std::vector<int> v( n );
int value = 1;
for ( auto &item : v ) item = value++;
putchar( '\n' );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
reorder( v, s );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
return 0;
}
The program output might look as already shown above
Vlera e s: 4
N: 10
1 2 3 4 5 6 7 8 9 10
1 2 6 5 4 3 10 9 8 7
Passing variable as array size is not valid you need to use constant const int n or create dinamic array int* arr = new int[n];, that array will be created in runtime, and you can pass variable as it size. Dont forget to delete that array whet it goes out of scope delete[] arr;
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 3 years ago.
Improve this question
I dont understand why the condition of if-statement needs to be a pointer. I assumed a normal variable call will not give any complaints.
Was trying to learn about std::vector::erase from cppreference, got intrigued about the example there (https://en.cppreference.com/w/cpp/container/vector/erase)
#include <vector>
#include <iostream>
int main( )
{
std::vector<int> c{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto &i : c) {
std::cout << i << " ";
}
std::cout << '\n';
// Erase all even numbers (C++11 and later)
for (auto it = c.begin(); it != c.end(); ) {
if (*it % 2 == 0) {
it = c.erase(it); // THE LINE ABOVE THIS
} else {
++it;
}
}
for (auto &i : c) {
std::cout << i << " ";
}
std::cout << '\n';
}
Output
0 1 2 3 4 5 6 7 8 9
1 3 5 7 9
Hope anyone could share an explanation or direct me to an available resource.
In the classical loop:
auto it = c.begin() - it is an iterator. To access what it refers to you need to dereference it, which you do with *it. The * there does not mean pointer, it means dereference (technically, on iterators, it's a call to operator*).
See also https://en.cppreference.com/w/cpp/iterator
In the range based loop:
for (auto &i : c) - here you get back a reference to the element in the container directly. No iterators involved.
Ranged based for-loop: necessity of pointer variable as condition in
if-statement
I think that the confusion is that you are incorrectly considering the ordinary for-loop
for (auto it = c.begin(); it != c.end(); )
as the ranged for-loop.
In your program the range-based for loop is used only to output the vector.
for (auto &i : c) {
std::cout << i << " ";
}
Iterators behave as pointers. That is for them for example there are defined operator * and operator ++.
Consider a similar program that deals with an array. Of course you can not remove elements from an array but you can move "removed" elements to the end of the array.
Here is a demonstrative program.
#include <iostream>
int main()
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const size_t N = sizeof( a ) / sizeof( *a );
for ( const int *p = a; p != a + N; ++p )
{
std::cout << *p << ' ';
}
std::cout << '\n';
int *q = a;
for ( const int *p = a; p != a + N; ++p )
{
if ( not ( *p % 2 == 0 ) )
{
if ( p != q ) *q = *p;
++q;
}
}
for ( const int *p = a; p != q; ++p )
{
std::cout << *p << ' ';
}
std::cout << '\n';
return 0;
}
Its output is
0 1 2 3 4 5 6 7 8 9
1 3 5 7 9
As you can see in this if statement
if ( not ( *p % 2 == 0 ) )
you have to dereference the pointer to get the value pointed to by the pointer.
Now rewrite the program the following way using generic functions std::begin, std::cbegin, and std::cend.
#include <iostream>
#include <iterator>
int main()
{
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( auto p = std::cbegin( a ); p != std::cend( a ); ++p )
{
std::cout << *p << ' ';
}
std::cout << '\n';
auto q = std::begin( a );
for ( auto p = std::cbegin( a ); p != std::end( a ); ++p )
{
if ( not ( *p % 2 == 0 ) )
{
if ( p != q ) *q = *p;
++q;
}
}
for ( auto p = std::begin( a ); p != q; ++p )
{
std::cout << *p << ' ';
}
std::cout << '\n';
return 0;
}
Now the pointers look like iterators and nothing was changed in the if statement
if ( not ( *p % 2 == 0 ) )
I'm a beginner in C++ and meet a problem.
Assuming there is a vector of integers, how could we get the index array for the same value?
i.e. If the vector is: [a,a,b,c,a,c,b,c] where a, b, c are integers.
Then the expected index arrays should be:
v_a = [1,2,5], v_b = [3,7], v_c = [4,6,8]
Is there any simple way in C++ to implement this?
In my opinion it is better to use std::multimap in this case because the number of different integers in the original array is unknown and as I understand can be changed.
Here is a demonstrative program
#include <iostream>
#include <vector>
#include <map>
int main( void )
{
std::vector<char> v = { 'a', 'a', 'b', 'c', 'a', 'c', 'b', 'c' };
std::multimap<char, size_t> m;
for ( size_t i = 0; i < v.size(); i++ ) m.insert( { v[i], i } );
for ( auto it = m.begin(); it != m.end(); )
{
auto p = m.equal_range( it->first );
while ( p.first != p.second )
{
std::cout << p.first++->second << ' ';
}
std::cout << std::endl;
it = p.second;
}
}
The program output is
0 1 4
2 6
3 5 7
Take into account that array indices start from 0 in C++.
First you need to take in account that in C++ (as in C and Java and many others languages), array's and vector's indexes start at 0. N size means N - 1 positions. For example: one vector/array with 3 elements, goes from index 0 to index 2.
In your example: v_a = [0,1,4], v_b = [2,6], v_c = [3,5,7]
int a, b, c;
vector<int> integers;
vector<int> v_a;
vector<int> v_b;
vector<int> v_c;
void indexes(){
for(int i = 0; i < integers.size(); i++){
if( integers[i] == a )
v_a.push_back(i);
else if( integers[i] == b )
v_b.push_back(i);
else if( integers[i] == c )
v_c.push_back(i);
}
}
Well this is the solution for your problem. Since you're learning C++, you may want to take this solution and try to make it more generic.
I have an array a[]={1,0,0,0,0}; and I want to rotate it so it ends up like this: a[] = {0,0,0,0,1};
how can I shift one element to the left or more then one?
#include<iostream.h>
int main ()
{
int temp,a[] = {1,0,0,0,0};
for(int i =0;i<=4;i++)
{
temp = a[0];
a[i] = a[i-1];
a[4] = temp;
cout << a[i];
}
system("pause");
return 0;
}
Use standard algorithm std::rotate declared in header <algorithm>
For example
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
int a[] = { 1, 0, 0, 0, 0 };
std::rotate( std::begin( a ), std::next( std::begin( a ) ), std::end( a ) );
for ( int x : a ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output is
0 0 0 0 1
Statement
std::rotate( std::begin( a ), std::next( std::begin( a ) ), std::end( a ) );
can be written simpler
std::rotate( a, a + 1, a + 5 );
ALso you can use standard algorithm std::rotate_copy if you want to have the original array unchanged.
If you compiler does not support the range-based for loop then you can write
for ( size_t i = 0; i < 5; i++ ) std::cout << a[i] << ' ';
If you have access to C++11, this can be done by creating an std::valarray and then using it's cshift function (which stands for circular-shift).
An std::valarray is an object that was designed, as a part of the C++ 2011 standard, to hold an array of values, and then easily perform operations on them, such as mathematical operators and common functions like swap or shift.
As an example:
#include <valarray>
int main()
{
int myInts[] = {1,2,3,4,5};
std::valarray<int> myValArray(myInts, 5); // 1 2 3 4 5
myValArray = myValArray.cshift(2); // 3 4 5 1 2 - rotated left
myValArray = myValArray.cshift(-1); // 2 3 4 5 1 - rotated right
return 0;
}
Not sure how to phrase this the best way but I am wanting to get unique data in reverse. It'll be better if I give an example
If I have the data
0 1
0 3
0 4
1 0
1 2
1 5
3 0
how could I get rid of the data that is a reverse of itself? For example: 0 1 and 1 0 and I would like to get rid of 1 0 because I already saw 0 1. Another example: 0 3 and 3 0 and I would like to get rid of 3 0 because I already saw 0 3.
So the data would instead be this:
0 1
0 3
0 4
1 2
1 5
Here is the code I have for how the data is coming out.
int temp;
int tn;
for (int i=0; i < n-1; i++)
{
for (int j=0; j< 4; j++)
{
temp = grid[i].neighbor[j];
tn = get_neighbor(j);
cout << i << " " << grid[i].neighbor[j] <<endl; //index
}
}
Note that it is i and grid[i].neighbor[j] that are producing the two numbers.
If you may not to change the order of elements of the original vector then the straightforward approach is the following
std::vector<std::vector<int>> v;
int a[][2] = { { 0, 1 }, { 0, 3 }, { 0, 4 }, { 1, 0 }, { 1, 2 }, { 1, 5 }, { 3, 0 } };
std::transform( std::begin( a ), std::end( a ), std::back_inserter( v ),
[]( const int ( &row )[2] )
{
return std::vector<int>( std::begin( row ), std::end( row ) );
} );
for ( const std::vector<int> &row : v )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
std::cout << std::endl;
std::function<bool( const std::vector<int> &, const std::vector<int> & )> identical =
[]( const std::vector<int> &v1, const std::vector<int> &v2 )
{
return ( v1.size() == v2.size() && v1.size() == 2 &&
( v1[0] == v2[0] && v1[1] == v2[1] || v1[0] == v2[1] && v1[1] == v2[0] ) );
};
auto last = v.begin();
for ( auto first = v.begin(); first != v.end(); ++first )
{
using namespace std::placeholders;
if ( std::find_if( v.begin(), last, std::bind( identical, _1, *first ) ) == last )
{
if ( first != last ) *last = *first;
++last;
}
}
v.erase( last, v.end() );
for ( const std::vector<int> &row : v )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
Of course there was no any need to define intermediate array a that to initialize the vector. You can initialize it using initializer list.
The output is
0 1
0 3
0 4
1 0
1 2
1 5
3 0
0 1
0 3
0 4
1 2
1 5
1) Sort the dataset
2) Check for duplicates (just normally, not in reverse)
3) Remove any duplicates found
4) Loop through and check each item against the reverse of each item (two for loops)
Steps 1/2/3 can be combined into step 4 for less iteration, or they can be seperated into a set. A set in C++ will automatically remove duplicates for steps 2 and 3 as well as sort your values and is a good chance to check out some STL stuff (Standard Template Library).
I have an idea on how to implement this, just for share, please do not vote down my answer..
The key point here is how to recognize two reverse pair, of course we can compare each of them, but there are surely more elegant way to do this.
If your numbers are in some fixed range integer, for example 0..10, then you can define a prime number array like this prime_arr = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31], now we can see if two pairs <x. y> and <a, b> are the same or in reverse, we can just compare prime_arr[x] * prime_arr[y] and prime_arr[a] * prime_arr[b].
Oh, it is just a sample, if your number is not in fixed range, but all non negative integer, you can consider x^2 + y^2, if two pairs <x, y> and <a, b> are the same or in reverse, compare x^2 + y^2 and a^2 + b^2.
Here is a demo implementation, hope it is useful for you...
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<pair<int, int>> v = { { 0, 1 }, { 0, 3 }, { 0, 4 },
{ 1, 0 }, { 1, 2 }, { 1, 5 }, { 3, 0 }};
vector<int> flagv;
for (auto p : v) {
int flag = p.first * p.first + p.second * p.second;
if (find(flagv.begin(), flagv.end(), flag) == flagv.end()) {
cout << p.first << " " << p.second << endl;
flagv.push_back(flag);
}
}
return 0;
}
Just one look for scanning the pair list..
Anyway, it is an advice from me, and limited usage(non negative integer), but you can figure out more proper computation to recognize two pair whether they are in reverse or the same.
just use comparator that normalize pair:
typedef std::pair<int,int> ipair;
typedef std::vector<ipair> ipvector;
inline
ipair norm( const ipair &p )
{
return ipair{ std::min( p.first, p.second ), std::max( p.first, p.second ) };
}
struct norm_cmp {
bool operator()( const ipair &p1, const ipair &p2 )
{
return norm( p1 ) < norm( p2 );
}
};
int main()
{
ipvector v = { { 0, 1 }, { 0, 3 }, { 0, 4 },
{ 1, 0 }, { 1, 2 }, { 1, 5 }, { 3, 0 }};
std::set<ipair, norm_cmp> s( v.begin(), v.end() );
for( const ipair &p : s )
std::cout << '{' << p.first << ',' << p.second << '}' << std::endl;
}
run on ideone