How to remove redundant output - c++

My problem is this:
"Given a list of numbers and a number k, return whether any two numbers from the list add up to k.
For example, given [10, 15, 3, 7] and k of 17, return true since 10 + 7 is 17."
And wrote this code:
#include<iostream>
#include<iterator>
template<int N>
bool adding(int (&list)[N], int k) {
//get size of array
int length = (sizeof(list) / sizeof(list[0]));
std::cout << k << std::endl;
bool a = false;
//init 2 pointer on array
int *p1;
p1 = &list[0];
int *p2;
p2 = &list[0];
int sum = 0;
int lengthNew = length;
//check if p1+p2 = k
for (int i = 0; i < length; i++) {
for (int j = 0; j < lengthNew; j++) {
sum = *p1 + *p2;
if (p1 == p2) {
p2++;
j++;
}
else if (sum == k) {
std::cout << sum << " = " << k << "\t*p1= " <<*p1<<"\t*p2= "<< *p2 << std::endl;
a = true;
}
p2++;
}
p2 = p2 - length;
p1++;
}
return a;
}
int main() {
int myInts[] = { 19,1,2,18,13,4,10,5,5,12,7,10,8,16 };
int k = 21;
adding(myInts, k);
int w;
std::cin >> w;
return 0;
}
I get this output:
21 = 21 *p1= 19 *p2= 2
21 = 21 *p1= 2 *p2= 19
21 = 21 *p1= 13 *p2= 8
21 = 21 *p1= 5 *p2= 16
21 = 21 *p1= 5 *p2= 16
21 = 21 *p1= 8 *p2= 13
21 = 21 *p1= 16 *p2= 5
21 = 21 *p1= 16 *p2= 5
As you can see there are always two equal outputs. I know that it's because I am settin p2 back to the beginning, but I don't know how to do it otherwise. Could someone show me how to bypass the redundant information? I thought that i could save the addresses of the outputs and compare if this combination is already used. But I think it's not a good solution.

Because addition is commutative, you don't have to go through the whole array for every element.
It's enough to check all the elements after the element you're currently checking.
bool adding(const std::vector<int>& list, int k) {
bool result = false;
for (int i = 0; i < list.size(); i++) {
for (int j = i + 1; j < list.size(); j++) {
int sum = list[i] + list[j];
if (sum == k) {
std::cout << sum << " = " << k << "\tn1= " <<list[i]<<"\tn2= "<< list[j] << std::endl;
result = true;
}
}
}
return result;
}
Each pair of elements will be only compared once now.

Related

Sum the elements from a vector using a nested for loop

