Swapping values in array C++ - c++

This is the code:
for (i = 0; i < size; i++)
{
swap(a[i], a[size - i - 1]);
}
It looks correct.. and it is because I have used it in other languages, but on C++ it doesn't work. Any suggestions? Thanks

Have you tried stepping through this program? Because at a glance, it doesn't look like it would work.
Like, for the following input, you'd get the following results:
a = {0, 1, 2, 3, 4};
i == 0: a = {4, 1, 2, 3, 0};
i == 1: a = {4, 3, 2, 1, 0};
i == 2: a = {4, 3, 2, 1, 0};
i == 3: a = {4, 1, 2, 3, 0};
i == 4: a = {0, 1, 2, 3, 4};
See what's happening? The numbers are getting swapped, and then swapped again.
Cutting it off half-way should fix the problem.
for (i = 0; i < size / 2; i++)
{
swap(a[i], a[size - i - 1]);
}

for (i = 0; i < size / 2; i++)
{
swap(a[i], a[size - i - 1]);
}
Since you will swap each item twice if you go i < size

Since you are using c++ you can use some awesome c++ features, like std::reverse:
std::reverse(&a[0], &a[0] + size);
Here is a live example.

You probably are looking for std::iter_swap. It swaps 2 values in an array using the appropriate iterators:
std::iter_swap(std::begin(a) + i, std::end(a) - i - 1);

Related

divide array when encountering zeroes

I want to divide an array into multiple(or one, maybe zero) arrays like the example below:
array = [0 1 1 2 3 4 0 3 0 3 3 0 5 6 7] -> array1 = [1 1 2 3 4] array2 = [3] array3 = [3 3] array4 = [5 6 7]
my naive approach to do this was first removing zeros from left and right then proceed to use two iterators to find the begin and end of every subarray and by using a vector constructor build the subarrays and pass them to a function. But I know for a fact that my approach is naive and inefficient so I would appreciate some suggestions on how to approach this more efficiently.
Thanks a lot guys!
also this is my code for my approach(a is the mother array):
for(int i = 0; i < a.size(); i++){
if(a[i] != 0)
break;
a.erase(a.begin() + i);
}
for(int i = a.size() - 1; i >= 0; i--){
if(a[i] != 0)
break;
a.erase(a.begin() + i);
}
auto begin = a.begin();
auto end = a.begin() + 1;
for (int i = 0; i < a.size(); i++){
if(a[i] == 0){
vector<int> temp(begin, end);
color(temp);
begin = end + 1;
end = begin + 1;
}
else end++;
}
One of the approach to solve this problem is to create an auxiliary array which contains index of all zero elements (in implementation const_iterator is used rather than index). This problem can be solved without creating such auxiliary array but the advantage of it is, you can find number of sub arrays are going to be created in advance. Approach is as follows,
Iterate input array and put index of zero elements in auxiliary array,
InputArray = [0, 1, 1, 2, 3, 4, 0, 3, 0, 3, 3, 0, 5, 6, 7]
Array contains zero elements index = [0, 6, 8, 11]
As you an see above there are four divider (zero index entries) which divides input array into 3 sub arrays and last zero is at index 11 and that is not last element of input array that's why one more sub array will be create so total sub arrays = 4 and for other details please see code,
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using std::cout;
std::vector<std::vector<int>> splitAtZero(const std::vector<int>& arr){
std::vector<std::vector<int>::const_iterator> divider;
divider.reserve(std::max<std::size_t>(arr.size() / 4, 2));
for(std::vector<int>::const_iterator it = arr.cbegin(), endIt = arr.cend(); endIt != it; ++it){
if(0 == *it){
divider.push_back(it);
}
}
if(divider.empty()){
return {arr};
}
if(arr.size() == divider.size()){
return {};
}
std::size_t numOfSubArray = (divider.size() - 1) + (arr.cbegin() != divider.front() ? 1 : 0) +
(arr.cend() != divider.back() ? 1 : 0);
std::vector<std::vector<int>> subArr;
subArr.reserve(numOfSubArray);
std::vector<int>::const_iterator it = arr.cbegin();
for(std::vector<int>::const_iterator divderIt : divider){
if(divderIt - it > 0){
subArr.emplace_back(it, divderIt);
}
it = divderIt + 1;
}
if(arr.cend() != it){
subArr.emplace_back(it, arr.cend());
}
return subArr;
}
int main(){
std::string comma("");
for(std::vector<int>& subArr : splitAtZero({0, 1, 1, 2, 3, 4, 0, 3, 0, 3, 3, 0, 5, 6, 7})){
cout<< comma<< "[";
std::copy(subArr.cbegin(), subArr.cbegin() + (subArr.size() - 1), std::ostream_iterator<int>(cout, ", "));
cout<< subArr.back()<< "]";
comma = ", ";
}
cout<< '\n';
}
Output:
[1, 1, 2, 3, 4], [3], [3, 3], [5, 6, 7]
In the following approach that I propose you can retrieve the sub-arrays with a single sequential scan, with no need to exclude zeros at the beginning or at the end:
std::vector<std::vector<int>> arrays;
std::vector<int> currentArray;
for (int i = 0; i < a.size; i++)
{
if (a[i] == 0 || i == a.size - 1)
{
if (currentArray.size() != 0)
{
arrays.push_back(currentArray);
currentArray.clear();
}
}
else
{
currentArray.push_back(a[i]);
}
}

