Implementing Iterator pattern of a single Linked List
Last Updated :
20 Dec, 2023
STL is one of the pillars of C++. It makes life a lot easier, especially when your focus is on problem-solving and you don’t want to spend time implementing something that is already available which guarantees a robust solution. One of the key aspects of Software Engineering is to avoid reinventing the wheel. Reusability is always preferred.
While relying on library functions directly impacts our efficiency, without having a proper understanding of how it works sometimes loses the meaning of the engineering efficiency we keep on talking about. A wrongly chosen data structure may come back sometime in the future to haunt us. The solution is simple. Use library methods, but know how does it handle operations under the hood.
Enough said! Today we will look at how we can implement our own Iterator pattern of a single Linked List. So, here is how an STL implementation of Linked List looks like:
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
int main()
{
// creating a list
vector<int> list;
// elements to be added at the end.
// in the above created list.
list.push_back(1);
list.push_back(2);
list.push_back(3);
// elements of list are retrieved through iterator.
for (vector<int>::iterator it = list.begin();
it != list.end(); ++it)
cout << *it << " ";
return 0;
}
Java
import java.util.*;
class GFG
{
public static void main(String[] args)
{
// creating a list
ArrayList<Integer> list = new ArrayList<>();
// elements to be added at the end.
// in the above created list.
list.add(1);
list.add(2);
list.add(3);
// elements of list are retrieved through iterator.
Iterator<Integer> it = list.iterator();
while (it.hasNext())
{
System.out.print(it.next() + " ");
}
}
}
// This code is contributed by pratham76
Python3
if __name__=='__main__':
# Creating a list
list = []
# Elements to be added at the end.
# in the above created list.
list.append(1)
list.append(2)
list.append(3)
# Elements of list are retrieved
# through iterator.
for it in list:
print(it, end = ' ')
# This code is contributed by rutvik_56
C#
using System;
using System.Collections.Generic;
public class GFG {
public static void Main(String[] args) {
// creating a list
List<int> list = new List<int>();
// elements to be added at the end.
// in the above created list.
list.Add(1);
list.Add(2);
list.Add(3);
// elements of list are retrieved through iterator.
foreach (int it in list) {
Console.Write(it + " ");
}
}
}
// This code contributed by umadevi9616
JavaScript
<script>
// creating a list
var list = [];
// elements to be added at the end.
// in the above created list.
list.push(1);
list.push(2);
list.push(3);
// elements of list are retrieved through iterator.
for (var i = 0; i<list.length;i++) {
document.write(list[i] + " ");
}
// This code contributed by umadevi9616
</script>
One of the beauties of cin and cout is that they don’t demand format specifiers to work with the type of data. This combined with templates makes the code much cleaner and readable. Although I prefer the naming method in C++ to start with caps, this implementation follows STL rules to mimic the exact set of method calls, viz push_back, begin, end.
Here is our own implementation of LinkedList and its Iterator pattern:
C++
// C++ program to implement Custom Linked List and
// iterator pattern.
#include <bits/stdc++.h>
using namespace std;
// Custom class to handle Linked List operations
// Operations like push_back, push_front, pop_back,
// pop_front, erase, size can be added here
template <typename T>
class LinkedList
{
// Forward declaration
class Node;
public:
LinkedList<T>() noexcept
{
// caution: static members can't be
// initialized by initializer list
m_spRoot = nullptr;
}
// Forward declaration must be done
// in the same access scope
class Iterator;
// Root of LinkedList wrapped in Iterator type
Iterator begin()
{
return Iterator(m_spRoot);
}
// End of LInkedList wrapped in Iterator type
Iterator end()
{
return Iterator(nullptr);
}
// Adds data to the end of list
void push_back(T data);
void Traverse();
// Iterator class can be used to
// sequentially access nodes of linked list
class Iterator
{
public:
Iterator() noexcept :
m_pCurrentNode (m_spRoot) { }
Iterator(const Node* pNode) noexcept :
m_pCurrentNode (pNode) { }
Iterator& operator=(Node* pNode)
{
this->m_pCurrentNode = pNode;
return *this;
}
// Prefix ++ overload
Iterator& operator++()
{
if (m_pCurrentNode)
m_pCurrentNode = m_pCurrentNode->pNext;
return *this;
}
// Postfix ++ overload
Iterator operator++(int)
{
Iterator iterator = *this;
++*this;
return iterator;
}
bool operator!=(const Iterator& iterator)
{
return m_pCurrentNode != iterator.m_pCurrentNode;
}
int operator*()
{
return m_pCurrentNode->data;
}
private:
const Node* m_pCurrentNode;
};
private:
class Node
{
T data;
Node* pNext;
// LinkedList class methods need
// to access Node information
friend class LinkedList;
};
// Create a new Node
Node* GetNode(T data)
{
Node* pNewNode = new Node;
pNewNode->data = data;
pNewNode->pNext = nullptr;
return pNewNode;
}
// Return by reference so that it can be used in
// left hand side of the assignment expression
Node*& GetRootNode()
{
return m_spRoot;
}
static Node* m_spRoot;
};
template <typename T>
/*static*/ typename LinkedList<T>::Node* LinkedList<T>::m_spRoot = nullptr;
template <typename T>
void LinkedList<T>::push_back(T data)
{
Node* pTemp = GetNode(data);
if (!GetRootNode())
{
GetRootNode() = pTemp;
}
else
{
Node* pCrawler = GetRootNode();
while (pCrawler->pNext)
{
pCrawler = pCrawler->pNext;
}
pCrawler->pNext = pTemp;
}
}
template <typename T>
void LinkedList<T>::Traverse()
{
Node* pCrawler = GetRootNode();
while (pCrawler)
{
cout << pCrawler->data << " ";
pCrawler = pCrawler->pNext;
}
cout << endl;
}
//Driver program
int main()
{
LinkedList<int> list;
// Add few items to the end of LinkedList
list.push_back(1);
list.push_back(2);
list.push_back(3);
cout << "Traversing LinkedList through method" << endl;
list.Traverse();
cout << "Traversing LinkedList through Iterator" << endl;
for ( LinkedList<int>::Iterator iterator = list.begin();
iterator != list.end(); iterator++)
{
cout << *iterator << " ";
}
cout << endl;
return 0;
}
Java
import java.util.Iterator;
// Custom class to handle Linked List operations
// Operations like push_back, push_front, pop_back,
// pop_front, erase, size can be added here
public class LinkedList<T> implements Iterable<T> {
// Forward declaration
private class Node {
T data;
Node next;
// LinkedList class methods need
// to access Node information
Node(T data) {
this.data = data;
this.next = null;
}
}
// Root of LinkedList wrapped in Iterator type
public Iterator<T> iterator() {
return new Iterator<T>() {
private Node current = root;
public boolean hasNext() {
return current != null;
}
public T next() {
T data = current.data;
current = current.next;
return data;
}
};
}
// Root of LinkedList wrapped in Iterator type
Iterator<T> begin() {
return iterator();
}
// End of LInkedList wrapped in Iterator type
Iterator<T> end() {
return null;
}
// Adds data to the end of list
void push_back(T data) {
Node temp = new Node(data);
if (root == null) {
root = temp;
} else {
Node crawler = root;
while (crawler.next != null) {
crawler = crawler.next;
}
crawler.next = temp;
}
}
void traverse() {
Node crawler = root;
while (crawler != null) {
System.out.print(crawler.data + " ");
crawler = crawler.next;
}
System.out.println();
}
private Node root;
// Driver program
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
// Add few items to the end of LinkedList
list.push_back(1);
list.push_back(2);
list.push_back(3);
System.out.println("Traversing LinkedList through method");
list.traverse();
System.out.println("Traversing LinkedList through Iterator");
for (int item : list) {
System.out.print(item + " ");
}
System.out.println();
}
}
// This code is contributed by shivamgupta0987654321
Python3
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.root = None
def push_back(self, data):
new_node = Node(data)
if not self.root:
self.root = new_node
else:
crawler = self.root
while crawler.next:
crawler = crawler.next
crawler.next = new_node
def traverse(self):
crawler = self.root
while crawler:
print(crawler.data, end=" ")
crawler = crawler.next
print()
class Iterator:
def __init__(self, current_node):
self.current_node = current_node
def __iter__(self):
return self
def __next__(self):
if self.current_node:
data = self.current_node.data
self.current_node = self.current_node.next
return data
else:
raise StopIteration
def __iter__(self):
return self.Iterator(self.root)
# Driver program
if __name__ == "__main__":
linked_list = LinkedList()
# Add few items to the end of LinkedList
linked_list.push_back(1)
linked_list.push_back(2)
linked_list.push_back(3)
print("Traversing LinkedList through method")
linked_list.traverse()
print("Traversing LinkedList through Iterator")
for item in linked_list:
print(item, end=" ")
print()
C#
using System;
// Custom class to handle Linked List operations
// Operations like push_back, push_front, pop_back,
// pop_front, erase, size can be added here
public class LinkedList<T>
{
// Node class for the LinkedList
public class Node
{
public T Data { get; set; }
public Node Next { get; set; }
}
// Iterator class for the LinkedList
public class Iterator
{
private Node currentNode;
public Iterator(Node node)
{
currentNode = node;
}
// Prefix ++ overload
public Iterator Next()
{
if (currentNode != null)
currentNode = currentNode.Next;
return this;
}
// Postfix ++ overload
public Iterator Next(int n)
{
Iterator iterator = new Iterator(currentNode);
for (int i = 0; i < n; i++)
iterator.Next();
return iterator;
}
public bool NotEquals(Iterator iterator)
{
return currentNode != iterator.currentNode;
}
public T GetData()
{
return currentNode.Data;
}
}
private Node root;
public LinkedList()
{
root = null;
}
// Root of LinkedList wrapped in Iterator type
public Iterator Begin()
{
return new Iterator(root);
}
// End of LinkedList wrapped in Iterator type
public Iterator End()
{
return new Iterator(null);
}
// Adds data to the end of the list
public void PushBack(T data)
{
Node temp = GetNode(data);
if (root == null)
{
root = temp;
}
else
{
Node crawler = root;
while (crawler.Next != null)
{
crawler = crawler.Next;
}
crawler.Next = temp;
}
}
public void Traverse()
{
Node crawler = root;
while (crawler != null)
{
Console.Write(crawler.Data + " ");
crawler = crawler.Next;
}
Console.WriteLine();
}
// Create a new Node
private Node GetNode(T data)
{
return new Node { Data = data, Next = null };
}
}
// Driver program
class Program
{
static void Main()
{
LinkedList<int> list = new LinkedList<int>();
// Add few items to the end of LinkedList
list.PushBack(1);
list.PushBack(2);
list.PushBack(3);
Console.WriteLine("Traversing LinkedList through method");
list.Traverse();
Console.WriteLine("Traversing LinkedList through Iterator");
for (LinkedList<int>.Iterator iterator = list.Begin();
iterator.NotEquals(list.End()); iterator.Next())
{
Console.Write(iterator.GetData() + " ");
}
Console.WriteLine();
}
}
// This code is contributed by shivamgupta0987654321
JavaScript
// Node class for LinkedList
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
// Custom class to handle Linked List operations
// Operations like push_back, push_front, pop_back,
// pop_front, erase, size can be added here
class LinkedList {
// Root of LinkedList wrapped in Iterator type
* [Symbol.iterator]() {
let current = this.root;
while (current !== null) {
yield current.data;
current = current.next;
}
}
// Root of LinkedList wrapped in Iterator type
begin() {
return this[Symbol.iterator]();
}
// End of LinkedList wrapped in Iterator type
end() {
return null;
}
// Adds data to the end of list
push_back(data) {
const temp = new Node(data);
if (this.root === null) {
this.root = temp;
} else {
let crawler = this.root;
while (crawler.next !== null) {
crawler = crawler.next;
}
crawler.next = temp;
}
}
traverse() {
let crawler = this.root;
while (crawler !== null) {
console.log(crawler.data + " ");
crawler = crawler.next;
}
console.log();
}
constructor() {
this.root = null;
}
}
// Driver program
const list = new LinkedList();
// Add few items to the end of LinkedList
list.push_back(1);
list.push_back(2);
list.push_back(3);
console.log("Traversing LinkedList through method");
list.traverse();
console.log("Traversing LinkedList through Iterator");
for (const item of list) {
console.log(item + " ");
}
console.log();
OutputTraversing LinkedList through method
1 2 3
Traversing LinkedList through Iterator
1 2 3
Exercise:
The above implementation works well when we have one data. Extend this code to work for a set of data wrapped in a class.
Similar Reads
Implementation of stack using Doubly Linked List
Stack and doubly linked lists are two important data structures with their own benefits. Stack is a data structure that follows the LIFO (Last In First Out) order and can be implemented using arrays or linked list data structures. Doubly linked list has the advantage that it can also traverse the pr
14 min read
Implementation of XOR Linked List in Python
Prerequisite: XOR Linked List An ordinary Doubly Linked List requires space for two address fields to store the addresses of previous and next nodes. A memory-efficient version of Doubly Linked List can be created using only one space for the address field with every node. This memory efficient Doub
6 min read
Operations of Doubly Linked List with Implementation
A Doubly Linked List (DLL) contains an extra pointer, typically called the previous pointer, together with the next pointer and data which are there in a singly linked list. Below are operations on the given DLL: Add a node at the front of DLL: The new node is always added before the head of the giv
15+ min read
Implement a stack using singly linked list
To implement a stack using a singly linked list, we need to ensure that all operations follow the LIFO (Last In, First Out) principle. This means that the most recently added element is always the first one to be removed. In this approach, we use a singly linked list, where each node contains data a
13 min read
Implementation of Deque using doubly linked list
A Deque (Double-Ended Queue) is a data structure that allows adding and removing elements from both the front and rear ends. Using a doubly linked list to implement a deque makes these operations very efficient, as each node in the list has pointers to both the previous and next nodes. This means we
9 min read
Queue - Linked List Implementation
In this article, the Linked List implementation of the queue data structure is discussed and implemented. Print '-1' if the queue is empty.Approach: To solve the problem follow the below idea:we maintain two pointers, front and rear. The front points to the first item of the queue and rear points to
8 min read
Print alternate nodes of a linked list using recursion
Given a linked list, print alternate nodes of this linked list. Examples : Input : 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 Output : 1 -> 3 -> 5 -> 7 -> 9 Input : 10 -> 9 Output : 10 Recursive Approach : Initialize a static variable(say flag) If flag
6 min read
Recursive approach for alternating split of Linked List
Given a linked list, split the linked list into two with alternate nodes. Examples: Input : 1 2 3 4 5 6 7 Output : 1 3 5 7 2 4 6 Input : 1 4 5 6 Output : 1 5 4 6 We have discussed Iterative splitting of linked list. The idea is to begin from two nodes first and second. Let us call these nodes as 'a'
7 min read
Find Length of a Linked List (Iterative and Recursive)
Given a Singly Linked List, the task is to find the Length of the Linked List.Examples:Input: LinkedList = 1->3->1->2->1Output: 5Explanation: The linked list has 5 nodes.Input: LinkedList = 2->4->1->9->5->3->6Output: 7 Explanation: The linked list has 7 nodes.Input: Lin
11 min read
Iteratively Reverse a linked list using only 2 pointers (An Interesting Method)
Given pointer to the head node of a linked list, the task is to reverse the linked list. Examples: Input : Head of following linked list 1->2->3->4->NULL Output : Linked list should be changed to, 4->3->2->1->NULL Input : Head of following linked list 1->2->3->4->
13 min read