I'm trying to sum the values of a vector but I have a problem with that.
The size of the vector is 20 elements and I'm trying to do a sum of 5 elements from the current position.
Something like: sum the elements from 1 to 5, 2 to 6, 3 to 7 and so on.
I thought that I could do a for nested loop, like this one below:
for (int a = 0; a < numVec.size(); a++) {
for (int b = a; b < numVec.size(); b++)
{
if (aux < 5) {
cout << "B: " << b << endl;
sum += numVec[b].num;
}
if (aux > 4) {
aux = 0;
sumAux= sum;
sum= 0;
break;
}
aux++;
}
cout << "Sum: " << sumAux<< endl;
}
But I'm having some problems when I get the 15th position, everything goes wrong and I can't figure out why.
If you can help me, I thank you very much.
It will help you a lot, if you think for a longer time before start to code something. Maybe you can take a piece of paper and write something down.
Then, it will very much help you, if you choose long and speaking variable names.
So, let us make a picuture. We write some test values and their index in the vector, where they are stored. Please remeber. Indices start with 0 in C++.
Value: 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
Index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
So, and if we now want to build the sums for 5 values each, then we need to add
Index 0 1 2 3 4 Value: 21 22 23 24 25
Index 1 2 3 4 5 Value: 22 23 24 25 26
Index 2 3 4 5 6 Value: 23 24 25 26 27
. . .
Index 14 15 16 17 18 Value: 35 36 37 38 39
Index 15 16 17 18 19 Value: 36 37 38 39 40
So, you can see. We have a start index that always will be incremented by 1. Beginning with this start index, we will always add up 5 values. But we must end this process, as you can see above at index 15, so 20 - 5.So, always, size of the whole array - the size of the subarray.
So, let us first solve this problem we can do it strigh forward:
#include <iostream>
#include <vector>
int main() {
// Our test data to play with
std::vector<int> data = { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40 };
// This is the size of the subarray. So the number of values that we want to sum up
int sizeOfSubarray = 5;
// And because we have a subarray size, the last summation starts at this index
int lastIndex = data.size() - sizeOfSubarray;
// So, now iterate over all data that needs to be summed up
for (int startIndex = 0; startIndex <= lastIndex; ++startIndex) {
// Because we have a new start index now, we start also with a 0 sum
int sum = 0;
// Calculate the end index of the sub array
int endIndexOfSubarray = startIndex + sizeOfSubarray;
for (int sumIndex = startIndex; sumIndex < endIndexOfSubarray; ++sumIndex) {
// Some debug output
std::cout << "Startindex: " << startIndex << "\tSumindex: " << sumIndex << "\tValue: " << data[sumIndex] << '\n';
// Calculate the subarray sum
sum = sum + data[sumIndex];
}
// Show the subarray sum
std::cout << "Sum: " << sum << '\n';
}
}
OK, understood. What, if we want also to add up the end of the values of the array? So, what if the startindex will rund over the complete array. Let us look at this.
Index 16 17 18 19 ? Value: 37 38 39 40 ?
Index 17 18 19 ? ? Value: 38 39 40 ? ?
Index 18 19 ? ? ? Value: 39 40 ? ? ?
Index 19 ? ? ? ? Value: 40 ? ? ? ?
You can see, that the start index runs until < 20. So < size of vector.
And if the is the end index of the summation is > 19, so >= the sizeof the vector, we can limit it to 19,
This we can either calculate or use a simple if statement.
Then the code would look like that
#include <iostream>
#include <vector>
int main() {
// Our test data to play with
std::vector<int> data = { 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40 };
// This is the size of the subarray. So the number of values that we want to sum up
int sizeOfSubarray = 5;
// So, now iterate over all data that needs to be summed up
for (int startIndex = 0; startIndex < data.size(); ++startIndex) {
// Because we have a new start index now, we start also with a 0 sum
int sum = 0;
// Calculate the end index of the sub array
int endIndexOfSubarray = startIndex + sizeOfSubarray;
// If this index is too big ( > 20) then limit it to 20
if (endIndexOfSubarray > data.size()) {
endIndexOfSubarray = data.size();
}
// Claculate sum of sub array
for (int sumIndex = startIndex; sumIndex < endIndexOfSubarray; ++sumIndex) {
// Some debug output
std::cout << "Startindex: " << startIndex << "\tSumindex: " << sumIndex << "\tValue: " << data[sumIndex] << '\n';
// Calculate the subarray sum
sum = sum + data[sumIndex];
}
// Show the subarray sum
std::cout << "Sum: " << sum << '\n';
}
}
I hope, this explanation helps
One option is to have the inner loop range from 0-5
for (int a = 0; a < numVec.size(); a++) {
int sum = 0;
for (int b = 0; b < 5 && a + b < numVec.size(); b++) {
sum += numVec[a + b];
}
std::cout << sum << "\n";
}
Another option is to use std::accumulate
for (auto a = numVec.begin(); a < numVec.end(); a++) {
std::cout << std::accumulate(a, std::min(a + 5, numVec.end()), 0) << '\n';
}
Also, mentioned in the comments by #Bathsheba is to keep a running total, which is O(n).
int sum = 0;
for (int a = 0; a < 5 && a < numVec.size(); a++) sum += numVec[a];
std::cout << sum << '\n';
for (int a = 5; a < numVec.size(); a++) {
sum = sum - numVec[a - 5] + numVec[a];
std::cout << sum << '\n';
}
This is considered to be the rolling sum etc. You could write a template that manipulates a binary function on the vector specifying the window:
# include <iostream>
# include <numeric>
# include <vector>
# include <functional>
using namespace std;
template<class T, class Lambda>
vector<T> roll_fun(vector<T> vec, int window, Lambda&& func, T init){
int final_size = vec.size() - window + 1;
vector<T> result(final_size);
for (int k = 0; k < final_size; k++)
result[k] = accumulate(vec.begin() + k, vec.begin() + k + window, init, func);
return result;
};
int main()
{ vector<double> myvec{1,2,2.3,3,4,5,6,7,8,9,1,2,3,4,5,6,7};
//rolling sum
vector<double> v = roll_fun<double>(myvec, 5,plus<double>(), 0.0);
for(auto i: v) cout<<i<<' ';
cout<<endl;
// rolling mean
vector<double> v1 = roll_fun<double>(myvec, 5,[](double x, double y){return x+y/5;}, 0);
for(auto i: v1) cout<<i<<' ';
cout<<endl;
//rolling max
vector<double> v2 = roll_fun<double>(myvec, 5,[](double x, double y){return x>y?x:y;}, 0.0);
for(auto i: v2) cout<<i<<' ';
cout<<endl;
return 0;
}
The whole aux and sumAux handling is making your logic more complicated than it needs to be.
Try something more like this:
#include <algorithm>
const size_t size = numVec.size();
const size_t increment = 5;
for (size_t a = 0; a < size; ++a)
{
size_t stop = a + std::min(size-a, increment);
sum = 0;
for (size_t b = a; b < stop; ++b)
sum += numVec[b].num;
cout << "Sum: " << sum << endl;
}
Online Demo
Alternatively:
#include <algorithm>
#include <numeric>
auto end = numVec.end();
decltype(numVec)::difference_type increment = 5;
for (auto start = numVec.begin(); start != end; ++start)
{
auto stop = start + std::min(end-start, increment);
sum = std::accumulate(start, stop, 0,
[](auto a, const auto &elem){ return a + elem.num; }
);
cout << "Sum: " << sum << endl;
}
Online Demo

