Code360 powered by Coding Ninjas X Naukri.com. Code360 powered by Coding Ninjas X Naukri.com
Table of contents
1.
Introduction
1.1.
Problem Statement
1.2.
Sample Examples
2.
Approach (Using STL)
2.1.
Algorithm
2.2.
Implementation in C++
2.2.1.
Time Complexity
2.2.2.
Space complexity
3.
Implementing our own Iterator Pattern
3.1.
Algorithm
3.2.
Implementation in C++
3.2.1.
Time Complexity
3.2.2.
Space complexity
4.
Frequently Asked Questions
4.1.
What is STL in C++?
4.2.
What is an iterator in C++?
4.3.
Why are iterators used in C++?
5.
Conclusion
Last Updated: Mar 27, 2024

Implement iterator pattern of a Singly Linked List

Author Harsh
0 upvote

Introduction

The Standard Template Library (STL) is a collection of C++ template classes for popular programming data structures and functions like lists, stacks, and arrays. It's a container library with algorithms, iterators, and container classes. Knowing the internal structure of these algorithms will be very beneficial as you will get to know how they are internally working. 

So, In this blog, we will look at one of those various algorithms and implement our own iterator pattern.

Problem Statement

In this problem, we will implement our own iterator pattern of a singly Linked List.

Sample Examples

Input

 

Output

1 2 3 4 5

 

Explanation

We're displaying numbers one by one as we go through the linked list.

Also read - Merge sort in linked list

Approach (Using STL)

Our lives are made a lot easier when we use the STL (Standard Template Library) in C++. We don't need to waste time writing and implementing lengthy codes because they are already available.

So, Before implementing our own iterator pattern lets understand how iterator available in STL works.

Algorithm

  1. Define a new List
     
  2. Add elements to it using the inbuilt “push_back()” function.
     
  3. Define a new iterator and assign it to “list.begin()”.
     
  4. Print the value.
     
  5. Increment iterator by one.
     
  6. Repeat step 4 and step 5 until iterator reaches “list.end()”.

Implementation in C++

// C++ Code to implement the iterator.
#include <bits/stdc++.h>
using namespace std;


int main(){
    // defining our new list
    list<int> l;


    // adding elements into our list
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);
    l.push_back(4);
    l.push_back(5);


    // defining iterator
    list<int>::iterator it = l.begin();


    // printing
    for(it; it != l.end(); it++){
        cout << *it << ' ';
    }
    cout << endl;
    
    return 0;
}
You can also try this code with Online C++ Compiler
Run Code

 

Output

1 2 3 4 5

Time Complexity

As we are only traversing the list to the overall time complexity will be O(n).

Space complexity

Since no extra space is used the space complexity will be O(1).

Also see, Rabin Karp Algorithm

Implementing our own Iterator Pattern

Although using STL makes our lives easier but it is always good to have a clear knowledge of the internal structure of the algorithm you are using so that you can get a clear picture of what's happening.

Our goal would be to implement push_back(), end(), and begin() methods so that we can use our Class just like we were using the implementation of STL.

Before Implementation let’s first look at the Algorithm or Steps that we can follow.

Algorithm

  1. Create a custom LinkedList class with methods like push_back, traverse.
     
  2. Create the Node class which represents the single Node in our list.
     
  3. Create an Iterator class inside our LinkedList class and using operator overloading define the functionality of different operators.
     
  4. Using the Iterator class define two methods namely begin() and end() which will return the start and the end of our linkedlist.
     
  5. Finally using all the defined method create a list and traverse it.

Implementation in C++

// C++ Code to implement the iterator.
#include <bits/stdc++.h>
using namespace std;