Vector erase function not working properly

I am trying one of the practice problems on hackerrank.
I'm aware there is a better way to do it, but I would like to know why this way didn't work to understand it better.
The vector erase function seems to work as intended until the last couple of times and then erases at the wrong index, even though nothing changes.
debugger output:
1, 1, 3, 1, 2, 1, 3, 3, 3, 3, //what is currently in the vector
Delete indx 0 & 1 //The first pair that I will erase and increment count
3, 1, 2, 1, 3, 3, 3, 3, //continue...
Delete indx 0 & 4
1, 2, 1, 3, 3, 3,
Delete indx 0 & 2
2, 3, 3, 3,
Delete indx 1 & 2 //says to delete the first and second three
3, 3, //it looks like the 0th and some other index was erased instead
Delete indx 0 & 1
count returned is: 5
let me know if I can add to this question to make it better, thanks
int i, count = 0;
for (i=0;i<ar.size()-1;i++)
{
for (int j=i+1;j<ar.size();j++)
{
if (ar[i] == ar[j])
{
ar.erase(ar.begin()+i-1);
ar.erase(ar.begin()+j-1);
count++;
i=-1;
break;
}
}
if (ar.size()== 0)
break;
}
From what I understood, you only need the count of pairs (considering the removals).
for(int i = 0; i < ar.size() - 1; i++){
for(int j = i + 1; j < ar.size(); j++){
if(ar[i] == ar[j]) {
ar.erase( ar.begin() + j );
count++;
break;
}
}
}
This way you only need to perform 1 call of erase (which is slow, considering it moves all the elements in the right of the deleted element 1 slot to the left).
If you have big vectors, also consider not using ar.size() all the time (at least in j loop, since in i loop it's kind of essential). Try for(int j = i + 1, len = ar.size(); j < len; j++).

Pointer Arithmetic using arrays

My question is that if you were print out the resulting *(ary + i), which I know is another way to say ary[i] value, would the following output be a hexadecimal/garbage data or would that specific index be assigned a new value based on the result computed from *ary + i? This whole pointer stuff still throwing me off.
int ary[] = [7, 5, 3, 1, 2, 4, 6, 8];
for (int i = 0; i < 8; i++)
{
*(ary + i) = *ary + i;
}
ary decays to a pointer in the expressions you posted. And since it always produces the same address (the first element), *ary will evaluate to 7 at every iteration.
Since you understand that *(ary + i) is equivalent to ary[i], you should now gather that your loop body is akin to this:
ary[i] = 7 + i;
int ary[] = [7, 5, 3, 1, 2, 4, 6, 8]; is wrong assignment method,
one must use { } to assign values to array.
So, correct way to define is:
int ary[] = {7, 5, 3, 1, 2, 4, 6, 8};
Here *(ary + i) is equivalent to ary [i] , and *ary + i is equivalent to ary [0] + i.
Addressing your question, no it won't throw hex or garbage, you have dereferenced a pointer, so it will give the data stored at that location.
Code:
#include <iostream>
int main ()
{
int ary[] = {7, 5, 3, 1, 2, 4, 6, 8};
for (int i = 0; i < 8; i++)
{
*(ary + i) = *ary + i;
}
for (int j=0;j <8;j++)
{
std::cout <<ary [j];
}
}
Output:
7891011121314
Hope you draw the correlation.
if this helps great, if it doesnot, indicate so in comments, willing to edit

Shifting Elements to the Right After a Certain Index

I have an array _data and I'm trying to add a number to the array at a certain position. Every number after the index of position should be shifted one index to the right. I'm having trouble conceptually in doing this.
This is what I have as of now:
void list::add(int num, size_t position)
{
for (int i = 0; i < _size; i++)
{
_data[position + i + 1] = _data[position + i];
}
_data[position] = num;
}
For example, say num = 9 and position = 3 and the given values in the array are {1, 3, 4, 5, 6, 7}. I would want it to be {1, 3, 4, 9, 5, 6, 7}. What ends up happening, though, is that it grabs the number that has already been replaced and puts that back into the array. (ex 1, 3, 4, 9, 5, 5, 5}.
It's depending on type of your variable _data:
If it's an array:
for (std::size_t i = _size - 1; i != position; --i)
{
_data[i] = _data[i - 1];
}
_data[position] = num;
If it's a vector:
_data.insert(_data.begin() + position, num);
Anyway, it's recommended to use a std::vector instead of raw array, and it's NOT recommended to use underscore at the beginning of variable name

Access violation?

I was trying to write a simple Monte Carlo simulation program. To be exact, I wanted to analyze the combat results depending on the varying army sizes on both offense and defense - something in tune of this: http://en.wikipedia.org/wiki/Risk_(game)#Dice_probabilities
Now... Risk II Same time rule offers different kind of challenge: varying army size means different color of dice (which means different distribution function for the numbers) In short, the smaller the size of your army is, the more likely you'll end up with 1s, while the larger the size of your army is, the more likely you'll end up with higher number of rolls.
Since using if statements for all the possible condition was a colossal stupidity at its finest, I tabulated all the possible rolling results in 5x12 array. (12 sides in all of the dice, and 5 varying strength, so you get 5x12)
I thought of carrying out 10000 simulations for each offense/defense combinations but once I realized that would mean over 9 million calculations, I decided to cut it short at 100 per combination.
The following is the code; once I run it, it gives me the Access Violation error. I don't know where I made an error. If there is any advice you could offer, I'd appreciate that too. Thanks in advance.
/* Risk II Combat Result Table
For starter, we shall consider one-direction attack in RISK II
and generate the combat table for use.
Machine: Pentium Dual Core E6600
Ram: 6G
OS: Windows 7
Compiler: Visual Studio 2010
Jimmy Smith, 24-March-2012
*/
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
/* Initializing:
Range legend:
White = 1 ~ 6
Yellow = 7 ~ 12
Orange = 13 ~ 20
Red = 21 ~ 30
Black = 31 ~
First row of Dice array corresponds to white dice, and so on.
*/
int Dice[5][12] = { {1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6},
{1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6},
{1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6},
{1, 2, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6},
{1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6} };
int Roll_Index [30]= {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4};
int main() {
float Table[30][30];
for (int i = 0; i < 30; i ++)
for (int j = 0; j < 30; j ++)
Table [i][j] = 0.0;
int Result[100];
for (int i = 0; i < 100; i++) Result[i] = 0;
float prob = 0.0;
int Atk = 0;
int Def = 0; //Number of attackers and defenders
int A_Ind = 0;
int D_Ind = 0; //Dice side index
int A_Roll_Index = 0;
int D_Roll_Index = 0; //Roll index on both sides
int A_Dice = 0;
int D_Dice = 0; //Roll result
int Damage = 0;
int Sum = 0; //Internal sum
FILE* fp;
//Time for hard core Monte-Carlo shit! 100 simulation for each situation
for (Atk = 0; Atk<30; Atk++) {
for (Def = 0; Def < 30; Def++) {
for (int i = 0; i < 100; i++) {
int Attacker = Atk +1;
int Defender = Def +1;
while((Attacker>0)&&(Defender>0)) {
A_Ind = (int)(rand()*12);
D_Ind = (int)(rand()*12); //The die is cast!
A_Roll_Index = Roll_Index[Attacker-1];
D_Roll_Index = Roll_Index[Defender-1];
A_Dice = Dice[A_Roll_Index][A_Ind];
D_Dice = Dice[D_Roll_Index][D_Ind];
Damage = min(A_Roll_Index, D_Roll_Index) + 1;
if (A_Dice >= D_Dice) {
Defender -= Damage;
if (Defender == 0) Result[i] = 1;
}
else {
Attacker -= Damage;
if (Attacker == 0) Result[i] = 0;
}
}
}
for (int i = 0; i < 100; i++) Sum+=Result[i];
prob = (float)(Sum/100);
Table[Atk][Def] = prob;
}
}
/* open new file for output and write a title */
fp = fopen( "Combat.dat", "w+");
if( NULL == fp ) {
printf( "cannot open file\n" );
return( 0 );
}
for (Atk = 0; Atk < 30; Atk++){
for (Def = 0; Def < 30; Def++)
fprintf(fp, "%16.8f", Table[Atk][Def]);
fprintf (fp, "\n");
}
fclose( fp );
return(EXIT_SUCCESS);
}
Your code
A_Ind = (int)(rand()*12);
D_Ind = (int)(rand()*12);
indicates that you seem to think that rand() returns a number in the range [0,1), which is not the case. Instead, int returns an integer in the range [0, RAND_MAX], so you need something like:
A_Ind = rand() * 12.0 / RAND_MAX;
If your simulation has to be statistically accurate, you are probably better off with a random number generator from the <random> library:
#include <random>
typedef std::mt19937 rng_type;
std::uniform_int_distribution<std::size_t> udist(0, 11);
rng_type rng;
// ...
// seed rng first:
rng.seed(some_seed_value);
// roll dice
std_size_t A_Ind = udist(rng), D_Ind = udist(rng);