Print all combinations of a 3D vector

Suppose I have a vector<vector<vector<int> > > result.
The only size I know before hand is the inner and outer vector, which are of size k.
if I print result I get this (for k = 3):
i = 0
0 1 2
3 4 5
i = 1
6 7 8
9 10 11
12 13 14
i = 2
15 16 17
18 19 20
What I need to do is to print every combinations of k rows from each of vector of vectors of i's. In other words, what I need is the following output:
0 1 2
6 7 8
15 16 17
0 1 2
6 7 8
18 19 20
0 1 2
9 10 11
15 16 17
...
3 4 5
12 13 14
18 19 20
Hope I was clear about the desired output. I have tried a thousand of different loops, trying to save in another vector<vector<int> > but no success so far. I really am lost and any help would be greatly appreaciated.
The code to generate the above output is here:
(I'm sorry, I know it is an ugly code but it was the closest I could get to demonstrate my problem in a MCVE code)
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<vector<vector<int> > > result;
int k = 3;
vector<vector<int> > randomVectors;
//I'll create seven random vectors
//In my original problem, I don't have this number beforehand
int number = 0;
for(int i = 0; i < 7; i++){
vector<int> temp;
for(int j = 0; j < k; j++){
temp.push_back(number);
number++;
}
randomVectors.push_back(temp);
}
//Vector of vector to assign to "result"
vector<vector<int> > randomVectors_0;
randomVectors_0.push_back(randomVectors[0]);
randomVectors_0.push_back(randomVectors[1]);
vector<vector<int> > randomVectors_1;
randomVectors_1.push_back(randomVectors[2]);
randomVectors_1.push_back(randomVectors[3]);
randomVectors_1.push_back(randomVectors[4]);
vector<vector<int> > randomVectors_2;
randomVectors_2.push_back(randomVectors[5]);
randomVectors_2.push_back(randomVectors[6]);
result.push_back(randomVectors_0);
result.push_back(randomVectors_1);
result.push_back(randomVectors_2);
cout << "Printing the 3D vector" << endl;
for(int i = 0; i < k; i++){
cout << "i = " << i << endl << endl;
for(int j = 0; j < result[i].size(); j++){
for(int m = 0; m < k; m++){
cout << result[i][j][m] << " ";
}
cout << endl;
}
cout << endl;
}
return 0;
}
Compiler version: gcc (tdm-1) 4.7.1
I would make a rows_to_print vector that starts with all 0's. Then once a loop, it'll increment the last value by 1. If that value is greater than the size of the last vector, then reset it to 0 and increment the next value up the list, etc... you're done looping when every value in rows_to_print is greater than the size of each of the vectors:
void print_rows(std::vector<size_t> rows, std::vector<std::vector<std::vector<int>>> v) {
for(size_t x = 0; x < v.size(); x++) {
for(size_t y = 0; y < v.at(x).at(rows.at(x)).size(); y++) {
std::cout << v.at(x).at(rows.at(x)).at(y) << ' ';
}
std::cout << std::endl;
}
}
bool increment_rows(std::vector<size_t> &rows, std::vector<std::vector<std::vector<int>>> v) {
if(!rows.size()) return false; //empty rows, BAD
rows.at(rows.size() - 1)++;
for(int x = rows.size() - 1; x >= 0; x--) {
if(rows.at(x) >= v.at(x).size()) {
if(x <= 0) { return false; } //first row is done, then we're done!
rows.at(x-1)++; //increment previous row and set us back to 0 (overflow)
rows.at(x) %= v.at(x).size();
}
}
return true;
}
int main() {
...
std::vector<size_t> rows_to_print(k, 0);
print_rows(rows_to_print, result);
while(increment_rows(rows_to_print, result)) {
print_rows(rows_to_print, result);
}
}
See it in action here: ideone