// Custom linkedlist class
template<typename T> class List {
private:
    // represents a single node
    class Node{
        T data;
        Node *next;


        // LinkedList can access private members of Node
        friend class List;
    };


    // takes in the data and returns the newly created node
    Node *getNode(T data){
        Node *newNode = new Node;
        newNode->data = data;
        newNode->next = nullptr;


        return newNode;
    }


    // returns rootnode
    Node* &getRootNode(){
        return rootNode;
    }


    // static declaration
    static Node *rootNode;


public:


    // constructor
    List<T>() {
        rootNode = nullptr;
    }


    // Iterator class
    class Iterator{
        private:
            const Node* currentNode;
        public:
            // constructor
            Iterator() : currentNode(rootNode){ }
            Iterator(const Node* node) : currentNode (node) { }


            // overloading = operator
            Iterator& operator=(Node* node){
                this->currentNode = node;
                return *this;
            } 


            // overloading ++ operator (postfix)
            Iterator& operator++(){
                if(currentNode){
                    currentNode = currentNode->next;
                }
                return *this;
            }
            
            // overloading ++ operator (prefix)
            Iterator operator++(int){
                Iterator it = *this;
                ++*this;
                return it;
            }


            // != operator overloading
            bool operator!= (const Iterator& it){
                return currentNode != it.currentNode;
            }


            // * operator overloading
            int operator*(){
                return currentNode->data;
            }
            
    };


    // returns the iterator pointing at the start of our list
    Iterator begin(){
        return Iterator(rootNode);
    }


    // returns iterator pointing at the end of the list.
    Iterator end() {
        return Iterator(nullptr);
    }
    
    // implementation of push_back
    // adds the data at the end of our list
    void push_back(T data){
        Node *temp = getNode(data);
        if(getRootNode() == nullptr){
            getRootNode() = temp;
        }
        else {
            Node *head = getRootNode();
            while(head->next){
                head = head->next;
            }
            head->next = temp;
        }


    }


    // traversing our list
    void traverse(){
        Node *head = getRootNode();
        while(head){
            cout << head->data << " ";
            head = head->next;
        }
        cout << '\n';
    }
    
};


// static variable initialisation
template <typename T> typename List<T>::Node* List<T>::rootNode = nullptr;


// main method
int main(){


    // creating our list
    List<int> list;


    // adding elements
    list.push_back(1);
    list.push_back(2);
    list.push_back(3);
    list.push_back(4);
    list.push_back(5);


    // traversing using method
    cout << "Traversing using method: ";
    list.traverse();


    // traversing using iterator
    cout << "Traversing using Iterator: ";
    for (List<int>::Iterator it = list.begin(); it != list.end(); it++){
        cout << *it << ' ';
    }
    cout << '\n';
    
    return 0;
}
You can also try this code with Online C++ Compiler
Run Code

 

Output

Traversing using method: 1 2 3 4 5 
Traversing using Iterator: 1 2 3 4 5

Time Complexity

As we are only traversing the list to the overall time complexity will be O(n).

Space complexity

Since no extra space is used the space complexity will be O(1).

Must Read:  Java List Iterator

Frequently Asked Questions

What is STL in C++?

The C++ STL (standard template library) is a software library that provides a collection of templates that represent containers, iterators, algorithms, and function objects in the C++ programming language.

What is an iterator in C++?

An iterator is a C++ Standard Library container object that can loop over elements and provides access to individual elements.

Why are iterators used in C++?

We can use an iterator to go from one element to another. An iterator's key benefit is that it provides a common interface for all container types.

Conclusion

In this article, we have implemented our own Iterator pattern in a Singly linked list and also shown the difference between the normal traversal and the traversing using an iterator.

We hope that this blog has enhanced your knowledge and cleared all of your doubts regarding the above question. Check out our articles on our Website to learn more 

Visit our Guided Path on Coding Ninjas Studio to upskill yourself in Competitive ProgrammingData Structures and AlgorithmsSystem DesignJavaScript, and many more! Check out the mock test series and participate in the contests hosted on Coding Ninjas Studio to test your proficiency in coding. But if you have just started your learning process and are looking for questions asked by tech giants like Amazon, Microsoft, etc; you must look at the interview experiences, problems, and interview bundle for placement preparations.

Nevertheless, you can also consider our paid courses to give your career an edge over others!

Do upvote the blog if you find it helpful and engaging!

Happy Learning!

Live masterclass