×

Implementing the sets without C++ STL containers

Many practical features and tools in C++ support us in programming competitions. One of these parts is a set from the Standard Template Library (STL), which offers an effective way to keep data sorted. All the fundamentals regarding implementing sets without STL containers are covered in this C++ set lesson.

In the C++ STL, sets are the containers used to store things in a certain order. A set must have distinct components. Each element in a set may be identified by the value alone, serving as the key itself. In C++, items can be added to or removed from sets, but they cannot be changed after being stored there since their values become constant.

What is a Set in C++ ?

As was already established, sets are the kind of STL containers used in C++ to store elements in an ordered manner. The operations that are allowed to be performed on the sets include insertion and deletion. In a set type container, the items are internally sorted in accordance with a rigid weak ordering. Users are unable to change or alter the values of the already-existing items in a set since they are constant in the containers. Sets are only permitted to contain unique values as a result.

In C++, we employ iterators to traverse sets. The couple of header files that are required to deal with sets in C++ are <set> and <iterators>. The < bits/stdc++> serves as a replacement to these two header files. Binary Search Trees (BST) are used for the implementation of sets internally.

Methods that can be performed on a set :

In C++, a broad range of operations may be carried out on sets. Let's examine some of the key set ways.

  • insert(value) :
    adds a key element with value to the set.
    Time Complexity : O(h), here the h represents the tree's height.
    Space Complexity : O(1)
  • _union(s) :
    returns a set that was produced by union with "set s".
    Time Complexity : O((n+m)*h), where n and m are the number of items in sets and h is the tree's height.
    Space complexity : O(n+m)
  • _intersection(s) :
    returns a set that was produced by intersection with "set s."
    Time Complexity : O(n*h), where n represents the number of items in sets and h is the tree's height.
    Space Complexity : O(n)
  • _complement(U) :
    Complementary set of a Universal set "Set U" is returned.
    Time Complexity : O(n*h), where n represents the number of items in sets and h is the tree's height.
    Space Complexity : O(n)
  • _array() :
    Returns an array that is made up of every element in the set.
    Time Complexity : O(n)
    Space Complexity : O(n)
  • _size() :
    Returns the set's total number of items.
    Time Complexity : O(1)
    Space Complexity : O(1)

Implementation of sets using the BST :

We have explained the implementation of sets using the BST procedure with the help of an example below :

Program :

#include <algorithm>  
#include <iostream>  
#include <math.h>  
#include <stack>  
#include <string>  
using namespace std;  
  
template <typename T>  
struct Node { // Creating the node of the BST  
  
    T data; // Node’s value  
  
    Node* leftwards; // Pointer to the left-hand side child  
  
    Node* rightwards; // Pointer to the right-hand side child  
  
public:  
    // inOrder() function prints the inorder traversal of the BST  
    void inOrder(Node* r)  
    {  
        if (r == NULL) { // If it reaches the last level  
            return;  
        }  
        inOrder(r->leftwards); // printing the left child  
        cout << r->data << " "; // printing the node value  
        inOrder(r->rightwards); // printing the right child  
    }  
  
    /* 
        Method to check whether the BST contains a node 
        with the given piece of data 
         
        r is the pointer towards the root node 
         d is the data to search in the BST 
        The function will return 1 if the node is present in the BST otherwise it will print 0 
    */  
    int containNode(Node* r, T d)  
    {  
        if (r == NULL) { // If it reaches the last level or the tree is empty  
            return 0;  
        }  
        int x = r->data == d ? 1 : 0; // Checking for duplicacy  
        // Traversing in the right and left subtree  
        return x | containNode(r->leftwards, d) | containNode(r->rightwards, d);  
    }  
  
