C++ counting number of positive/negative numbers from an array - c++

I'm trying to create a code that counts the number of positive and negative numbers from a given array using a function. For example in the array {-1, 2, -3, 4.5 , 0, .3, -999.99} it's supposed to show 2 positive numbers, and 4 negative numbers and excludes the number 0.
I'm using two counters to keep track of how many negative and positive numbers, a for loop to cycle through the array, but I don't know how to incorporate the boolean parameter when true or false is called on to display the right counter.
My code isn't outputting the right information and any tips would be help on how to improve my code.
#include <iostream>
using namespace std;
int countingArray(float list[], int size, bool)
{
int NumberOfPositives = 0;
int NumberOfNegatives = 0;
for (int index = 0; index < size; index++) {
if (list[index] > 0) {
if (true) {
NumberOfPositives++;
}
}
else if (list[index] < 0) {
if (false) {
NumberOfNegatives++;
}
}
else if (list[index] == 0)
continue;
}
return NumberOfPositives;
return NumberOfNegatives;
}
int main()
{
float list[] = { -1, 2, -3, 4.5, 0, -3, -999.99 };
cout << "# of Pos. = " << countingArray(list, 7, true) << endl;
cout << "# of Pos. = " << countingArray(list, 7, false) << endl;
system("PAUSE");
return 0;
}

You cannot return 2 values. Once you return, that function immediately ends.
Therefore, countingArray will only return the number of positive numbers you have, as return NumberOfPositives occurs before return NumberOfNegatives.

I would have wrote it this way:
void countingArray(float list[], int size, int& positive, int& negative) {
for (int index = 0; index < size; index++)
if (list[index] > 0)
++positive;
else if (list[index] < 0)
++negative;
}
int main() {
float list[] = { -1, 2, -3, 4.5, 0, -3, -999.99 };
int positive = 0;
int negative = 0;
countingArray(list, 7, positive, negative);
cout << "# of Pos. = " << positive << endl;
cout << "# of Pos. = " << negative << endl;
system("PAUSE");
return 0;
}
Pass the counters by reference so you don't loop array twice.
And your problem is you return twice from your function if doing it your way you need to check the boolean flag before returning and return positive or negative counter based on your flag.
Also, you can use std::array instead c type array, that way you can loop through array using iterator and you won't need to pass array size.

Something like this would do it:
#include <iostream>
struct PosNeg
{
void reset()
{
p = n = z = 0;
}
int p; // Positive.
int n; // Negative.
int z; // Zero.
};
void pos_neg(float* arr, int sz, PosNeg& count)
{
for (int i = 0; i < sz; ++i)
{
if (arr[i] < 0)
{
count.n++;
}
else if (arr[i] == 0)
{
count.z++;
}
else
{
count.p++;
}
}
}
int main()
{
float arr[] = { 1.0f, 2.0f, 3.0f, 0.0f, -1.0f, -2.0f, -3.0f };
PosNeg pn;
pn.reset();
pos_neg(arr, 7, pn);
std::cout << "Pos: " << pn.p << " Neg: " << pn.n << " Zero: " << pn.z << "\n";
std::cin.get();
return 0;
}
Encompass everything into a struct and count positive, negative number and eventually 0.
Remember that you have to set each member of the struct to zero before using it (random by default when initialized).

You might do, with std:
std::pair<std::size_t, std::size_t> countingNegPos(const float* v, std::size_t size)
{
return { std::count_if(v, v + size, [](auto f){ return f < 0; }),
std::count_if(v, v + size, [](auto f){ return f > 0; })};
}
int main()
{
const float list[] = { -1, 2, -3, 4.5, 0, -3, -999.99 };
auto [neg, pos] = countingArray(list, 7);
std::cout << "# of Neg. = " << neg << std::endl;
std::cout << "# of Pos. = " << pos << std::endl;
}

Related

greedy and optimal solution for maximum sub interval in certain range

