Complete Implementation of Sets

Let's look at the complete code implementation of programs on sets.

Complete implementation of set

In this lesson, we’ve added the complete code that we’ve covered so far on different problems on sets (both with and without functions).

Without functions

The complete code in a single code editor is given below. Skim through this and see how complex the implementation of all these tasks would have been to follow if we had not used functions.

Press + to interact
main.cpp
Sets.txt
#include <iostream>
#include<fstream>
using namespace std;
int main()
{
const int capacity = 500;
int A[capacity] = { 0 }, B[capacity] = { 0 }, sizeA, sizeB;
int input, repeatedElement = false;
ifstream rdr("Sets.txt");
cout << "Size of Set A = ";
rdr >> sizeA; cout << sizeA<<"\n";
cout << "Size of Set B = ";
rdr >> sizeB; cout << sizeB<<"\n";
for (int i = 0; i <= sizeA-1; i++)
{
rdr >> input;
for (int ei = 0; ei < i-1; ei++)
{
if (input == A[i])
{
repeatedElement = true;
cout << "\nMust have identical elements in the set!!!\n";
cout << "Remaining Elements: ";
i--;
}
}
if (repeatedElement == false)
A[i] = input;
repeatedElement =false;
}
cout << endl;
for (int i = 0; i <= sizeB-1; i++)
{
rdr >> input;
for (int ei = 0; ei < i; ei++)
{
if (input == B[i])
{
repeatedElement = true;
cout << "\nMust have identical elements in the set!!!\n";
cout << "Remaining Elements: ";
i--;
}
}
if (repeatedElement == false)
B[i] = input;
repeatedElement = false;
}
//Tast 2 - Sorting the two sets
//Sorting A
for (int t = 1; t <= sizeA - 1; t++)
{
for (int ai = 0; ai + 1 < sizeA; ai++)
{
if(A[ai]>A[ai+1])
swap(A[ai], A[ai + 1]);
}
}
//Sorting B
for (int t = 1; t <= sizeB - 1; t++)
{
for (int bi = 0; bi + 1 < sizeB; bi++)
{
if(B[bi]>B[bi+1])
swap(B[bi], B[bi + 1]);
}
}
//Task 3 - Displaying the two sets
cout << "A = {";
for (int ai = 0; ai <= sizeA - 1; ai++)
{
cout << A[ai];
if (ai != sizeA - 1)
cout << ", ";
}
cout << "}" << endl;
cout << "B = {";
for (int bi = 0; bi <= sizeB -1; bi++)
{
cout << B[bi];
if(bi != sizeB -1)
cout << ", ";
}
cout << "}";
//Task 4 A is a Subset of B or B is a subset of A or none.
int count =0;
if (sizeA <= sizeB)
{
for (int ai = 0; ai <= sizeA - 1; ai++)
{
for (int bi = 0; bi <= sizeB - 1; bi++)
{
if (A[ai] == B[bi]) // A[ai] is in B
{
count++; // remember that A[ai] is present
break; // no need to check for this number any further
}
}
}
if (count == sizeA)
cout << "\nA is a subset of B.\n";
else
cout << "\nNeither is a subset of other.\n";
}
else if (sizeA > sizeB)
{
for (int bi = 0; bi <= sizeB - 1; bi++)
{
for (int ai = 0; ai <= sizeA - 1; ai++)
{
if (B[bi] == A[ai])
count++;
}
}
if (count == sizeB)
cout << "\nB is a subset of A.\n";
else
cout << "\n Neither is a subset of other.\n";
}
//Task 5
int UnionSet[500] = { 0 };
for (int ai = 0; ai <= sizeA - 1; ai++)
{
UnionSet[ai] = A[ai]; // Add all the elements in A in the unionSet
}
int check = 0, ui = sizeA;
for (int bi = 0; bi <= sizeB - 1; bi++)
{
check = 0;
for (int ai = 0; ai <= sizeA - 1; ai++)
{
if (B[bi] == A[ai])
check++;
}
if (check == 0)
{
UnionSet[ui] = B[bi];
ui++;
}
}
int uSize = ui;
//Sorting Union-Set
for (int t = 1; t <= uSize-1; t++)
{
for (int ui = 0; ui +1< uSize; ui++)
{
if (UnionSet[ui] > UnionSet[ui + 1])
swap(UnionSet[ui], UnionSet[ui + 1]);
}
}
cout << "\nA U B = {";
for (int ui = 0; ui <= uSize-1; ui++)
{
cout << UnionSet[ui];
if (ui != uSize-1)
cout << ", ";
}
cout << "}";
//Task6
int intersectionSet[500] = { 0 };
int ii = 0;
for (int bi = 0; bi <= sizeB - 1; bi++)
{
for (int ai = 0; ai <= sizeA - 1; ai++)
{
if (B[bi] == A[ai])
check++;
}
if (check != 0)
{
intersectionSet[ii] = B[bi];
ii++;
}
check = 0;
}
//Displaying Intersection Set
int iSize = ii;
cout << "\nA ^ B = {";
for (int i = 0; i <= iSize-1; i++)
{
cout << intersectionSet[i];
if (i != iSize-1)
cout << ", ";
}
cout << "}";
//Task 7
int AMinusB[500];
bool found;
int mi = 0;
for (int ai = 0; ai <= sizeA - 1; ai++)
{
found = false;
for (int bi = 0; bi <= sizeB - 1; bi++)
{
if (A[ai] == B[bi])
{
found = true; break;
}
}
if (!found)
{
AMinusB[mi] = A[ai];
mi++;
}
}
int minusSize = mi;
cout << "\nA - B: = {";
for (int mi = 0; mi <= minusSize - 1; mi++)
{
cout << AMinusB[mi];
if (mi != minusSize - 1)
cout << ", ";
}
cout << "}";
{
int BMinusA[500];
mi = 0;
bool present;
for (int bi = 0; bi <= sizeB - 1; bi++)
{
present = false;
for (int ai = 0; ai <= sizeA - 1; ai++)
{
if (B[bi] == A[ai])
{
present=true;
break;
}
}
if (!present)
{
BMinusA[mi] = B[bi];
mi++;
}
}
cout << "\nB - A: = {";
for (int i = 0; i <= mi-1; i++)
{
cout << BMinusA[i];
if (i != mi-1)
cout << ", ";
}
cout << "}";
}
//Task 8
cout << "\nA x B: = {\n";
for (int ai = 0; ai <= sizeA-1; ai++)
{
cout << "\t\t\t";
for (int bi = 0; bi <= sizeB - 1; bi++)
{
cout << "(" << A[ai] << ", " << B[bi] << ")";
if (bi != (sizeB - 1) || ai != (sizeA - 1))
cout << ", ";
}
cout << endl;
}
cout << "\n\t\t}";
return 0;
}

