Passing a Truncated Vector by Reference - c++

I'm trying to figure out if there's a way to pass a truncated vector by reference so that it still changes the original vector.
Here's a simplified example of what I'm trying to do. I want the vector
x = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
when the function exits. When my code finishes, though, I get
{ 1, 8, 7, 6, 5, 4, 3, 2, 1, 0 }.
#include <iostream>
#include <vector>
using namespace std;
void example(vector<int> &x)
{
vector<int>::iterator ii = x.begin();
vector<int>::iterator jj = x.end();
if (ii == jj) { return; }
else {
*ii = 1;
example(vector<int>(ii + 1, jj));
}
}
int main()
{
vector<int> x = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
example(x);
for (vector<int>::iterator ii = x.begin(); ii != x.end(); ii++)
cout << *ii << " ";
cout << endl;
}
Any thoughts?

On this line
example(vector<int>(ii + 1, jj));
You are creating a new vector in each call, thus not altering the one passed in to the originating call.
I think if you want to pass part of a vector and retain the original vector you can either pass indexes or iterators.
Here are 2 possible solutions.
#include <iostream>
#include <vector>
using namespace std;
void example2(vector<int>& x, int ind = 0)
{
if (ind < x.size())
{
x[ind] = 1;
example2(x, ind + 1);
} else
{
return;
}
}
void example(vector<int>::iterator start, vector<int>::iterator end)
{
if (start == end)
{
return;
} else
{
*start = 1;
example(++start, end);
}
}
int main()
{
vector<int> x = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
example(x.begin(), x.end());
//example2(x);
for (vector<int>::iterator ii = x.begin(); ii != x.end(); ii++)
cout << *ii << " ";
cout << endl;
}

I see a recursion and any call of example(vector<int>(ii + 1, jj)); creates new vector (particularly this vector<int>(ii + 1, jj) is unnamed vector created on the base of initial x), so it is impossible to get in main what you want with your code

Related

How can I add an item to the structure with vector elements?

I would like to add the peak position of a vector and the peak number but I can't find a way to add the elements and then return it, or write it on console.
#include <iostream>
#include <vector>
using namespace std;
struct PeakData {
vector<int> pos, peaks;
};
PeakData pick_peaks(vector<int> v) {
PeakData result;
for (int i = 1; i < v.size() - 1; i++) {
if ((v[i] > v[i - 1]) && (v[i] > v[i + 1])) {
result.peaks.push_back(v[i]);
result.pos.push_back(i);
}
}
return result;
}
Example: pickPeaks([3, 2, 3, 6, 4, 1, 2, 3, 2, 1, 2, 3]) should return {pos: [3, 7], peaks: [6, 3]}
Add this to your main function:
int main()
{
vector<int> a = {3, 2, 3, 6, 4, 1, 2, 3, 2, 1, 2, 3};
PeakData stPickPeaks = pick_peaks(a);
vector<int> :: iterator itr;
for(itr = stPickPeaks.pos.begin(); itr<stPickPeaks.pos.end(); itr++)
{
cout <<*itr<<endl;
}
for(itr = stPickPeaks.peaks.begin(); itr<stPickPeaks.peaks.end(); itr++)
{
cout <<*itr<<endl;
}
return 0;
}
Also try to pass the parameters either by reference or pointer.

How do i remove duplicates from this recursion code? Many 6-sided dice will be rolled and print only unique combinations that add up to a desired sum