I tried to get first a greedy solution for me handling reservation buy getting 2 days (start, end) and getting the maximum days that can be reserved without the interval being overlap
#include <algorithm>
#include <iostream>
using namespace std;
struct Interval {
int start, end;
};
// Compares two intervals
// according to starting times.
bool comparesorting(Interval i1, Interval i2)//sorting
{
return (i1.end < i2.end);
}
bool compareoverlap(Interval i1, Interval i2)//overlap
{
return (i1.start < i2.start) ? true : false;
}
bool isIntersect(Interval arr[], int n)
{
// Sort intervals in increasing order of start time
sort(arr, arr + n, compareoverlap);
// In the sorted array, if start time of an interval
// is less than end of previous interval, then there
// is an overlap
for (int i = 1; i < n; i++)
if (arr[i - 1].end > arr[i].start)
//return true;
if (true) {
for (int i = 0; i < n; i++)
cout << "mmmm" << endl;
cout << "[" << arr[i].start << "," << arr[i].end
<< "] ";
}
// If we reach here, then no overlap
return false;
}
int main()
{
Interval arr[]
= { { 6, 8 }, { 7, 9 }, { 2, 4 }, { 4, 7 } , { 1,9 } , {6,9} ,{2,6} , {1,10} };
int n = sizeof(arr) / sizeof(arr[0]);
// sort the intervals in increasing order of
// start time
sort(arr, arr + n, comparesorting);
cout << "Intervals sorted : \n";
for (int i = 0; i < n; i++)
cout << "[" << arr[i].start << "," << arr[i].end
<< "] ";
int n1 = sizeof(arr) / sizeof(arr[0]);
isIntersect(arr, n1) ? cout << "Yes\n" : cout << "No\n";
return 0;
}
the output should be {2,4} {4,7} (that does not overlap)
I'm trying to make an optimal solution to solve this problem. I'm thinking to subtract the end - start and compare it to the addition of this greedy solution
please help I'm stuck!!!!

C++ multiple returns from single function

