I'm trying to solve a simple beginner exercise, I compare two arrays and find the numbers that appear in both. The result is put into another array called result. For whatever reason the result should contain "2 44 55" but it shows "2 1 10 10". What did I do wrong?
#include <iostream>
void common_elements(int array_1[], int array_2[]){
int result[] {0};
int counter{0};
for (int i{0}; i < 10; i++){
for (int j{0}; j < 10; j++){
if (array_2[i] == array_1[j]){
result[counter] = array_1[j];
counter++;
}
}
}
if (counter == 0) {
std::cout << "There are 0 common elements";
} else {
std::cout << "There are " << counter << " common elements they are : ";
for (int k{0}; k < counter; k++){
std::cout << result[k] << " ";
}
}
}
int main(){
int data1[] {1,2,4,5,9,3,6,7,44,55};
int data2[] {11,2,44,45,49,43,46,47,55,88};
common_elements(data1,data2);
return 0;
}
I'm confused because when I std::cout the numbers during examination (two nested loops), the result is correct.
It is just containing one single element, because the compiler deduces the length to 1. This would mean the 2 is valid, all other values are "out of bound". Thanks for your help. I repaired it to
int result[10]{0};
Now it's working, thanks a lot.
Btw: It is a C++ course but it starts from the very beginning. That why this looks like C.
For starters the function should be declared at least like
std::vector<int> common_elements( const int array_1[], size_t n1,
const int array_2[], size_t n2 );
Using the magic number 10 within the function as
for (int i{0}; i < 10; i++){
does not make sense. The function can be called for arrays that have different numbers of elements.
This declaration of an array
int result[] {0};
declares an array with only one element that also does not make sense.
Also the function should not output any message. It is the caller of the function that decides whether to output a message. The function should return a sequence of common elements of two arrays.
The function can be defined the following way
#include <vector>
#include <iterator>
#include <functional>
//...
std::vector<int> common_elements( const int array_1[], size_t n1,
const int array_2[], size_t n2 )
{
std::vector<int> v;
if ( n1 != 0 && n2 != 0 )
{
if ( n2 < n1 )
{
std::swap( n1, n2 );
std::swap( array_1, array_2 );
}
for ( size_t i = 0; i < n1; i++ )
{
size_t count = 1;
for ( size_t j = 0; j < i; j++ )
{
if ( array_1[j] == array_1[i] ) ++count;
}
for ( size_t j = 0; count != 0 && j < n2; j++ )
{
if ( array_2[j] == array_1[i] )
{
--count;
}
}
if ( count == 0 ) v.push_back( array_1[i] );
}
}
return v;
}
And in main the function is called like
int data1[] {1,2,4,5,9,3,6,7,44,55};
int data2[] {11,2,44,45,49,43,46,47,55,88};
auto v = common_elements( data1, std::size( data1 ), data2, std::size( data2 ) );
if ( std::size( v ) == 0 )
{
std::cout << "There are 0 common elements";
}
else
{
std::cout << "There are " << std::size( v ) << " common elements they are : ";
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
}
Instead of the vector you could use std::map<intg, size_t>. In this case the container will contain how many times a common number is encountered in the both arrays.
Here is a demonstration program.
#include <iostream>
#include <vector>
#include <iterator>
#include <functional>
std::vector<int> common_elements( const int array_1[], size_t n1,
const int array_2[], size_t n2 )
{
std::vector<int> v;
if (n1 != 0 && n2 != 0)
{
if (n2 < n1)
{
std::swap( n1, n2 );
std::swap( array_1, array_2 );
}
for (size_t i = 0; i < n1; i++)
{
size_t count = 1;
for (size_t j = 0; j < i; j++)
{
if (array_1[j] == array_1[i]) ++count;
}
for (size_t j = 0; count != 0 && j < n2; j++)
{
if (array_2[j] == array_1[i])
{
--count;
}
}
if (count == 0) v.push_back( array_1[i] );
}
}
return v;
}
int main()
{
int data1[]{ 1,2,4,5,9,3,6,7,44,55 };
int data2[]{ 11,2,44,45,49,43,46,47,55,88 };
auto v = common_elements( data1, std::size( data1 ), data2, std::size( data2 ) );
if (std::size( v ) == 0)
{
std::cout << "There are 0 common elements";
}
else
{
std::cout << "There are " << std::size( v ) << " common elements they are : ";
for (const auto &item : v)
{
std::cout << item << ' ';
}
std::cout << '\n';
}
}
The program output is
There are 3 common elements they are : 2 44 55
Related
I have a function that pushes down all non zero integers to the top of my array and then reprints it in a 3x3 matrix.
the problem i am having is when i push all the non zero integers into my stack it reverses the order.
** the indexing of my array is backwards. ie, in a 3x3 matrix the coordinates (0,0) would be the bottom left **
here is the relevant code:
void State::pushDown() {
std::stack<int> tempStack;
for ( int c = 0; c < BOARDSIZE; c++ )
{
for ( int r = 0; r < BOARDSIZE ; r++ )
{
if ( grid[r][c] != 0 ) tempStack.push( grid[r][c] );
}
for ( int r = BOARDSIZE; r != 0; --r )
{
if ( !tempStack.empty() )
{
grid[r-1][c] = tempStack.top();
tempStack.pop();
}
else
{
grid[r-1][c] = 0;
}
}
}
}
State() {
for (int i = 0; i < BOARDSIZE; i++)
for (int j = 0; j < BOARDSIZE; j++)
grid[i][j] = rand() % 7;
}
void State::printBoard() {
cout << endl;
for (int i = 0; i < BOARDSIZE; i++) {
for (int j = 0; j < BOARDSIZE; j++) {
cout << " " << grid[BOARDSIZE - i - 1][j] << " ";
}
cout << endl;
}
}
int main() {
srand(time(0));
State state;
state.printBoard();
state.pushDown();
state.printBoard();
return 0;
}
here is my current output:
before push down function
045
504
226
after push down function:
006
224
545
as you can see it successfully pushes the non zero elements to the bottom of the matrix however in the process it reverses the order of the other numbers and i believe this is because of the stack.
my expected output would be the following:
before push down function
045
504
226
after push down function:
005
544
226
My question is- how can i fix my function so that the order of the elements remain the same without reversing.
Here is a demonstrative program that shows how the loops can be defined.
#include <iostream>
#include <stack>
const int BOARDSIZE = 3;
void reformat( int ( &a )[BOARDSIZE][BOARDSIZE] )
{
std::stack<int> tempStack;
for ( int c = 0; c < BOARDSIZE; c++ )
{
for ( int r = 0; r < BOARDSIZE ; r++ )
{
if ( a[r][c] != 0 ) tempStack.push( a[r][c] );
}
for ( int r = BOARDSIZE; r != 0; --r )
{
if ( !tempStack.empty() )
{
a[r-1][c] = tempStack.top();
tempStack.pop();
}
else
{
a[r-1][c] = 0;
}
}
}
}
int main()
{
int a[BOARDSIZE][BOARDSIZE] =
{
{ 0, 4, 5 },
{ 5, 0, 4 },
{ 2, 2, 6 }
};
for ( const auto &row : a )
{
for ( const auto &item : row ) std::cout << item << ' ';
std::cout << '\n';
}
std::cout << '\n';
reformat( a );
for ( const auto &row : a )
{
for ( const auto &item : row ) std::cout << item << ' ';
std::cout << '\n';
}
std::cout << '\n';
return 0;
}
Its output is
0 4 5
5 0 4
2 2 6
0 0 5
5 4 4
2 2 6
If you are outputting the array starting from its last row then use the following loops
#include <iostream>
#include <stack>
const int BOARDSIZE = 3;
void reformat( int ( &a )[BOARDSIZE][BOARDSIZE] )
{
std::stack<int> tempStack;
for ( int c = 0; c < BOARDSIZE; c++ )
{
for ( int r = 0; r < BOARDSIZE ; r++ )
{
if ( a[BOARDSIZE-r-1][c] != 0 ) tempStack.push( a[BOARDSIZE-r-1][c] );
}
for ( int r = 0; r != BOARDSIZE; ++r )
{
if ( !tempStack.empty() )
{
a[r][c] = tempStack.top();
tempStack.pop();
}
else
{
a[r][c] = 0;
}
}
}
}
int main()
{
int a[BOARDSIZE][BOARDSIZE] =
{
{ 2, 2, 6 },
{ 5, 0, 4 },
{ 0, 4, 5 }
};
for ( size_t i = 0; i < BOARDSIZE; i++ )
{
for ( const auto &item : a[BOARDSIZE - i - 1] ) std::cout << item << ' ';
std::cout << '\n';
}
std::cout << '\n';
reformat( a );
for ( size_t i = 0; i < BOARDSIZE; i++ )
{
for ( const auto &item : a[BOARDSIZE - i - 1] ) std::cout << item << ' ';
std::cout << '\n';
}
std::cout << '\n';
return 0;
}
The program output is the same as shown above
0 4 5
5 0 4
2 2 6
0 0 5
5 4 4
2 2 6
But now the array is outputted starting from its last line.
I'm trying to display a vector of deques (std::vector<std::deque<int>> v) like this
v.at(0).at(0) v.at(1).at(0) v.at(2).at(0) v.at(3).at(0)
v.at(0).at(1) v.at(1).at(1) v.at(2).at(1) v.at(3).at(1)
v.at(0).at(2) v.at(1).at(2) v.at(2).at(2) v.at(3).at(2)
v.at(1).at(3) v.at(3).at(3)
v.at(3).at(4)
The first part of the vector is fixed at 7, the size of the actual columns are dynamic however depending on what the user chooses to do.
I was attempting something like
int row = 0;
int column;
for (column = 0; column < v.at(row).size(); column++){
cout << "v["<< row <<"]["<< column << "]" << v.at(row).at(column) << "\t";
while (row < v.size()){
cout << endl;
row++;
}
}
I'm getting errors like
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: vector
make: *** [Pile.h] Abort trap: 6
Having one of those blah brain days. Can someone help me print this out the way I want it?
Here is a demonstrative program that shows one of approaches to the task.
#include <iostream>
#include <iomanip>
#include <vector>
#include <deque>
#include <algorithm>
int main()
{
std::vector<std::deque<int>> v =
{
{ 0, 1, 2 },
{ 0, 1, 2, 3 },
{ 0, 1, 2 },
{ 0, 1, 2, 3, 4 }
};
size_t n = std::max_element( v.begin(), v.end(),
[]( const auto &x, const auto &y )
{
return x.size() < y.size();
} )->size();
for ( size_t i = 0; i < n; i++)
{
for ( size_t j = 0; j < v.size(); j++ )
{
std::cout << std::setw( 4 );
if ( i < v[j].size() )
{
std::cout << v[j][i];
}
else
{
std::cout << "";
}
}
std::cout << std::endl;
}
return 0;
}
Its output is
0 0 0 0
1 1 1 1
2 2 2 2
3 3
4
First of all, I suggest to get the max queue size
std::size_t maxQ { 0U };
for ( auto const & q : v )
maxQ = std::max(maxQ, q.size());
Now you can write a loop over (0U, maxQ( (the loop of lines) writing elements when available and space otherwise.
for ( auto i = 0U ; i < maxQ ; ++i )
{
for ( auto j = 0U ; j < v.size() ; ++j )
if ( i < v[j].size() )
; // print v[j][i]
else
; // print space
std::cout << std::endl; // endl of line
}
I leave to you cells printing details
i have a really simple code right there that counts how much values you need in arrays.
for (int i = 0; i < dm; i++)
{
if (arr[i] == c)
{
counter++;
}
};
But i need to make it a little bit tricky.I need to count number of same values. Imagine i have an array {4,4,4,3,3,2,2,1,1,0,0,0} and i need to find how much "twins" there. So 3,2,1 are twins because they have only 1 exact friend.
I tried something like 2 fors and 2 counters but still have troubles. Thanks. Hope you understand what i mean by "twin". x and x are twins and y,y,y are not ( just in case)
I'd make a map that counts - for each individual number in the array - their occurrences. The code could look as follows:
#include <iostream>
#include <map>
int main()
{
const int numberOfElements = 12;
int array[numberOfElements] = { 4,4,4,3,3,2,2,1,1,0,0,0 };
std::map<int,int> counts;
for (int i=0; i < numberOfElements; i++) {
counts[array[i]]++;
}
for (auto x : counts) {
if (x.second == 2) {
cout << "pair: " << x.first << endl;
}
}
return 0;
}
If - for some reason - the range of the elements is limited, you could also use a "plain" array for counting the occurrences. If, for example, the elements are in the range of 0..4, you could use the following fragment:
const int numberOfElements = 12;
const int elementMax = 4;
int array[numberOfElements] = { 4,4,4,3,3,2,2,1,1,0,0,0 };
int counts[elementMax+1] = {};
for (int i=0; i<numberOfElements; i++) {
counts[array[i]]++;
}
for (int i=0; i <= elementMax; i++) {
if (counts[i] == 2) {
cout << "pair: " << i << endl;
}
}
And if your array is sorted, than a solution without a counter-array could look as follows:
const int numberOfElements = 12;
int array[numberOfElements] = { 4,4,4,3,3,2,2,1,1,0,0,0 };
int prev = -1;
int count = 0;
for (int i=0; i<numberOfElements; i++) {
if (array[i] == prev) {
count++;
}
else {
if (count == 2) {
cout << "pair: " << prev << endl;
}
count=1;
prev = array[i];
}
}
if (prev >= 0 && count==2) {
cout << "pair: " << prev << endl;
}
You can do that in one pass and use binary search for efficiency:
int arr[] = { 4,4,4,3,3,2,2,1,1,0,0,0 };
int twins = 0;
for( auto i = std::begin( arr ); i != std::end( arr ); ) {
auto next = std::upper_bound( i, std::end( arr ), *i, std::greater<int>() );
if( std::distance( i, next ) == 2 ) ++twins;
i = next;
}
Live example
In case there are not too many duplicates in the array std::upper_bound could be not efficient and can be easily replaced:
auto next = std::find_if( std::next( i ), std::end( arr ), [i]( int n ) { return *i != n; } );
Solution without using additional array:
int twins_counter = 0;
for (int i = 0; i < dm; i++)
{
int counter = 0; // counter for elements
for (int j = 0; j < dm; j++)
{
if (arr[i] == arr[j])
{
if( j < i )
{
break; // we have searched twin for this element already
}
counter++;
if( counter > 2 )
{
break; // we meet element third time, it isn't twin
}
}
}
if( counter == 2 )
{
twins_counter++;
}
};
For sorted (upwards or downwards) arrays one cycle is enough:
int twins_counter = 0;
int counter = 1;
for (int i = 1; i < dm; i++)
{
if( arr[i] == arr[i-1] )
{
counter++;
}
else
{
if( counter == 2 )
{
twins_counter++;
counter = 1;
}
}
}
// check last value
if( counter == 2 )
{
twins_counter++;
}
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.
I would like to know how to check for subset and proper subset of two arrays. I cannot figure out a logical way to check for the subset of two arrays. Here is what I have so far.
Here is my Code:
Sets.h
#ifndef SETS_H
#define SETS_H
using namespace std;
class Sets{
private:
static const int SIZE = 5;
int arr[SIZE];
public:
Sets();
void addElement(int);
int getElement(int);
int getSize();
bool isSubset(Sets);
bool isProper(Sets);
void printSet();
void printOrderedPairs(Sets);
};
#endif
Sets.cpp
#include "Sets.h"
#include <iostream>
using namespace std;
Sets::Sets(){
for (int i = 0; i < SIZE; i++){
arr[i] = -1;
}
}
int Sets::getSize(){
return SIZE;
}
void Sets::addElement(int l){
for (int i = 0; i < SIZE; i++){
if (arr[i] == -1){
arr[i] = l;
break;
}
}
}
int Sets::getElement(int j){
if (j < SIZE){
return (-1);
}
else{
int temp;
temp = arr[j];
return temp;
}
}
bool Sets::isSubset(Sets b){
for (int i = 0; i < SIZE; i++){
for (int j = 0; j < SIZE; j++){
if (arr[i] != b.arr[i]){
return false;
}
}
}
return true;
}
bool Sets::isProper(Sets b){
for (int i = 0; i < SIZE; i++){
for (int j = 0; j < SIZE; j++){
if (arr[i] != b.arr[j]){
return false;
}
}
}
return true;
}
void Sets::printOrderedPairs(Sets b){
cout << "A X B = {";
for (int i = 0; i < SIZE-1; i++){
for (int j = 0; j < SIZE; j++){
cout << "(" << arr[i] << "," << b.arr[j] << ") , ";
}
}
cout << "}";
}
void Sets::printSet(){
cout << "{";
for (int i = 0; i < SIZE; i++){
cout << arr[i] << " ,";
}
cout << "}";
}
TestSets.cpp
#include <iostream>
#include "Sets.h"
using namespace std;
int main(){
Sets a;
Sets b;
a.addElement(1);
a.addElement(3);
a.addElement(5);
a.addElement(7);
a.addElement(9);
b.addElement(1);
b.addElement(3);
b.addElement(5);
b.addElement(7);
b.addElement(9);
cout << "Set A is ";
a.printSet();
cout << endl;
cout << "Set B is ";
b.printSet();
cout << "\n" << endl;
a.printOrderedPairs(b);
cout << "\n" << endl;
if (a.isSubset(b) == true){
cout << "Set B is subset of set A" << endl;
}
else{
cout << "Set B is not a subset of set A" << endl;
}
if (a.isProper(b) == true){
cout << "Set B is proper subset of set A" << endl;
}
else{
cout << "Set B is not a proper subset of set A" << endl;
}
system("PAUSE");
return 0;
}
Any help would be appreciate at this point. Thanks in advance.
A way to check is a set b is a subset of another set a is to loop through each element of b and verify that it is present in a. This is faster if both the sets are sorted (and that's the case of std::set for example).
Your class uses an array of int (and it would be better using a std::vector instead) of fixed size (5, for whatever reason). I think it should be an improvment using some dynamical allocation instead.
So, to check if a set is a subset I'll suggest you something like:
// a.isSubset(b) check if b is a subset of a
bool Sets::isSubset( const Sets &b ) {
for (int i = 0; i < b.size; i++ ) {
bool is_present = false;
for (int j = 0; j < size; j++ ) {
// b is a subset if all of its element are in a
// so check if any element of b is in a
if ( arr[j] == b.arr[i] ) {
is_present = true;
break;
}
}
if ( !is_present ) return false;
}
return true;
}
// a.isProper(b) check if b is a proper subset of a
bool Sets::isProper( const Sets &b) {
int n_equals = 0;
for (int i = 0; i < b.size; i++) {
bool is_present = false;
for (int j = 0; j < size; j++) {
// b is a prpoper subset if all of its element are in a
// but there exists at least one element of a that is not in b
if ( arr[j] == b.arr[i] ) {
is_present = true;
++n_equals;
break;
}
}
if ( !is_present ) return false;
}
return n_equals < size;
}
Your class should be modified accordingly.
EDIT
To gain better performances and to simplify most of the algorithms it's better to use a sorted container. For example, the two function belove may become:
// a.isSubset(b) check if b is a subset of a. Requires that both are sorted
bool Sets::isSubset( const Sets &b ) {
for (int i = 0, j = 0; i < b.size; i++ ) {
// scan a, which is sorted
while ( j < size && arr[j] < b.arr[i] ) ++j;
if ( j == size || arr[j] > b.arr[i] )
// There's at least one element of b which not belongs to a
return false;
// b.arr[i] == arr[j], move on
}
// all the element of b are in a too
return true;
}
// a.isProper(b) check if b is a proper subset of a.
// It requires that both are sorted
bool Sets::isProper( const Sets &b ) {
int n_equals = 0;
for (int i = 0, j = 0; i < b.size; i++ ) {
while ( j < size && arr[j] < b.arr[i] ) ++j;
if ( j == size || arr[j] > b.arr[i] )
// b is a prpoper subset if all of its element are in a
// but there exists at least one element of a that is not in b
return false;
++n_equals;
}
return n_equals < size;
}
To force the sorting you only have to modify the function that adds elements. I added some helper functions too:
#include <iostream>
using namespace std;
class Sets{
private:
int size;
int allocated;
int *arr;
// It's way better using a std::vector:
// vector<int> v;
// or you can cheat and use a std::set
public:
Sets();
~Sets();
void addElement(int);
void delElement(int);
int getLowerPos(int);
int getElement(int);
int getSize();
bool doesContain(int);
bool isSubset(const Sets &);
bool isProper(const Sets &);
void printSet();
void printOrderedPairs(const Sets &);
};
Sets::Sets() : size(0), allocated(0), arr(nullptr) { }
Sets::~Sets() {
delete[] arr;
}
int Sets::getSize(){
return size;
}
// Add an element if it isn't already present, keeping the array sorted
void Sets::addElement( int x ) {
int pos = this->getLowerPos(x);
if ( pos < size && arr[pos] == x ) return;
if ( size == allocated ) {
// it's time to expand the array. If it's empty, start from 8
allocated = allocated > 0 ? allocated * 2 : 8;
int *new_arr = new int[allocated];
for ( int i = 0; i < pos; i++ ) {
new_arr[i] = arr[i];
}
for ( int i = size; i > pos; --i ) {
new_arr[i] = arr[i - 1];
}
delete[] arr;
arr = new_arr;
}
else {
for ( int i = size; i > pos; --i ) {
arr[i] = arr[i - 1];
}
}
arr[pos] = x;
++size;
}
// Remove an element from the set if it is present, keeping the array sorted
void Sets::delElement( int x ) {
int pos = this->getLowerPos(x);
if ( pos == size || arr[pos] != x ) return;
// I move the elements and update size only, without deallocation.
--size;
for ( int i = pos; i < size; ++i ) {
arr[i] = arr[i + 1];
}
}
// I guess you want to return the element j of the set or -1 if it's not present
int Sets::getElement( int j ){
// consider using size_t instead of int for indeces or at least unsigned int
if ( j < 0 || j >= size )
// I assume all the elements are positive integers
return -1;
else
// why the temp?
return arr[j];
}
// Find the position of the lowest element in the set such that x <= arr[pos]
// with a binary search. It requires that the array is sorted.
// Return the value size if all the elements are lower then x
int Sets::getLowerPos( int x ) {
int first = 0, count = size - first, step, pos = 0;
while ( count > 0 ) {
step = count / 2;
pos = first + step;
if ( arr[pos] < x ) {
first = ++pos;
count -= step + 1;
}
else
count = step;
}
return first;
}
// Check if x is present in the set with a binary search.
// It requires that the array is sorted
bool Sets::doesContain( int x ) {
int pos = this->getLowerPos(x);
return ( pos != size && arr[pos] == x );
/*
// Or directly with a simple binary search:
int low = 0, high = size - 1, pos;
while ( low <= high ) {
pos = low + (high - low) / 2;
if ( x == arr[pos] )
return true;
else if ( x < arr[pos] )
high = pos - 1;
else
low = pos + 1;
}
return false;
*/
}
// ... isSubset() and isProper() as above ...
void Sets::printOrderedPairs( const Sets &b){
cout << "A X B = {";
for (int i = 0; i < size; i++){
for (int j = 0; j < b.size; j++){
cout << '(' << arr[i] << ", " << b.arr[j] << "), ";
}
}
cout << "\b\b} ";
}
void Sets::printSet(){
cout << '{';
for (int i = 0; i < size; i++){
cout << arr[i] << ", ";
}
cout << "\b\b} ";
}
int main(void) {
try {
Sets a;
Sets b;
a.addElement(9);
a.addElement(3);
a.addElement(7);
a.addElement(5);
a.addElement(1);
b.addElement(3);
b.addElement(7);
b.addElement(1);
b.addElement(5);
cout << "Set A is ";
a.printSet();
cout << "\nSet B is ";
b.printSet();
cout << "\n\n";
a.printOrderedPairs(b);
cout << "\n\n";
if ( a.isSubset(b) ) {
cout << "Set B is a subset of set A\n";
}
else {
cout << "Set B is not a subset of set A\n";
}
if ( a.isProper(b) ){
cout << "Set B is a proper subset of set A\n";
}
else{
cout << "Set B is not a proper subset of set A\n";
}
system("PAUSE");
}
catch ( const bad_alloc& e) {
cout << "Allocation failed: " << e.what() << '\n';
}
return 0;
}
Now the output is:
Set A is {1, 3, 5, 7, 9}
Set B is {1, 3, 5, 7}
A X B = {(1, 1), (1, 3), (1, 5), (1, 7), (3, 1), (3, 3), (3, 5), (3, 7), (5, 1), (5, 3), (5, 5), (5, 7), (7, 1), (7, 3), (7, 5), (7, 7), (9, 1), (9, 3), (9, 5), (9, 7)}
Set B is subset of set A
Set B is proper subset of set A