in the following code, I'm able to print all the dice combinations that add up to a desired sum. I'd like some help in tweaking the code to remove the duplicate entries.
void rep(int n, string ans, int currentSum, int targetSum)
{
if(n==0)
{
if(currentSum==targetSum)
cout << "{" << ans << "}"<<endl;
}
else
{
for(int i=1 ; i<=6 ; i++)
{
if(n>1)
{
rep(n-1, ans + to_string(i) + ", ", currentSum+i, targetSum);
}
else
{
rep(n-1, ans + to_string(i), currentSum+i, targetSum);
}
}
}
}
void ManyDiceSum(int howManyDice, int targetSum)
{
if(howManyDice>0)
rep(howManyDice,"",0,targetSum);
}
int main()
{
int howManyDice, targetSum;
howManyDice=3;
targetSum=7;
ManyDiceSum(howManyDice, targetSum);
return 0;
}
Output for 3 dice and target sum of 7 should be:
{1, 1, 5}
{1, 2, 4}
{1, 3, 3}
{2, 2, 3}
But, my code is displaying all combinations:
{1, 1, 5}
{1, 2, 4}
{1, 3, 3}
{1, 4, 2}
{1, 5, 1}
{2, 1, 4}
{2, 2, 3}
{2, 3, 2}
{2, 4, 1}
{3, 1, 3}
{3, 2, 2}
{3, 3, 1}
{4, 1, 2}
{4, 2, 1}
{5, 1, 1}
Constraints are: It has to use recursion and use only 1 loop if
necessary.
First of all you do not need to pass both target and current sum to the function, only target is enough, and checking it first will speed up whole process significantly:
void rep( int n, int target, std::string ans = std::string(), int last = 1 )
{
if( n == 0 ) {
if( target == 0 )
std::cout << "{" << ans << "}" << std::endl;
return;
}
const auto limit = std::min( 6, target );
// or even following, but not sure this is quite right though
//const auto limit = std::min( 6, target - n * last );
for( int i = last ; i <= limit; ++i )
rep(n-1, target - i, ans + to_string(i) + ( n > 1 ? ", " : "" ), i );
}
void ManyDiceSum( int howManyDice, int TargetSum )
{
if (howManyDice > 0)
rep( howManyDice, TargetSum );
}
and to avoid duplicates continue from the last number you started.
A exemplary solution based on #Jarod42's comment:
void rep(int n, std::string ans, int currentSum, int TargetSum, int startFrom) {
if (n == 0) {
if (currentSum == TargetSum)
std::cout << "{" << ans << "}" << std::endl;
} else
for (int i = startFrom; i <= 6; i++)
if (n > 1)
rep(n-1, ans + to_string(i) + ", ", currentSum + i, TargetSum, i);
else
rep(n-1, ans + to_string(i), currentSum + i, TargetSum, i);
}
void ManyDiceSum(int howManyDice, int TargetSum) {
if (howManyDice > 0)
rep(howManyDice, "", 0, TargetSum, 1);
}

C/C++ - efficient method of rotating an array without using build-in functions (homework)