still pretty new to C++.
Had to write a function in class to count the number of each digit in a multi-dimensional array.
Now I didn't think you could return multiple int values from a single called function and then use all of these returns in a text based answer, so I attempted to return a different value depending on the value requested as parameter for each digit.
The code below is unnecessarily long and I'm still receiving the following errors.
main-1-3.cpp: In function 'int main()':
main-1-3.cpp:12:21: error: too few arguments to function 'int
count_numbers(int(*)[4], int)'
count_numbers(array);
^
main-1-3.cpp:7:12: note: declared here
extern int count_numbers(int array[4][4], int);
With a bit of debugging I could likely fix up these compile errors, but I feel like my method is extremely convoluted and was wondering if it were possible to call the function as:
count_number(array[4][4])
(Removing the need for the Q parameter) and then have count_numbersreturn all ten of the number values and the just output them as text like << ",3:" << three << instead of << ",8:" << count_numbers(array, 8) <<
Anyway, the function.cpp and main.cpp are below.
If anyone could point me in the right direction it would greatly appreciated. Just need to know the correct method so I can condense this code.
function.cpp
#include <iomanip>
#include <locale>
#include <sstream>
#include <string>
#include <iostream>
int count_numbers(int array[4][4], int Q)
{
int X=0;
int Y=0;
int zero=0;
int one=0;
int two=0;
int three=0;
int four=0;
int five=0;
int six=0;
int seven=0;
int eight=0;
int nine=0;
while(X<4)
{
if(array[X][Y]==0)
{
zero=zero+1;
}
if(array[X][Y]==1)
{
one=one+1;
}
if(array[X][Y]==2)
{
two=two+1;
}
if(array[X][Y]==3)
{
three=three+1;
}
if(array[X][Y]==4)
{
four=four+1;
}
if(array[X][Y]==5)
{
five=five+1;
}
if(array[X][Y]==6)
{
six=six+1;
}
if(array[X][Y]==7)
{
seven=seven+1;
}
if(array[X][Y]==8)
{
eight=eight+1;
}
if(array[X][Y]==9)
{
nine=nine+1;
}
Y++;
if(Y==4)
{
Y=0;
X++;
}
}
if(Q==0)
{
return zero;
}
if(Q==1)
{
return one;
}
if(Q==2)
{
return two;
}
if(Q==3)
{
return three;
}
if(Q==4)
{
return four;
}
if(Q==5)
{
return five;
}
if(Q==6)
{
return six;
}
if(Q==7)
{
return seven;
}
if(Q==8)
{
return eight;
}
if(Q==9)
{
return nine;
}
}
main.cpp
#include <iomanip>
#include <locale>
#include <sstream>
#include <string>
#include <iostream>
extern int count_numbers(int array[4][4], int);
int array[4][4] = { {1,2,3,4} , {1,2,3,4} , {1,2,3,4} , {1,2,3,4}};
int main()
{
count_numbers(array);
std::cout << ",0:" << count_numbers(array, 0) << ",1:" << count_numbers(array, 1) << ",2:" << count_numbers(array, 2) << ",3:" << count_numbers(array, 3) << ",4:" << count_numbers(array, 4) << ",5:" << count_numbers(array, 5) << ",6:" << count_numbers(array, 6) <<",7:" << count_numbers(array, 7) << ",8:" << count_numbers(array, 8) << ",9:" << count_numbers(array, 9) << std::endl;
}
PS. Ignore incorrect indentation its just from pasting to this site
PPS. Thanks for any assistance.
EDIT
Thank you "Vlad From Moscow" for the assistance.
My initial (terrible) code would have worked if I'd simply removed the (unintentional) count_number(array); call from main.cpp
However the for loop system proposed by Vlad allowed me to shrink the code by 80%. It now looks like this:
int count_numbers(int array[4][4], int Q)
{
int ans=0;
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
{
ans += array[i][j] ==Q;
}
}
return ans;
}
Thank you for the assistance which was great, I began coding on Python so it was my lack of understanding of loops in C++ which was the real problem here.
Anyway, problem solved..
This call
count_numbers(array);
does not make sense and moreover is invalid because the function requires two arguments instead of one.
The function itself can be written the following way
const size_t N = 4;
size_t count_number( const int ( &a )[N][N], int value )
{
size_t n = 0;
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
n += a[i][j] == value;
}
}
return n;
}
and called like
std::cout << "0: " << count_number( array, 0 )
<< ", 1: " << count_number( array, 1 )
<< ", 2: " << count_number( array, 2 )
<< ", 3: " << count_number( array, 3 )
<< ", 4: " << count_number( array, 4 )
<< ", 5: " << count_number( array, 5 )
<< ", 6: " << count_number( array, 6 )
<< ", 7: " << count_number( array, 7 )
<< ", 8: " << count_number( array, 8 )
<< ", 9: " << count_number( array, 9 )
<< std::endl;
Here is a demonstrative program
#include <iostream>
const size_t N = 4;
size_t count_number( const int ( &a )[N][N], int value )
{
size_t n = 0;
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
n += a[i][j] == value;
}
}
return n;
}
int main()
{
int array[N][N] =
{
{ 1, 2, 3, 4 } ,
{ 1, 2, 3, 4 } ,
{ 1, 2, 3, 4 } ,
{ 1, 2, 3, 4 }
};
bool first = true;
for ( int value = 0; value < 10; ++value )
{
size_t n = count_number( array, value );
if ( n )
{
std::cout << ( first ? first = false, "" : ", " )
<< value << ": " << n;
}
}
std::cout << std::endl;
}
Its output is
1: 4, 2: 4, 3: 4, 4: 4
A more general approach can look the following way
#include <iostream>
#include <iterator>
#include <algorithm>
template <typename InputIterator, typename T>
size_t count_number( InputIterator first,
InputIterator last,
const T &value )
{
size_t n = 0;
for ( ; first != last; ++first )
{
n += std::count( std::begin( *first ), std::end( *first ), value );
}
return n;
}
int main()
{
const size_t N = 4;
int array[N][N] =
{
{ 1, 2, 3, 4 } ,
{ 1, 2, 3, 4 } ,
{ 1, 2, 3, 4 } ,
{ 1, 2, 3, 4 }
};
bool first = true;
for ( int value = 0; value < 10; ++value )
{
size_t n = count_number( std::begin( array ), std::end( array ), value );
if ( n )
{
std::cout << ( first ? first = false, "" : ", " )
<< value << ": " << n;
}
}
std::cout << std::endl;
}
The program output will be the same as it is shown above.
If the array contains only digits that you need to count then the function can look like
const size_t N = 4;
void count_digits( const int ( &a )[N][N], size_t ( &digits)[10] )
{
for ( size_t &x : digits ) x = 0;
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
++digits[a[i][j]];
}
}
}
To call the function you need to declare in main an array like for example
size_t digits[10];
you can return int[] or event better since you are using c++ return vector<int>.
In your function you can replace one, two, .. with something like
vector<int> result(10);
This will create a vector with 10 entries, all of them 0.
Then replace thing like three = three + 1 with result[3] = result[3] + 1 or even more condensed result[3]++
Then at the end you can write ... << ",0:" << result[0] << ... or even do a for loop like:
for (int i = 0; i < 10; ++i) count << "," << i << ":" << result[i];
You can do all this with int[] as well if that's required but you need to take care of allocating and deallocating the memory. vector will simplify your code a lot.

How to move elements in an array, putting odds to the beginning of the array (smallest to largest), and evens to the back ( largest to smallest )