    /* 
        Method to insert a node with the
        given data into BST 
         
        r is the pointer to the root node in BST  
        d is the data to be inserted in the BST 
        return the pointer to the root of resultant BST 
    */  
    Node* insert(Node* r, T d)  
    {  
  
        if (r == NULL) { // Adding where NULL is encountered meaning the space is present  
            Node<T>* temp = new Node<T>; // Creating a new node in the BST  
            temp->data = d; // inserting the data in BST  
            temp->leftwards = temp->rightwards = NULL; // Allocating the left and the right pointers a NULL  
            return temp; // returning the current node  
        }  
  
        //    Inserting the node in the left subtree if the data is lesser than the current node data  
        if (d < r->data) {  
            r->leftwards = insert(r->leftwards, d);  
            return r;  
        }  
  
        //   Inserting the node in the right subtree if the data is greater than the current node data  
        else if (d > r->data) {  
            r->rightwards = insert(r->rightwards, d);  
            return r;  
        }  
        else  
            return r;  
    }  
};  
  
template <typename T> // creating a class template for the implementation of a set in the BST  
class Set { // Creating the class set  
  
    Node<T>* root; // Root to store the data  
  
    int size; // this indicates the size of set  
  
public:  
    Set() // If no value is passed  
    {  
        root = NULL; // It points towards the NULL  
        size = 0; // this means the size will be zero  
    }  
  
    Set(const Set& s) // Copy constructor  
    {  
        root = s.root;  
        size = s.size;  
    }  
  
    void add(const T data) // It adds an element to set  
    {  
        if (!root->containNode(root, data)) { // Checking if it is the first element or not 
            root = root->insert(root, data); // Inserting of the data into the set  
            size++; // Increment the size of the set  
        }  
    }  
  
    bool contain(T data)  
    {  
        return root->containNode(root, data) ? true : false;  
    }  
  
    void displaysSet()  
    {  
        cout << "{ ";  
        root->inOrder(root);  
        cout << "}" << endl;  
    }  
  
    /* 
        Method for returning the current size of the Set 
          
        @return is the size of the set 
    */  
    int getSize()  
    {  
        return size;  
    }  
};  
  
int main()  
{  
  
    // Creating the Set X  
    Set<int> X;  
  
    // Adding elements to the Set X  
    X.add(10);  
    X.add(20);  
    X.add(30);  
    X.add(20);  
  
    // Displaying the contents of the Set X
    cout << "X = ";  
    X.displaysSet();  
  
    // Checking if the Set X contains some of the elements  
    cout << "X " << (X.contain(30) ? "contains"  
                                   : "does not contain")  
         << " 30" << endl;  
    cout << "X " << (X.contain(40) ? "contains"  
                                   : "does not contain")  
         << " 40" << endl;  
    cout << endl;  
  
    return 0;  
}  

Output :

X = { 1 2 3 }
X contains 30
X does not contain 40

Explanation :

In the above example, internally, the set data structure uses the BST (Binary Search Tree) data structure. In order to implement the Set, we added the components to the tree and utilised this tree template. We made a BST template. Three components made up the tree : the node's data, its left and right pointers, and its members.

We used the insert() function to add the nodes to the tree once it had been created. The BST placed the data that was lesser than the root on the left hand side of the tree and the bigger data on the right. The function ContainNode() was used to determine if a node is there in the tree or not. The BST's inorder traversal was printed using the inOrder() method. The BST template was put into action in the Set class. The set template was mainly made to implement the BST once the BST had been built for the set's internal operation. The size variable was used to return the size of the set, and it contained a root pointer node to hold the data. The Set class provided a copy constructor that copied a set into the other set and a default constructor that initialised the root of BST as NULL.

The values in the set were added using the method add(). By invoking the method containNode(), it did not add the already added data to the set. Then, if a new element was present, the set was expanded. The contain() method determined if a certain element was present in the set or not at that particular time. In the BST, contain() method internally called containNode(). The set items were printed using the displaysSet() method. Internally, it used the BST's inOrder() method. The size of the set was returned by the getSize() method.


Related Topics

OOPs Concepts in C++

C++ Object-Oriented Programming Concepts C++ uses the concept of object-oriented programming. Object Oriented Programming has some prominent features: Object Class Data abstraction Encapsulation Polymorphism Inheritance Message passing Object An object is the basic unit...