Array that fills using a loop *AND swaps

I did this program in class and I'm trying to recreate it for an exam coming up. The program is supposed to be an array[2][10] and is supposed to output numbers in this order:
1 3 5 7 9 11 13 15 17 19
0 2 4 6 8 10 12 14 16 18
I'm really lost on this and I could really use any help.
#include<iostream>
#include <string>
#include <cstring>
using namespace std;
void out(int n[2][10]);
void fillit(int n[2][10]);
int main(){
int nums[2][10];
fillit(nums);
out(nums);
}
void fillit(int n[2][10]){
n[0][0] = 1;
n[1][0] = 0;
for (int i = 1; i < 10; i++){
n[0][i] = n[0][i] + 2;
n[1][i] = n[0][i] + 2;
}
}
void out(int n[2][10]){
for (int r = 0; r <= 1; r++){
for (int c = 0; c <= 9; c++){
cout << n[r][c];
}
cout << endl;
}
}
Update I have the program successfully filling the array but now I need the program to swap row 1 with row 2 and then output the new array. I.e.
0 2 4 6 8 10 12 14 16 18
1 3 5 7 9 11 13 15 17 19
void fillit(int n[2][10]){
for (int i = 0; i < 10; i++){
n[0][i] = (i * 2 ) + 1;
n[1][i] = i * 2;
}
}
#include<iostream>
#include <string>
#include <cstring>
using namespace std;
void out(int n[2][10]);
void fillit(int n[2][10]);
int main(){
int nums[2][10];
fillit(nums);
out(nums);
}
void fillit(int n[2][10]){
n[0][0] = 1;
n[1][0] = 0;
for (int i = 1; i < 10; i++){
n[0][i] = n[0][i-1] + 2;
n[1][i] = n[0][i-1] + 2;
}
}
void out(int n[2][10]){
for (int r = 0; r <= 1; r++){
for (int c = 0; c <= 9; c++){
cout << n[r][c];
}
cout << endl;
}
}
How about this, its shorter?
int nums[2][10];
for (int i = 0; i < 20; i++)
{
nums[(i%2)^1][i/2] = i;
}
I noticed that second array elements are even numbers, and the first array corresponding elements are one bigger (and thus odd) ... so this answer accomplishes using ONLY addition. Might be easier to understand.
void fillit(int n[2][10])
{
int even = 0; // start value
for (size_t i = 0; i < 10; i++)
{
int odd = even + 1;
n[0][i] = odd;
n[1][i] = even;
even += 2;
}
}
I noticed that you tagged this problem with C++. Perhaps you should try vectors.
For small vectors, you simply declare with initial values in curly-braces, making it easy to define the matrix limits [2] and [10]. In this example, I initialized using easy to recognize values, so you can tell the 2x10 matrix has not yet been filled. Without this init, the values contained will be random noise.
std::vector<std::vector<int>> n {
{ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }, // row 1
{ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 } // row 2
// 1 2 3 4 5 6 7 8 9 10 <-- col
};
Yes, you could write in the target value of your output, but then fillit() would not be needed.
For passing the 2x10 vector to fillIt(), remember that you need to mark the matrix as a reference. The following emphasizes that n[0] contains odd numbers, and n[1] contains 10 even numbers.
// vector x vector v--reference
void fillIt(std::vector<std::vector<int>>& n)
{
int even = 0;
for (size_t c = 0; c < 10; ++c) // row major {
int odd = even + 1;
n[0][c] = odd;
n[1][c] = even;
even += 2;
}
}
For test, I recommend just passing the 2x10 vector to a new function "showIt()".
// do not modify--vvvvv do not copy--v
void vec2x10Show (const std::vector<std::vector<int>>& n)
{
// header
std::cout << "\nCOL->";
for (int i=0; i<10; ++i) std::cout << std::setw(3) << i+1 << " ";
std::cout << "\nr1: "; // r c
for (int c=0; c<10; ++c) std::cout << std::setw(3) << n[0][c] << " ";
std::cout << "\nr2: "; // r c
for (int c=0; c<10; ++c) std::cout << std::setw(3) << n[1][c] << " ";
std::cout << std::endl;
}
Note the hard coded '10' in each loop (a magic number). Using vectors, this magic number is not necessary because the vector includes this information (your next assignment).