I have to write a functioncalled moveAndSortInt() that will receive an array of integers as an argument, and move all the even values down to the second half of the array and sort them from largest to smallest, while all the odd values will be sorted from smallest to largest. How can I improve my code?
#include <iostream>
using namespace std;
void moveAndSortInt(int[], int);
void displayName();
int main() {
int ary1[] = { -19, 270, 76, -61, 54 };
int size = 5;
int i;
int ary2[] = {9, 8, -103, -73, 74, 53};
int size2 = 6;
int j;
displayName();
cout << endl;
cout << "Original ary1[]" << endl;
for (i = 0; i < size; i++) {
cout << " " << ary1[i] << " ";
}
cout << endl;
cout << "\nCallingMoveAndSortInt() --\n " << endl;
moveAndSortInt(ary1, size);
cout << "Updated ary1[]" << endl;
for (i = 0; i < size; i++) {
cout << " " << ary1[i] << " ";
}
cout << endl;
cout << "\nOriginal ary2[]" << endl;
for (j = 0; j < size2; j++) {
cout << " " << ary2[j] << " ";
}
cout << endl;
cout << "\nCallingMoveAndSortInt() --\n" << endl;
moveAndSortInt(ary2, size2);
cout << "Updated ary2[]" << endl;
for (j = 0; j < size2; j++) {
cout << " " << ary2[j] << " ";
}
}
void moveAndSortInt(int ary[], int size) {
int i, j;
int temp;
for (i = 0; i < 1 + size / 2; i++) {
if (ary[i] % 2 == 0) {
for (j = size - 1; j > size / 2; j--) {
if (ary[j] % 2 != 0) {
temp = ary[i];
ary[i] = ary[j];
ary[j] = temp;
j = 0;
}
}
}
}
return;
I would suggest using std::sort, the standard algorithm for sorting, which is often implemented with a Quicksort. It is very fast, and also supports custom comparison. Here's some code to get you started:
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> data = { 2, 213, 2, 2, 3 ,123, 4, 213, 2132, 123 };
std::sort(data.begin(), data.end(), [](int lhs, int rhs)
{
if (lhs % 2) // if lhs is odd
if (rhs % 2) // and rhs is odd then just use comparision
return lhs < rhs;
else // and if rhs is even then rhs is "bigger"
return false;
else // if lhs is even
if (rhs % 2)
return true; // and rhs is odd then lhs is "bigger"
else // and if they are both even just use comparision.
return lhs < rhs;
});
}
I'm sorry if that code is a little hard to read, but it does the trick.
This of course would work with C-style arrays too, just replace data.begin() with data and data.end() with data + size.
Alright, so I looked at it a bit. Let's start with conventions.
int i;
for (i = 1; i < 10; i++)
Can be shortened to:
for (int i = 1; i < 10; i++)
Which looks better and is more readable. It would also be nice to have a few more comments, but that's something everyone needs to get better at, no matter how good they are.
So it seems that your code does correctly sort the array into even and odd halves. That's all you need to do yourself as long as you know where they end because sorting them largest to smallest is something that std::sort can do for you.
Edit: It was pointed out to me that my previous example is not exactly the same, as with the second one i can only be used in the loop. For your purposes, they work the same.
You can just reorder it
#include <algorithm>
#include <climits>
#include <iostream>
#include <vector>
int main()
{
auto const shuffle = [] (int input)
{
if ( input % 2 )
{
unsigned const dist_from_min = (unsigned)input - INT_MIN;
return dist_from_min >> 1;
}
else
{
unsigned const dist_from_max = INT_MAX - (unsigned)input;
return INT_MIN + (dist_from_max >> 1);
}
};
auto const ordering = [shuffle] (int left, int right)
{ return shuffle (left) < shuffle (right); };
std::vector <int> data =
{ 5, 2, 3, 0, -1, -3, 1, 100
, INT_MIN, INT_MIN + 1, INT_MAX, INT_MAX - 1
, -567, -765, 765, 567, -234, -432, 234, 432
};
std::sort ( data.begin ( ), data.end ( ), ordering );
for ( auto item : data )
std::cout << item << "\n";
}

Merge sort code debugging