Problems with the above implementation

Congratulations! You have successfully implemented the different programs regarding sets with the help of several nested loops. In programs, where we did not make functions, you must have noticed the following problems:

  • We were repeating some of the tasks with different data, e.g., printing the arrays, sorting the arrays, searching in arrays, computing the set difference of the two sets, and so on. This repetition must be avoided. We overcome this issue when we implement the same using functions.
  • This repetition always wastes a lot of time as one needs to make the entire effort again with a similar problem with different inputs.
  • It is challenging to extend this type of code because it becomes unmanageable due to its huge length.
  • It can be hard to debug if there is a logical error somewhere in the code.

With functions

Let’s look at the complete code. You may see how all the repetition of the code in the above playground is completely avoided through modularisation.

Press + to interact
main.cpp
Sets.txt
#include <iostream>
#include<fstream>
using namespace std;
void loadSet(const char Msg[], int S[ ], int &size, ifstream &rdr)
{
rdr >> size;
cout << "The size of the set "<<Msg<<" : "<<size<<endl;
int input, repeatedElement = false;
for (int i = 0; i <= size-1; i++)
{
rdr >> input;
for (int ei = 0; ei < i; ei++)
{
if (input == S[i])
{
repeatedElement = true;
cout << "\nMust have identical elements in the set!!!\n";
cout << "Remaining Elements: ";
i--;
}
}
if (repeatedElement == false)
S[i] = input;
repeatedElement =false;
}
}
void sort(int S[ ], int size)
{
for (int t = 1; t <= size - 1; t++)
{
for (int si = 0; si + 1 < size; si++)
{
if(S[si]>S[si+1])
swap(S[si], S[si + 1]);
}
}
}
void setPrint(const char Msg[ ],
int S[ ], int size)
{
cout << Msg<<" = {";
for (int si = 0; si <= size - 1; si++)
{
cout << S[si];
if (si != size - 1)
cout << ", ";
}
cout << "}" << endl;
}
bool isPresent(int S[ ], int size, int t)
{
for(int si=0; si<size; si++)
{
if(S[si]==t)
return true;
}
return false;
}
bool isSubset(int A1[ ], int sizeA1,
int A2[ ], int sizeA2)
{
int count = 0;
for (int ai = 0; ai <= sizeA1 - 1; ai++)
{
if(!isPresent(A2, sizeA2, A1[ai]))
return false;
// remember that A1[ai] is present
}
return true;
}
void UNION(int A[ ], int sizeA, int B[ ],
int sizeB, int UnionSet[ ], int &sizeU)
{
for (int ai=0; ai<=sizeA-1; ai++)
{
UnionSet[ai] = A[ai];
// Add all the elements in unionSet
}
int check = 0, ui = sizeA;
for (int bi=0; bi<= sizeB-1; bi++)
{
if(!isPresent(UnionSet,ui,B[bi]))
{// if B[bi] is not in UnionSet
UnionSet[ui] = B[bi];
ui++;
}
}
sizeU = ui;
//Sorting Union-Set
sort(UnionSet, sizeU);
}
void subsetTest(int A[ ], int sizeA,
int B[ ], int sizeB)
{
int count =0;
if (sizeA <= sizeB)
{ // checking A is subset of B
if(isSubset(A,sizeA,B,sizeB))
cout << "\nA is a subset of B.\n";
else
cout << "\n Neither is a subset \n";
}
else if (sizeA > sizeB)
{ // checking B is subset of A
if(isSubset(B,sizeB,A,sizeA))
cout << "\nB is a subset of A.\n";
else
cout << "\n Neither is a subset \n";
}
}
void intersection(int A[ ], int sizeA,
int B[ ], int sizeB,
int IntersectionSet[ ],int& iSize)
{
int ii = 0;
int check;
for (int bi = 0; bi <= sizeB - 1; bi++)
{
if(isPresent(A, sizeA, B[bi]))
{
IntersectionSet[ii] = B[bi];
ii++;
}
check = 0;
}
iSize = ii;
}
void setMinus(int A1[ ], int sizeA1,
int A2[ ], int sizeA2,
int R[ ], int &sizeR)
{
bool found;
int mi = 0;
for (int ai = 0; ai <= sizeA1-1; ai++)
{
if(!isPresent(A2, sizeA2, A1[ai]))
{
R[mi] = A1[ai];
mi++;
}
}
sizeR = mi;
}
void crossProduct(const char Msg[],
int A1[],int sizeA1,int A2[],int sizeA2)
{
cout << Msg<<": = {\n";
for (int ai = 0; ai <= sizeA1-1; ai++)
{
cout << "\t\t\t";
for (int bi = 0; bi<=sizeA2-1;bi++)
{
cout<<"("<<A1[ai]<<", "
<< A2[bi] << ")";
// not printing comma ',' at the end
if (bi!=(sizeA2-1)||ai!=(sizeA1-1))
cout << ", ";
}
cout << endl;
}
cout<<"\t}";
}
int main()
{
const int capacity = 500;
int A[capacity] = { 0 }, B[capacity] = { 0 }, sizeA, sizeB;
ifstream rdr("Sets.txt");
loadSet("A",A, sizeA, rdr);
loadSet("B",B, sizeB, rdr);
// Tast 2 - Sorting the two sets
// Sorting A and B
sort(A, sizeA);
sort(B, sizeB);
//Task 3 - Displaying the two sets
setPrint("A", A, sizeA);
setPrint("B", B, sizeB);
//Task 4 A is a Subset of B or B is a subset of A or none.
subsetTest(A, sizeA, B, sizeB);
//Task 5
int UnionSet[500] = { 0 };
int sizeU;
UNION(A, sizeA, B, sizeB, UnionSet, sizeU);
setPrint("A U B", UnionSet, sizeU);
//Task6
int IntersectionSet[500] = { 0 };
int iSize;
intersection(A, sizeA, B, sizeB, IntersectionSet, iSize);
setPrint("A ^ B", IntersectionSet, iSize);
//Task 7
int AMinusB[500];
int minusSize;
setMinus(A, sizeA, B, sizeB, AMinusB, minusSize);
setPrint("A-B", AMinusB, minusSize);
int BMinusA[500];
setMinus(B, sizeB, A, sizeA, BMinusA, minusSize);
setPrint("B-A", BMinusA, minusSize);
//Task 8
crossProduct("AxB",A, sizeA, B, sizeB);
return 0;
}

Pros of using functions

From the 2nd implementation, we have the following very important points,

  • Modularized code looks much cleaner.
  • It is much more manageable.
  • Functional implementation has significantly reduced redundancies in the code.
  • While coding such a huge program, errors arising are a natural occurrence. If the code is in modularized/functional form, it is much more easily debugged.
  • Modularized code is considered a great precious programming skill. Without it, you cannot work with other programmers because your code will not be usable by others.