C++ - Strand sort using arrays only

I got a homework, to create a Strand sort algorithm in C++, but I'm not allowed to use lists, only arrays. I have trouble understanding the algorithm, because it was never explained to me, and Google yields limited information on this subject.
I've tried my best porting the code I found on Wikipedia, from PHP to C++, but It's not working correctly. It doesn't sort the array.
Here is my code, I know a lot of it is probably badly written, but it's the best I could do with my knowledge.
#include <iostream>
using namespace std;
void echoArray(int a[], int n) {
for(int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
}
//removes an element from array
int* array_remove(int* a, int& n, int index) {
int p = 0;
int* newArray = new int[n - 1];
for(int i = 0; i < n; i++) {
if(i != index) {
newArray[p] = a[i];
p++;
}
}
n--;
return newArray;
}
//adds an element to the end of an array
int* array_append(int* a, int& n, int el) {
int* newArray = new int[n+1];
int i = 0;
for(; i < n; i++) {
newArray[i] = a[i];
}
if(n == 0)
i = 0;
newArray[i] = el;
n++;
return newArray;
}
//inserts an element (el) to index p
int* array_insert(int* a, int& n, int p, int el) {
int c = 0;
n++;
int* newArray = new int[n];
for(int i = 0; i < n; i++) {
if(i != p) {
newArray[i] = a[c];
c++;
} else {
newArray[i] = el;
}
}
return newArray;
}
int* strandSort(int* a, int n) {
int arrC = n;
int resC = 0;
int subC = 0;
int* result = new int[1];
while(arrC > 0) {
subC = 0;
int* sublist = new int[1];
sublist = array_append(sublist, subC, a[0]);
a = array_remove(a, arrC, 0);
for(int i = 0; i < arrC; i++) {
if(a[i] > sublist[subC - 1]) {
sublist = array_append(sublist, subC, a[i]);
a = array_remove(a, arrC, i);
i--;
}
}
if(resC > 0) {
for(int i = 0; i < subC; i++) {
bool spliced = false;
for(int j = 0; j < resC - 1; i++) {
if(sublist[i] > result[j]) {
result = array_insert(result, resC, i, sublist[i]);
spliced = true;
break;
}
}
if(!spliced) {
result = array_append(result, resC, sublist[i]);
}
}
} else {
result = sublist;
resC = subC;
}
}
echoArray(result, resC);
return result;
}
int main() {
int a[] = {3, 20, 6, 1, 19, 21, 6, 11, 25, 6, 0, 1, 8, 7, 29, 26, 10, 29, 9, 5};
int n = 20;
strandSort(a, n);
return 0;
}
Also, I realize that arrays are passed by reference.
Use cout<< to target the problem
After read the wiki of Strand Sort, we know there is two parts of this algorithm.
Take out a relatively sorted list
Merge it with the result list
So you need to find which part is wrong, just add
cout << "step1: sublist = ";
echoArray(sublist, subC);
before if(resC > 0) { we will see step1 is right or wrong.
Add
cout << "step2: result = ";
echoArray(result, resC);
In the bottom of the while(arrC > 0) {} loop to check step2.
Get:
step1: sublist = 3 20 21 25 29
step2: result = 3 20 21 25 29
step1: sublist = 6 19 26 29
step2: result = 6 19 26 29 3 20 21 25 29
step1: sublist = 1 6 11
step2: result = 6 19 11 26 29 3 20 21 25 29
step1: sublist = 6 8 10
step2: result = 6 8 10 19 11 26 29 3 20 21 25 29
step1: sublist = 0 1 7 9
step2: result = 6 8 7 9 10 19 11 26 29 3 20 21 25 29
step1: sublist = 5
step2: result = 6 8 7 9 10 19 11 26 29 3 20 21 25 29 0
As we can see step1 is always right but the merge step is wrong.
So we will focus the code in if(resC > 0) {} block.
Read the code carefully
If you read your code carefully you will find in for(int j = 0; j < resC - 1; i++) { the i++ is nonsense.
And the merge step has many bugs, you need to rethink about it.
The fixed code of step 2:
if(resC > 0) {
int j = 0;
for(int i = 0; i < subC; i++) {
bool spliced = false;
for(;j < resC; j++) {
if(sublist[i] < result[j]) {
result = array_insert(result, resC, j++, sublist[i]);
spliced = true;
break;
}
}
if(!spliced) {
result = array_append(result, resC, sublist[i]);
}
}
} else {
result = sublist;
resC = subC;
}

c++ passing function as array index isn't working.

Why do the following two codes gives different results ?
the first one prints zeros, while the second print the random count as expected.
using gcc 4.6.3
8 int foo(){
9 return rand() % 2;
10 }
11
12 int main()
13 {
14 int ar[2] = {0};
15 for (int i = 0; i < 20; i++) {
16 // int tmp = foo();
17 // ar[tmp]++;
18 ar[foo()];
19 }
20
21 for (int i = 0; i < 2; i++)
22 cout << i << " : " << ar[i] << endl;
23 }
~
~
8 int foo(){
9 return rand() % 2;
10 }
11
12 int main()
13 {
14 int ar[2] = {0};
15 for (int i = 0; i < 20; i++) {
16 int tmp = foo();
17 ar[tmp]++;
18 // ar[foo()];
19 }
20
21 for (int i = 0; i < 2; i++)
22 cout << i << " : " << ar[i] << endl;
23 }
Because you don't actually increment the value in the array:
ar[foo()]++;
// ^
// You forgot this
This means all of the elements are left untouched and you get 0s as your output.