I am trying to write a code for merge sort. I am not getting the correct output. I am following this pseudocode link Following is my code. I pass my unsorted array into merge_sort function and call merge function recursively to sort and combine the sub arrays.I know there are more simpler and efficient ways to write code for merge sort but I want to try on my own otherwise I won't learn. Thanks in advance.
int* merge_sort(int* a,int size)
{
//cout<<size;
//cout<<"hi";
if(size == 1)
{
//cout<<"less";
//cout<<a[0];
return a;
}
int* left;
int* right;
int middle = ceil(size/2);
left = new int(middle);
right = new int(middle);
for(int i=0;i<middle;i++)
{
left[i]=a[i];
//cout<<left[i];
}
cout<<"\t";
for(int j=middle;j<size;j++)
{
right[j]=a[j];
//cout<<right[j];
}
cout<<"\t";
left = merge_sort(left,middle);
//if(size==2)
//cout<<left[0];
right = merge_sort(right,middle);
//if(size==2)
//cout<<right[0];
return merge(left,right,middle);
}
int* merge(int* l,int* r,int m)
{
int* result;
result = new int(2*m); //to store the output
int lsize=m; // to keep track of left sub list
int rsize=m; // to keep track of right sub list
int counter = 0; // will use to index result
//cout<<m;
while(lsize>0 || rsize>0)
{
if(lsize>0 && rsize>0)
{
if(l[0]<=r[0])
{
result[counter]=l[0];
counter++; //to store next value in result
lsize--;
l=&l[1]; //decrementing the size of left array
}
else
{
result[counter]=r[0];
counter++;
rsize--;
r=&r[1]; //dec. size of right array
}
}
else if(lsize>0)
{
result[counter]=l[0];
counter++;
lsize--;
l=&l[1];
}
else if(rsize>0)
{
result[counter]=l[0];
counter++;
lsize--;
l=&l[1];
}
}
return result;
}
Your code:
int *left = new int(middle);
allocates a single integer initialized to middle. You need:
int *left = new int [middle];
which allocates an array of middle integers. Rinse and repeat for int *right. Actually, you need to use:
int *right = new int [size - middle];
This gets the correct size for the right array. You then have to modify the recursive call to merge_sort() for the right sub-array:
merge_sort(right, size - middle);
Finally, you have to rewrite merge() to take the size of the left array and the size of the right array independently, because they may be of different sizes. For example, if you sort 10 elements,
you then end up with a call to merge two arrays of 5 (which is fine), but at the next level you need to merge an array of 2 and an array of 3 elements (and you're hosed).
The allocation of result also has the () vs [] allocation problem. And there are some other as yet unresolved problems. But these are important steps in the right direction.
As mentioned in a comment to the question, you have a monumental memory leakage problem, too. What's more, it is not trivial to fix because merge_sort() does an early exit without allocating new memory, so it isn't as simple as 'delete the memory returned by merge_sort()'.
Copy and paste is wonderful until you forget to edit the pasted copy correctly:
else if (lsize > 0)
{
result[counter] = l[0];
counter++;
lsize--;
l = &l[1];
}
else if (rsize > 0)
{
result[counter] = l[0];
counter++;
lsize--;
l = &l[1];
}
Methinks you should be using r and rsize in the second of these blocks.
This still isn't the whole story...
And the residual problem (apart from memory management, which is still 100% leaky and problematic) is:
for(int j=middle;j<size;j++)
{
right[j]=a[j];
//cout<<right[j];
}
You're copying into parts of right that you've not allocated. You need something more like:
for(int j = 0; j < size - middle; j++)
{
right[j] = a[j + middle];
//cout<<right[j];
}
This code works as long as you always sort at least two items at the top level (you crash freeing unallocated space if you sort 1 item — that's part of the memory management problem).
#include <iostream>
using namespace std;
namespace {
int *merge(int *l, int m, int *r, int n);
void dump_array(int *a, int size)
{
int i;
cout << size << ": ";
for (i = 0; i < size; i++)
{
cout << ' ' << a[i];
if (i % 10 == 9)
cout << '\n';
}
if (i % 10 != 0)
cout << '\n';
}
};
int *merge_sort(int *a, int size)
{
cout << "-->> merge_sort:\n";
dump_array(a, size);
if (size <= 1)
{
cout << "<<-- merge_sort: early return\n";
return a;
}
int middle = size/2;
int *left = new int[middle];
int *right = new int[size - middle];
cout << middle << ": ";
for (int i = 0; i < middle; i++)
{
left[i] = a[i];
cout << ' ' << left[i];
}
cout << "\n";
cout << (size - middle) << ": ";
for (int j = 0; j < size - middle; j++)
{
right[j] = a[j + middle];
cout << ' ' << right[j];
}
cout << "\n";
cout << "MSL:\n";
int *nleft = merge_sort(left, middle);
cout << "NL: ";
dump_array(nleft, middle);
cout << "OL: ";
dump_array(left, middle);
cout << "OR: ";
dump_array(right, size - middle);
cout << "MSR:\n";
int *nright = merge_sort(right, size - middle);
cout << "NR: ";
dump_array(nright, size - middle);
cout << "NL: ";
dump_array(nleft, middle);
cout << "OL: ";
dump_array(left, middle);
cout << "OR: ";
dump_array(right, size - middle);
int *result = merge(nleft, middle, nright, size - middle);
cout << "<<-- merge_sort:\n";
dump_array(result, size);
return result;
}
namespace {
int *merge(int *l, int m, int *r, int n)
{
int *result = new int[m + n];
int lsize = m;
int rsize = n;
int counter = 0;
cout << "-->> merge: (" << m << "," << n << ")\n";
dump_array(l, m);
dump_array(r, n);
while (lsize > 0 || rsize > 0)
{
if (lsize > 0 && rsize > 0)
{
if (l[0] <= r[0])
{
result[counter] = l[0];
cout << "C: " << counter << "; L = " << l[0] << "; LS = " << lsize << '\n';
counter++;
lsize--;
l++;
}
else
{
result[counter] = r[0];
cout << "C: " << counter << "; R = " << r[0] << "; RS = " << rsize << '\n';
counter++;
rsize--;
r++;
}
}
else if (lsize > 0)
{
result[counter] = l[0];
cout << "C: " << counter << "; L = " << l[0] << "; LS = " << lsize << '\n';
counter++;
lsize--;
l++;
}
else if (rsize > 0)
{
result[counter] = r[0];
cout << "C: " << counter << "; R = " << r[0] << "; RS = " << rsize << '\n';
counter++;
rsize--;
r++;
}
}
cout << "<<-- merge:\n";
dump_array(result, m+n);
return result;
}
};
int main()
{
for (int i = 2; i <= 10; i++)
{
int array1[] = { 9, 3, 5, 7, 1, 8, 0, 6, 2, 4 };
cout << "\nMerge array of size " << i << "\n\n";
int *result = merge_sort(array1, i);
delete[] result;
}
return 0;
}
This is the debug-laden code. It's the level to which I went to get the result. I could perhaps have used a debugger. Were I on a machine where valgrind works, it might have helped too (but it does not work on Mac OS X 10.8.x, sadly).
There are still many, many ways to improve the code — including the memory management. You'd probably find it easiest to pass the input array to merge() for use as the result array (avoiding the memory allocation in that code). This would reduce the memory management burden.
When you remove the debug code, you'll need to call the dump_array() function in the main() program to get the before and after sorting array images.
Code converted to template functions and leak-free
I've simplified the code a fair bit, especially in the merge() function. Also, more as a matter of curiosity than anything else, converted it to a set of template functions, and then used them with 4 different array types (int, double, std::string, char). The amount of debugging has been dramatically reduced, and the main debugging is conditional on being compiled with -DTRACE_ENABLED now.
The code is now leak-free; valgrind on a Linux box (virtual machine) gives it a clean bill of health when there are no exceptions. It is not guaranteed exception-safe, though. In fact, given the naked uses of new and delete, it is pretty much guaranteed not to be exception-safe. I've left the namespace control in place, but I'm far from convinced it is really correct — indeed, I'd lay odds on it not being good. (I'm also curious if anyone has any views on how to layout code within a namespace { … }; block; it seems odd not indenting everything inside a set of braces, but …)
#include <iostream>
using namespace std;
namespace {
#if !defined(TRACE_ENABLED)
#define TRACE_ENABLED 0
#endif
enum { ENABLE_TRACE = TRACE_ENABLED };
template <typename T>
void merge(T *l, int m, T *r, int n, T *result);
template <typename T>
void dump_array(const char *tag, T *a, int size)
{
int i;
cout << tag << ": (" << size << ") ";
for (i = 0; i < size; i++)
{
cout << " " << a[i];
if (i % 10 == 9)
cout << '\n';
}
if (i % 10 != 0)
cout << '\n';
}
};
template <typename T>
void merge_sort(T *a, int size)
{
if (size <= 1)
return;
if (ENABLE_TRACE)
dump_array("-->> merge_sort", a, size);
int middle = size/2;
T *left = new T[middle];
T *right = new T[size - middle];
for (int i = 0; i < middle; i++)
left[i] = a[i];
for (int j = 0; j < size - middle; j++)
right[j] = a[j + middle];
merge_sort(left, middle);
merge_sort(right, size - middle);
merge(left, middle, right, size - middle, a);
delete [] left;
delete [] right;
if (ENABLE_TRACE)
dump_array("<<-- merge_sort", a, size);
}
namespace {
template <typename T>
void merge(T *l, int m, T *r, int n, T *result)
{
T *l_end = l + m;
T *r_end = r + n;
T *out = result;
if (ENABLE_TRACE)
{
cout << "-->> merge: (" << m << "," << n << ")\n";
dump_array("L", l, m);
dump_array("R", r, n);
}
while (l < l_end && r < r_end)
{
if (*l <= *r)
*out++ = *l++;
else
*out++ = *r++;
}
while (l < l_end)
*out++ = *l++;
while (r < r_end)
*out++ = *r++;
if (ENABLE_TRACE)
dump_array("<<-- merge", result, m+n);
}
};
#include <string>
int main()
{
for (size_t i = 1; i <= 10; i++)
{
int array1[] = { 9, 3, 5, 7, 1, 8, 0, 6, 2, 4 };
if (i <= sizeof(array1)/sizeof(array1[0]))
{
cout << "\nMerge array of type int of size " << i << "\n\n";
dump_array("Original", array1, i);
merge_sort(array1, i);
dump_array("PostSort", array1, i);
}
}
for (size_t i = 1; i <= 10; i++)
{
double array2[] = { 9.9, 3.1, 5.2, 7.3, 1.4, 8.5, 0.6, 6.7, 2.8, 4.9 };
if (i <= sizeof(array2)/sizeof(array2[0]))
{
cout << "\nMerge array of type double of size " << i << "\n\n";
dump_array("Original", array2, i);
merge_sort(array2, i);
dump_array("PostSort", array2, i);
}
}
for (size_t i = 1; i <= 10; i++)
{
std::string array3[] = { "nine", "three", "five", "seven", "one", "eight", "zero", "six", "two", "four" };
if (i <= sizeof(array3)/sizeof(array3[0]))
{
cout << "\nMerge array type std::string of size " << i << "\n\n";
dump_array("Original", array3, i);
merge_sort(array3, i);
dump_array("PostSort", array3, i);
}
}
for (size_t i = 1; i <= 10; i++)
{
char array4[] = "jdfhbiagce";
if (i <= sizeof(array4)/sizeof(array4[0]))
{
cout << "\nMerge array type char of size " << i << "\n\n";
dump_array("Original", array4, i);
merge_sort(array4, i);
dump_array("PostSort", array4, i);
}
}
return 0;
}

C++ Array copying/shift

We had a project that asked us to Write a program that allows a user to enter a series of numbers "read numbers into an array for further processing, user signals that they are finished by entering a negative number (negative not used in calculations), after all numbers have been read in do the following, sum up the #'s entered, count the #'s entered, find min/max # entered, compute average, then output them on the screen. So the working version of this that I made looks like so
/* Reads data into array.
paramater a = the array to fill
paramater a_capacity = maximum size
paramater a_size = filled with size of a after reading input. */
void read_data(double a[], int a_capacity, int& a_size)
{
a_size = 0;
bool computation = true;
while (computation)
{
double x;
cin >> x;
if (x < 0)
computation = false;
else if (a_size == a_capacity)
{
cout << "Extra data ignored\n";
computation = false;
}
else
{
a[a_size] = x;
a_size++;
}
}
}
/* computes the maximum value in array
paramater a = the array
Paramater a_size = the number of values in a */
double largest_value(const double a[], int a_size)
{
if(a_size < 0)
return 0;
double maximum = a[0];
for(int i = 1; i < a_size; i++)
if (a[i] > maximum)
maximum = a[i];
return maximum;
}
/* computes the minimum value in array */
double smallest_value(const double a[], int a_size)
{
if(a_size < 0)
return 0;
double minimum = a[0];
for(int i = 1; i < a_size; i++)
if (a[i] < minimum)
minimum = a[i];
return minimum;
}
//computes the sum of the numbers entered
double sum_value(const double a [], int a_size)
{
if (a_size < 0)
return 0;
double sum = 0;
for(int i = 0; i < a_size; i++)
sum = sum + a[i];
return sum;
}
//keeps running count of numbers entered
double count_value(const double a[], int a_size)
{
if (a_size < 0)
return 0;
int count = 0;
for(int i = 1; i <= a_size; i++)
count = i;
return count;
}
int _tmain(int argc, _TCHAR* argv[])
{
const int INPUT_CAPACITY = 100;
double user_input[INPUT_CAPACITY];
int input_size = 0;
double average = 0;
cout << "Enter numbers. Input negative to quit.:\n";
read_data(user_input, INPUT_CAPACITY, input_size);
double max_output = largest_value(user_input, input_size);
cout << "The maximum value entered was " << max_output << "\n";
double min_output = smallest_value(user_input, input_size);
cout << "The lowest value entered was " << min_output << "\n";
double sum_output = sum_value(user_input, input_size);
cout << "The sum of the value's entered is " << sum_output << "\n";
double count_output = count_value(user_input, input_size);
cout << "You entered " << count_output << " numbers." << "\n";
cout << "The average of your numbers is " << sum_output / count_output << "\n";
string str;
getline(cin,str);
getline(cin,str);
return 0;
}
That went fine, the problem I am having now is part 2. Where we are to "copy the array to another and shift an array by N elements". I'm not sure where to begin on either of these. I've looked up a few resources on copying array's but I was not sure how to implement them in the current code I have finished, especially when it comes to shifting. If anyone has any thoughts, ideas, or resources that can help me on the right path it would be greatly appreciated. I should point out as well, that I am a beginner (and this is a beginners class) so this assignment might not be the 'optimal' way things could be done, but instead incorporates what we have learned if that makes sense.
for(int i = 0; i < n; ++i){
int j = (i - k)%n;
b[i] = a[j];
}
Check it. I'm not sure
If this works you could improve it to
for(int i = 0; i < n; ++i)
b[i] = a[(i - k)%n];//here can be (i +/- k) it depends which direction u would shift
If you only want to copy the array into another array and shift them
ex : input = 1, 2, 3, 4, 5; output = 3, 4, 5, 1, 2
The cumbersome solution is
//no template or unsafe void* since you are a beginner
int* copy_to(int *begin, int *end, int *result)
{
while(begin != end){
*result = *begin;
++result; ++begin;
}
return result;
}
int main()
{
int input[] = {1, 2, 3, 4, 5};
size_t const size = sizeof(input) / sizeof(int);
size_t const begin = 2;
int output[size] = {0}; //0, 0, 0, 0, 0
int *result = copy_to(input + begin, input + size - begin, output); //3, 4, 5, 0, 0
copy_to(input, input + begin, result); //3, 4, 5, 1, 2
return 0;
}
How could the stl algorithms set help us?
read_data remain as the same one you provided
#include <algorithm> //std::minmax_element, std::rotate_copy
#include <iostream>
#include <iterator> //for std::begin()
#include <numeric> //for std::accumulate()
#include <string>
#include <vector>
int main(int argc, char *argv[]) //don't use _tmain, they are unportable
{
const int INPUT_CAPACITY = 100;
double user_input[INPUT_CAPACITY];
int input_size = 0;
double average = 0;
cout << "Enter numbers. Input negative to quit.:\n";
read_data(user_input, INPUT_CAPACITY, input_size);
auto const min_max = std::minmax_element (user_input, user_input + input_size); //only valid for c++11
std::cout << "The maximum value entered was " << min_max.second << "\n";
std::cout << "The lowest value entered was " << min_max.first << "\n";
double sum_output = std::accumulate(user_input, user_input + input_size, 0);
cout << "The sum of the value's entered is " << sum_output << "\n";
//I don't know the meaning of you count_value, why don't just output input_size?
double count_output = count_value(user_input, input_size);
cout << "You entered " << count_output << " numbers." << "\n";
cout << "The average of your numbers is " << sum_output / count_output << "\n";
int shift;
std::cout<<"How many positions do you want to shift?"<<std::endl;
std::cin>>shift;
std::vector<int> shift_array(input_size);
std::rotate_copy(user_input, user_input + shift, user_input + input_size, std::begin(shift_array));
//don't know what are they for?
std::string str;
std::getline(std::cin,str);
std::getline(std::cin,str);
return 0;
}
if your compiler do not support c++11 features yet
std::minmax_element could replace by
std::min_element and std::max_element
std::begin() can replace by shift_array.begin()
I don't know what is the teaching style of your class, in my humble opinion, beginners should
start with those higher level components provided by c++ like vector, string, algorithms
and so on.I suppose your teachers are teaching you that way and you are allowed to use the
algorithms and containers come with c++(Let us beg that your class are not teaching you "c with classes" and say something like "OOP is the best thing in the world").
ps : You could use vector to replace the raw array if you like