2 minutes read.

C++ Reading file

In file handling, read() function is used to read data from the file into the program. The read() uses ifstream library to read data from a file. Syntax file-stream-class   file-stream-object;   file-stream-object.read((char *)&var , sizeof (var)); <h3">Example ofstream  outfile;         outfile . read((char*)&emp,sizeof(emp)); C++ File Handling read() Function Example Reading the content of existing...

2 minutes read.

C++ Date and Time

The date and time formats in C++ will be covered in this article. Because C++ lacks a proper date and time format, we must rely on the c language. The...

7 minutes read.

C++ Fibonacci Series

What is a Fibonacci series? A Fibonacci series or sequence is a very popular programming paradigm. The next element occurring in the N terms series is determined by the sum of...

2 minutes read.

C++ First Program

Let's write a simple basic program structure of C++, its compilation and its execution (how it runs). This program is compiled using GCC compiler. Open any editor to write C++ program. #include<iostream>   using namespace std;   int main(){       cout<<"Welcome to C++ program"<<endl;   } Output...

2 minutes read.

C++ array to function

Arrays in C++ : Instead of defining distinct variables for each item, arrays are used to hold numerous values in a single variable. An array can be declared by specifying the variable...

4 minutes read.

Differences between Local and Global Variable

Define Global Variable Global variables are those that may be accessible worldwide across a programme and are defined outside of any functions or blocks. It may be accessed by any function in...

3 minutes read.

C++ Try-Catch

Every useful program will eventually encounter unexpected outcomes. By entering data that are incorrect, users might create mistakes. Sometimes the program's creator didn't consider all of the options or was...

7 minutes read.

C++ Recursion Function

A programming method called recursion that uses a function to call itself to address lesser problems. The Fibonacci sequence, factorial computation, and tree traversal are just a few of the...

4 minutes read.

C++ | C Plus Plus Data type

Data type in every language is very important. Data type means the different kinds of data that are supported by a particular programming language. A computer language’s data types specify the...

15 minutes read.

C++ Static

What is the Static keyword? In C++, the keyword static is used to give an element some particular properties. Static elements are only given storage in the static storage region once...

4 minutes read.

gmtime() function in C/C++

C++ language is used to make high-performance applications that can work efficiently. It is one of the world's most popular languages. It is an object-oriented and high-level programming language, which...

4 minutes read.

Boost split in C++ library

Boost::split in C++ library Boost offers strong tools for adding mature, well-tested libraries to the C++ standard library. The boost: split function, which is a component of the Boost string algorithm...

2 minutes read.

C++ Do while loop

In this article, we will discuss the C++ Do-While loop with its syntax, working, key features, algorithm, and examples. Do-While Loop: The do-while loop constitutes a specific style of looping construct in...

5 minutes read.

Skyline Problem in C++

We have given n rectangular buildings in a 2-dimensional city. Here, to compute the Skyline of the given n rectangle structures in a two-dimensional metropolis while removing hidden lines, the...

3 minutes read.

C++ Pointer

Pointer is a derived data type that stores the address of a variable. A pointer is used for memory management and dynamic memory allocation. Pointer works on the address of data rather than...

2 minutes read.

C++ Range-based For Loop

In C++ language, the range-based for loop was added, which is far superior than the ordinary For loop. The implementation of a range-based for loop doesn't really need much code. It's a...

4 minutes read.

C++ Bitset

Overview In C++, bitset represents a fixed-sequence of some bits values by either 0 and 1. Zero represents the value as false or unset, while 1 represents the value as true...

4 minutes read.

rand() and srand() in C / C++

In this tutorial, we'll explore the syntax, usage, and examples of the C++ STL functions rand() and srand(). What exactly is rand()? The C++ STL's built-in rand() function is defined in the...

3 minutes read.

C++ Scope of Variables

In this tutorial, we will explore about the scope of variables in c++ programming language. And also, how it works in a program. What is Scope? The range of applications for something...

4 minutes read.