The task is to rotate left or rotate right a subarray of an array given number of times.
Let me explain this on an example:
lets data be an array.
data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
a sub array is determined by parameters begin and end.
if begin = 3 and end = 7, then subarray is {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
if begin = 7 and end = 3, then subarray is {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
let's rotate it right two times
if begin = 3 and end = 7, then the result is {0, 1, 2, 6, 7, 3, 4, 5, 8, 9};
if begin = 7 and end = 3, then the result is {8, 9, 0, 1,, 4, 5, 6, 2, 3, 7};
I've written code that performs this task but it's to slow.
Can someone give me a hint how to make it quicker?
Important: I'm not allowed to use other arrays than data, subprograms and build-in functions.
#include <iostream>
using namespace std;
int main(){
int dataLength;
cin >> dataLength;
int data [ dataLength ];
for (int i = 0; i < dataLength; i++){
cin >> data [ i ];
}
int begin;
int end;
int rotation;
int forLoopLength;
int tempBefore;
int tempAfter;
cin >> begin;
cin >> end;
cin >> rotation;
if (end > begin)
forLoopLength = (end - begin) + 1;
else
forLoopLength = (end - begin) + 1 + dataLength;
if (rotation < 0)
rotation = forLoopLength + (rotation % forLoopLength);
else
rotation = rotation % forLoopLength;
for (int i = 0; i < rotation; i++) {
tempBefore = data [ end ];
for (int i = 0; i < forLoopLength; i++) {
tempAfter = data [ (begin + i) % dataLength ];
data [ (begin + i) % dataLength ] = tempBefore;
tempBefore = tempAfter;
}
}
for (int i = 0; i < dataLength; i ++ ) {
cout << data [ i ] << " ";
}
return 0;
}
There's a trick to this. It's pretty weird that you'd get this for homework if the trick wasn't mentioned in class. Anyway...
To rotate a sequence of N elements left by M:
reverse the whole sequence
reverse the last M elements
reverse the first N-M elements
done
e.g. left by 2:
1234567
->
7654321
->
7654312
->
3456712
Here is my code, it makes exactly n reads and n writes, where n is subarray size.
#include<iostream>
int arr[]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// replacing 'addr( pos, from, size )' with just 'pos' mean rotation the whole array
int addr( int ptr, int from, int size)
{
return (ptr + from ) % size;
}
void rotate( int* arr, int shift, int from, int count, int size)
{
int i;
int pos= 0;
int cycle= 0;
int c= 0;
int c_old= 0;
// exactly count steps
for ( i=0; i< count; i++ ){
// rotation of arrays part is essentially a permutation.
// every permutation can be decomposed on cycles
// here cycle processing begins
c= arr[ addr( pos, from, size ) ];
while (1){
// one step inside the cycle
pos= (pos + shift) % count;
if ( pos == cycle )
break;
c_old= c;
c= arr[ addr( pos, from, size ) ];
arr[ addr( pos, from, size ) ]= c_old;
i++;
}
// here cycle processing ends
arr[ addr( pos, from, size ) ]= c;
pos= (pos + 1) % count;
cycle= (cycle + 1) % count;
}
}
int main()
{
rotate( arr, 4, 6, 6, 11 );
int i;
for ( i=0; i<11; i++){
std::cout << arr[i] << " ";
}
std::cout << std::endl;
return 0;
}

Merge Sort Algorithm Assistance

I'm trying to implement the merge-sort algorithm. I started with pseudocode that was available in an algorithms book. The pseudocode indicates the first position in the array as 1 and not 0. I am having a very difficult time trying to implement the code.
Here is what I have. I've tried stepping through the recursion by printing out the results at each step but it is very convoluted at this point.
#include <iostream>
#include <deque>
using size_type = std::deque<int>::size_type;
void print(std::deque<int> &v)
{
for(const auto &ref:v)
std::cout << ref << " ";
std::cout << std::endl;
}
void merge(std::deque<int> &vec, size_type p, size_type q, size_type r)
{
int n_1 = q - p;
int n_2 = r - q;
std::deque<int> left, right;
for(auto i = 0; i != n_1; i++)
left.push_back(vec[p + i]);
for(auto j = 0; j != n_2; j++)
right.push_back(vec[q + j]);
int i = 0, j = 0;
std::cout << "left = ";
print(left);
std::cout << "right = ";
print(right);
for(auto k = p; k != r; k++) {
if((i != n_1 && j != n_2) && left[i] <= right[j]) {
vec[k] = left[i];
i++;
}
else if(j != n_2){
vec[k] = right[j];
j++;
}
}
}
void merge_sort(std::deque<int> &A, size_type p, size_type r)
{
int q;
if(p < r - 1) {
q = (p + r)/2;
merge_sort(A, p, q);
merge_sort(A, q + 1, r);
merge(A, p, q, r);
}
}
int main()
{
std::deque<int> small_vec = {1, 6, 2, 10, 5, 2, 12, 6};
std::deque<int> samp_vec = {2, 9, 482, 72, 42, 3, 4, 9, 8, 73, 8, 0, 98, 72, 473, 72, 3, 4, 9, 7, 6, 5, 6953, 583};
print(small_vec);
merge_sort(small_vec, 0, small_vec.size());
print(small_vec);
return 0;
}
I get the following output when I run the program:
left = 1
right = 6
left = 1 6
right = 2 10
left = 2
right = 12 6
left = 1 2 6 10
right = 5 2 12 6
1 2 5 2 6 10 12 6
The error is here: (i != n_1 && j != n_2) && left[i] <= right[j]) when i != n_1 evaluates to false vec[k] = right[j]; is executed - correct.
But if i != n_1 evaluates to true and j != n_2 to false i.e. j = n_2 your program trys to do this vec[k] = right[j]; again i.e. accesing over the bounds of your deque.
Rewrite your for loop as follows:
if (i<n_1 && (j>=n_2 || left[i] <= right[j])
This loop works only due to C++'s short circuiting of the conditions i.e. when j>=n_2 evaluates to true, left[i] <= right[j] is never checked again and you don't access the deque over bounds.
left[i] <= right[j] is being checked only if both i<n_1 is true and j>=n_2 false otherwise the 2nd branch is executed.
After spending a lot of time and getting some valuable help on another post was able to get the algorithm to run correctly.
CORRECT CODE:
#include <iostream>
#include <deque>
using size_type = std::deque<int>::size_type;
void print(std::deque<int> &v)
{
for(const auto &ref:v)
std::cout << ref << " ";
std::cout << std::endl;
}
void print(int arr[], int size)
{
for(int i = 0; i != size; i++)
std::cout << arr[i] << " ";
std::cout << std::endl;
}
void merge(std::deque<int> &vec, size_type p, size_type q, size_type r)
{
int n_1 = q - p + 1;
int n_2 = r - q;
std::deque<int> left, right;
int i = 0, j = 0;
while(i < n_1)
left.push_back(vec[p + i++]);
while(j < n_2)
right.push_back(vec[j++ + q + 1]);
i = 0; j = 0;
//std::cout << "left = ";
//print(left);
//std::cout << "right = ";
//print(right);
for(auto k = p; k <= r; k++) {
if((i < n_1 && left[i] <= right[j]) || j >= n_2) {
vec[k] = left[i++];
}
else if(j < n_2){
vec[k] = right[j++];
}
}
}
void merge_sort(std::deque<int> &A, size_type p, size_type r)
{
int q;
if(p < r) {
q = (r + p) / 2;
std::cout << "q = " << q << std::endl;
//std::cout << "p = " << p << std::endl;
merge_sort(A, p, q);
merge_sort(A, q + 1, r);
merge(A, p, q, r);
}
}
int main()
{
std::deque<int> small_vec = {10, 3, 6, 4, 1, 5, 3, 9, 7, 2, 8};
std::deque<int> samp_vec = {2, 9, 482, 42, 3, 4, 9, 8, 73, 8, 0, 98, 72, 473, 72, 3, 4, 9, 7, 6, 5, 6953, 583};
print(samp_vec);
merge_sort(samp_vec, 0, samp_vec.size() - 1);
print(samp_vec);
return 0;
}

Dijkstra's Shortest Path Algorithm issue

So I'm trying to code Dijkstra's shortest path algorithm in C++. For some reason, it's not adding up the distances correctly...
Here is what I have so far for code. You can ignore the section where I am copying the path to the stack because I know it's not complete yet. Any ideas where I'm going wrong?
#include <fstream>
#include "matrix.h"
#include <list> // STL container
using namespace std;
//---------------------------------------------------------------------------
const int INFIN = 100000;
const int size = 8;
double a[] = {
0, 0, 5, 0, 0, 2, 3, 0, //length matrix ( #9, page 276)
4, 0, 6, 0, 7, 0, 5, 0,
0, 3, 0, 9, 2, 6, 0, 7,
3, 0, 2, 0, 1, 0, 7, 6,
0, 5, 0, 1, 0, 0, 4, 0,
0, 0, 2, 0, 8, 0, 9, 0,
1, 2, 3, 0, 0, 6, 0, 0,
5, 0, 8, 0, 2, 0, 9, 0
};
// Global declarations for L Matrix and begin and end node
Matrix L(size,size,a); //length matrix
int begin, end;
void path(long* D, int* P); //function prototype for shortest path algorithm
Matrix Warshall(Matrix M);
void main()
{
int i, u;
long D [size+1]; //distance functions
int P [size+1]; //prior vertices in path
cout << "\nLength Matrix: " << L;
cout << "\nPaths that exist:" << Warshall(L);
for (i=1; i <= size; i++) {
D[i] = INFIN; //initialize distance functions
P[i] = 0;
}
cout << "\nFind distance from vertex #";
cin >> begin;
cout << " to vertex #";
cin >> end;
if (begin == end) exit(1);
if (begin < 0 || end < 0) exit(1);
if (begin > size || end > size) exit(1);
path(D,P);
cout << "\nShortest distance from \nvertex #"
<< begin << " to vertex #"
<< end << " is " << D[end];
// u = end;
list<int> stack; // work path backwards
while (1) {
stack.push_front(end);
stack.push_front(begin);
break;
}
cout << "\nusing path:\n";
cout << "\t" << stack.front();
stack.pop_front();
while (stack.size()) {
cout << " -> " << stack.front();
stack.pop_front();
}
getch();
}
void path(long* D, int* P) {
int i, u, dist;
int U[size+1];
for (i=1; i <= size; i++)
U[i] = 0;
U[begin] = 1; // add first vertex;
D[begin] = 0;
u = begin;
do { // until find end vertex
for (i = 1; i <= size; i++) {
dist = L.element(u,i); // distance from u to i
if( D[u] + dist < D[i]) {
D[i] = D[u] + dist;
P[i] = u;
}
}
dist = 38000; // reset distance value to large value
int min;
for(i = 1; i <= size; i++) {
if(L.element(u,i) != 0) {
if(L.element(u,i) < dist && U[i] != 1) {
dist = L.element(u,i);
min = i;
}
}
}
u = min;
U[u] = 1;
cout << "Min is " << min << endl;
} while (u != end);
}
if( D[u] + dist < D[i]) {
D[i] = D[u] + dist;
P[i] = u;
}
should be
if( D[u] + dist < D[i] && dist != 0) {
D[i] = D[u] + dist;
P[i] = u;
}