Linked List in C/C++/java/Python
Linked List Introduction
Comparison & Time Complexity
Visual Representation
LinkedList in Collection Framework(Java)
Linked List is a part of the Collection framework present in java.util package. This class is an implementation of the LinkedList data structure which is a linear data structure where the elements are not stored in contiguous locations and every element is a separate object with a data part and address part. The elements are linked using pointers and addresses. Each element is known as a node.
Constructors in the LinkedList:
In order to create a LinkedList, we need to create an object of the LinkedList class. The LinkedList class consists of various constructors that allow the possible creation of the list. The following are the constructors available in this class:
- 1. LinkedList(): This constructor is used to create an empty list.
LinkedList<String> list = new LinkedList<String>();
- 2. LinkedList(Collection C): - This constructor is used to create an ordered list that contains all the elements of a specified collection, as returned by the collection’s iterator. If we wish to create a LinkedList with the name ll, then, it can be created as:
LinkedList<String> ll = new LinkedList<String>(Collection C);
Methods for Java LinkedList:
Methods | Description |
---|---|
add(int index, E element) | Inserts the specified element at the specified position in this list. |
addAll(int index, Collection<E> c) | Inserts all of the elements in the specified collection into this list, starting at the specified position. |
addAll(collection<E> c) | Appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's iterator. |
addFirst(E e) | Inserts the specified element at the beginning of this list. |
addLast(E e) | Appends the specified element to the end of this list. |
clear() | Removes all of the elements from this list. |
clone() | Returns a shallow copy of this LinkedList. |
contains(Object o) | Returns true if this list contains the specified element. |
descendingIterator() | Returns an iterator over the elements in this deque in reverse sequential order. |
element() | Retrieves, but does not remove, the head (first element) of this list. |
get(int index) | Returns the element at the specified position in this list. |
getFirst() | Returns the first element in this list. |
getLast() | Returns the last element in this list. |
indexOf(Object o) | Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. |
lastIndexOf(Object o) | Returns the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element. |
listIterator(int index) | Returns a list-iterator of the elements in this list (in proper sequence), starting at the specified position in the list. |
offer(E e) | Inserts the specified element at the end of this list. |
offerFirst(E e) | Inserts the specified element at the front of this list. |
offerLast(E e) | Inserts the specified element at the end of this list. |
peek() | Retrieves, but does not remove, the head (first element) of this list. |
peekFirst() | Retrieves, but does not remove, the first element of this list, or returns null if this list is empty. |
peekLast() | Retrieves, but does not remove, the last element of this list, or returns null if this list is empty. |
poll() | Retrieves and removes the head (first element) of this list. |
pollFirst() | Retrieves and removes the first element of this list, or returns null if this list is empty. |
pollLast() | Retrieves and removes the last element of this list, or returns null if this list is empty. |
pop() | Pops an element from the stack represented by this list. |
push(E e) | Pushes an element onto the stack represented by this list. |
remove(int index) | Removes the element at the specified position in this list. |
remove(Object o) | Removes the first occurrence of the specified element from this list, if it is present. |
removeFirst() | Removes and returns the first element from this list. |
removeFirstOccurrence(Object o) | Removes the first occurrence of the specified element in this list (when traversing the list from head to tail). |
removeLast() | Removes and returns the last element from this list. |
removeLastOccurrence(Object o) | Removes the last occurrence of the specified element in this list (when traversing the list from head to tail). |
set(int index, E element) | Replaces the element at the specified position in this list with the specified element. |
size() | Returns the number of elements in this list. |
toArray() | Returns an array containing all of the elements in this list in proper sequence (from first to last element). |
toArray(T[] a) | Returns an array containing all of the elements in this list in proper sequence (from first to last element); the runtime type of the returned array is that of the specified array. |
toString() | Returns a string representation of this collection. The string representation consists of a list of the collection's elements in the order they are returned by its iterator, enclosed in square brackets ("[]"). Adjacent elements are separated by the characters ", " (comma and space). Elements are converted to strings as by String.valueOf(Object). |
AbstractList:
This class is used to implement an unmodifiable list, for which one needs to only extend this AbstractList Class and implement only the get() and the size() methods.
CopyOnWriteArrayList:
This class implements the list interface. It is an enhanced version of ArrayList in which all the modifications(add, set, remove, etc.) are implemented by making a fresh copy of the list.
List in C++ Standard Template Library (STL)
List are sequence containers that allow non-contiguous memory allocation. As compared to vector, list has slow traversal, but once a position has been found, insertion and deletion are quick.
Functions Used with List
Functions | Description |
---|---|
front() | Returns a reference to the first element in the list container. |
back() | Returns a reference to the last element in the list container. |
push_front(g) | Adds a new element ‘g’ at the beginning of the list, like stack. |
push_back(g) | Adds a new element ‘g’ at the end of the list, like queue. |
pop_front() | Removes the first element in the list, and reduces size of the list by 1. |
pop_back() | Removes the last element in the list, and reduces size of the list by 1. |
list::begin() | Returns an iterator pointing to the first element in the list. |
list::end() | Returns an iterator pointing to the theoretical last element which follows the last element. |
list rbegin() and rend() | Returns a reverse iterator pointing to the last element in the list (reverse beginning). It moves from last to first element. |
list cbegin() and cend() | Returns a constant iterator pointing to the first element in the list. |
list crbegin() and crend() | Returns a constant reverse iterator pointing to the last element in the list (reverse beginning). It moves from last to first element. |
list::empty() | Returns whether the list is empty(1) or not(0). |
list::size() | Returns the number of elements in the list. |
insert() | Inserts new elements in the list before the element at a specified position. |
erase() | Removes a single element or a range of elements from the list. |
list::assign() | Assigns new elements to list by replacing current elements and resizes the list. |
list::remove() | Removes all the elements from the list, which are equal to given element. |
list::remove_if() | Removes all the elements satisfying specific criteria. |
lisr::reverse() | Reverses the list. |
reverse() | Reverses the order of the elements in the list container. |
list resize() | Resizes the container so that it contains ‘g’ elements. |
sort() | Sorts the list in ascending order. |
list max_size() | Returns the maximum number of elements that the list container can hold. |
list unique() | Removes all duplicate consecutive elements from the list. |
list::emplace_front() and list::emplace_back() | The function extends the container by inserting new element at position. |
list::clear() | Removes all the elements of the list container, thus making it size 0. |
list::operator= | Assigns new contents to the container, replacing its current contents, and modifying its size accordingly. |
list::swap() | Exchanges the content of the container by the content of ‘x’, which is another list object of the same type. Sizes may differ. |
list splice() | Transfers elements from list to list. |
list merge() | Merges two sorted lists into one. |
list emplace() | The function extends the container by inserting new element at position. |
list::emplace_back() | The function extends the container by inserting new element at position. |
list::emplace_front() | The function extends the container by inserting new element at position. |
Operations
Traversal
Traversal is the process of visiting each node in a linked list.
Approach
- The main Approach to traverse a linked list is to start from the head node and keep on visiting the next node until the last node is reached which points to NULL.
pseudocode
temp = head;
while (temp!=NULL)
{
temp = temp -> next;
}
Code Explanation
Code Implementation
#include<iostream>
using namespace std;
class Node
{
public:
int data;
Node *next;
Node(int d)
{
data=d;
next=NULL;
}
};
void insert(Node **head,int data)
{
Node *node=new Node(data);
node->next=NULL;
if(*head==NULL)
{
*head=node;
}
else
{
Node *temp=*head;
while(temp->next!=NULL)
{
temp=temp->next;
}
temp->next=node;
}
}
void traverse(Node *head)
{
Node *temp=head;
while(temp!=NULL)
{
cout<<temp->data<<endl;
temp=temp->next;
}
}
int main()
{
Node *head=NULL;
insert(&head,10);
insert(&head,20);
insert(&head,30);
insert(&head,40);
insert(&head,50);
traverse(head);
return 0;
}
output
10
20
30
40
50
Time Complexity
The time complexity of traversing a linked list is O(n) where n is the number of nodes in the linked list because we have to visit each node once to print its data.
Space Complexity
The space complexity of traversing a linked list is O(1) because we are not using any extra space.
Insertion
Insertion from the front end
Approach
pseudocode
NODE *FrontInsertion(int data, NODE *head){
NODE *newnode = createNode(data);
if(head == NULL){
head = newnode;
}
else{
newnode->next = head;
head = newnode;
}
return head;
}
Code Explanation
Code Implementation
#include<iostream>
using namespace std;
class Node
{
public:
int data;
Node *next;
};
void insertFirst (Node **head, int data)
{
Node *newnode = new Node();
newnode->data = data;
newnode->next = *head;
*head = newnode;
}
void printList(Node *head)
{
while(head != NULL)
{
cout<<head->data<<" ";
head = head->next;
}
}
int main()
{
Node *head = NULL;
insertFirst(&head, 1);
insertFirst(&head, 2);
insertFirst(&head, 3);
insertFirst(&head, 4);
insertFirst(&head, 5);
printList(head);
return 0;
}
output
5 4 3 2 1
Time Complexity
The time complexity of insert at the front is O(1) because we are inserting the element at the beginning of the list and we don’t need to traverse the list to find the last element.
Space Complexity
The space complexity of insert at the front is O(1) because we are not using any extra space.
Insertion from the back end
Approach
pseudocode
NODE *InsertatIndex(int data, NODE *head, int index){
NODE *newnode = createNode(data);
NODE *temp = head;
int count=0;
while(count != index-1){
temp = temp->next;
count++;
}
//temp reaches the index before the target index
newnode->next = temp->next;
temp->next = newnode;
return head;
}
Code Explanation
Code Implementation
#include<iostream>
using namespace std;
class Node
{
public:
int data;
Node *next;
};
void insertLast(Node **head, int data)
{
Node *newnode = new Node();
newnode->data = data;
newnode->next = NULL;
if (*head == NULL) {
*head = newnode;
} else {
Node *temp = *head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newnode;
}
}
void printList(Node *head)
{
Node *tnode = head;
while (tnode != NULL) {
cout << tnode->data << " ";
tnode = tnode->next;
}
}
int main()
{
Node *head = NULL;
insertLast(&head, 1);
insertLast(&head, 2);
insertLast(&head, 3);
insertLast(&head, 4);
insertLast(&head, 5);
printList(head);
return 0;
}
output
1 2 3 4 5
Time Complexity
The time complexity at the end of the linked list is O(n) because we have to traverse the entire linked list to reach the end here n is the number of nodes in the linked list.
Space Complexity
The space complexity is O(1) because we are not using any extra space here.
Insertion at Specific Index
Approach
pseudocode
NODE *InsertatIndex(int data, NODE *head, int index){
NODE *newnode = createNode(data);
NODE *temp = head;
int count=0;
while(count != index-1){
temp = temp->next;
count++;
}
//temp reaches the index before the target index
newnode->next = temp->next;
temp->next = newnode;
return head;
}
Code Explanation
Code Implementation
#include<iostream>
using namespace std;
class Node
{
public:
int data;
Node *next;
Node(int data)
{
this->data = data;
this->next = NULL;
}
};
class LLLast
{
public:
Node *head;
LLLast()
{
head = NULL;
}
void insert(int data)
{
Node *newNode = new Node(data);
if (head == NULL)
{
head = newNode;
}
else
{
Node *last = head;
while (last->next != NULL)
{
last = last->next;
}
last->next = newNode;
}
}
void insertAt(int data, int index)
{
Node *newNode = new Node(data);
Node *temp = head;
int count = 0;
while (count != index - 1)
{
temp = temp->next;
count++;
}
newNode->next = temp->next;
temp->next = newNode;
}
void print()
{
Node *current = head;
while (current != NULL)
{
cout << current->data << " ";
current = current->next;
}
}
};
int main()
{
LLLast list;
list.insert(1);
list.insert(2);
list.insert(3);
list.insertAt(6, 2);
list.print();
return 0;
}
output
1 2 6 3
Time Complexity
The time complexity of the insert a node at a given position in a linked list is O(n) because we have to traverse the linked list to reach the position where we want to insert the node.
Space Complexity
The space complexity of the insert a node at a given position in a linked list is O(1) because we are not using any extra space.
Insertion using Functions
first , end & given position
#include<iostream>
#include<list>
using namespace std;
int main()
{
// Declaring list
list<string> list;
list.push_back("CodeXam");
list.push_back("is");
list.push_back("Best");
// Displaying the list
cout << "List: ";
for (auto it = list.begin(); it != list.end(); it++)
cout << *it << " ";
cout << endl;
// Adding an element to the first position
list.push_front("Hello");
//Displaying the list after adding the element
cout << "List after adding the element at the first position: ";
for (auto it = list.begin(); it != list.end(); it++)
cout << *it << " ";
cout << endl;
// Adding an element to the last position
list.push_back("Java");
//Displaying the list after adding the element
cout << "List after adding the element at the last position: ";
for (auto it = list.begin(); it != list.end(); it++)
cout << *it << " ";
cout << endl;
// Adding an element to the specified position
auto it = list.begin();
advance(it, 2);
list.insert(it, "Programming");
//Displaying the list after adding the element
cout << "List after adding the element at the specified position: ";
for (auto it = list.begin(); it != list.end(); it++)
cout << *it << " ";
cout << endl;
return 0;
}
output
Linked list: [CodeXam, is, Best]
Linked list after adding the element at the first position: [Hello, CodeXam, is, Best]
Linked list after adding the element at the last position: [Hello, CodeXam, is, Best, Java]
Linked list after adding the element at the specified position: [Hello, CodeXam, Programming, is, Best, Java]
Deletion
Deletion from the front end
Approach
- Check if the head is NULL, if it is then return.
- Make the head point to the next node of the head.
Note that we are not deleting the node, we are just making the head point to the next node of the head. In java & python garbage collector will delete the node automatically. In C we have to use free() function to delete the node. In C++ we have to use delete keyword to delete the node.
pseudocode
if(head == NULL)
return;
head = head->next;
Code Explanation
Code Implementation
#include<iostream>
using namespace std;
class Node
{
public:
int data;
Node *next;
Node(int d)
{
data=d;
next=NULL;
}
};
void removeFirstNode(Node *&head)
{
if(head==NULL)
{
return;
}
Node *temp=head;
head=head->next;
delete temp;
}
void traverse(Node *head)
{
while(head!=NULL)
{
cout<<head->data<<" ";
head=head->next;
}
}
int main()
{
Node *head=new Node(1);
head->next=new Node(2);
head->next->next=new Node(3);
head->next->next->next=new Node(4);
head->next->next->next->next=new Node(5);
head->next->next->next->next->next=new Node(6);
removeFirstNode(head);
traverse(head);
return 0;
}
output
2
3
4
5
6
Time Complexity
Deletion of first node takes constant time O(1) because we are not traversing the list. We are just changing the head pointer to the next node.
Space Complexity
Space complexity is O(1) because we are not using any extra space.
Deletion from the back end
Approach
- Traverse the list till the last node.
- Change the next pointer of the second last node to NULL.
- Delete the last node.
pseudocode
removeLast() {
if (head == null) {
return;
}
if (head.next == null) {
head = null;
return;
}
Node temp = head;
while (temp.next.next != null) {
temp = temp.next;
}
temp.next = null;
}
Code Explanation
Code Implementation
#include<iostream>
using namespace std;
class Node
{
public:
int data;
Node *next;
Node(int d)
{
data=d;
next=NULL;
}
};
void removeLastNode(Node *head)
{
Node *temp=head;
while(temp->next->next!=NULL)
{
temp=temp->next;
}
temp->next=NULL;
}
void push(Node **head,int new_data)
{
Node *new_node=new Node(new_data);
new_node->next=*head;
*head=new_node;
}
void printList(Node *head)
{
Node *tnode=head;
while(tnode!=NULL)
{
cout<<tnode->data<<" ";
tnode=tnode->next;
}
cout<<endl;
}
int main()
{
Node *head=NULL;
push(&head,1);
push(&head,2);
push(&head,3);
push(&head,4);
push(&head,5);
cout<<"Created Linked list is: ";
printList(head);
removeLastNode(head);
cout<<"Linked List after deletion of last node: ";
printList(head);
return 0;
}
output
Created Linked list is: 5 4 3 2 1
Linked List after deletion of last node: 5 4 3 2
Time Complexity
The time complexity of deletion last node is O(n) where n is the number of nodes in the linked list because we need to traverse the list to find the second last node.
Space Complexity
The space complexity of deletion last node is O(1) because we are not using any extra space.
Deletion at Specific Index
Approach
The main idea of the algo is to traverse the list till the index and delete the node at that index. We need to keep track of the previous node of the node to be deleted. We can use two pointers to keep track of the previous and current node. We can also use a single pointer to keep track of the current node and use the previous node of the current node to delete the node at the given index.
- Create a temp node and initialize it with head node.
- Create a prev node and initialize it with null.
- If index is 0 and temp is not null, then make head as temp.next and return.
- Create a counter and initialize it with 0.
- Traverse the list till temp is not null.
- If counter is equal to index, then make prev.next as temp.next and break the loop.
- Else, make prev as temp and temp as temp.next and increment counter by 1.
- If temp is null, then print "Index not found".
pseudocode
removeAtSpecificIndex(index)
temp = head
prev = null
if index == 0 and temp != null
head = temp.next
return
counter = 0
while temp != null
if counter == index
prev.next = temp.next
break
else
prev = temp
temp = temp.next
counter++
if temp == null
print "Index not found"
Code Explanation
Code Implementation
#include<iostream>
using namespace std;
class Node
{
public:
int data;
Node *next;
Node(int d)
{
data=d;
next=NULL;
}
};
void removeAtSpecificIndex(Node *head,int index)
{
Node *temp=head;
Node *prev=NULL;
int count=0;
while(temp!=NULL)
{
if(count==index)
{
prev->next=temp->next;
delete temp;
return;
}
prev=temp;
temp=temp->next;
count++;
}
}
void push(Node **head,int new_data)
{
Node *new_node=new Node(new_data);
new_node->next=*head;
*head=new_node;
}
void printList(Node *head)
{
Node *tnode=head;
while(tnode!=NULL)
{
cout<<tnode->data<<" ";
tnode=tnode->next;
}
cout<<endl;
}
int main()
{
Node *head=NULL;
push(&head,1);
push(&head,2);
push(&head,3);
cout<<"Created Linked list is: ";
printList(head);
removeAtSpecificIndex(head,1);
cout<<"Linked List after Deletion at index 1: ";
printList(head);
return 0;
}
output
Created Linked list is:
3 2 1
Linked List after Deletion at index 1:
2 1
Time Complexity
Deletion at a given index is an operation that takes O(n) time. This is because in the worst case, we might have to travel all the way from the head of the list to the tail to find the node at the given index.
Space Complexity
The space complexity of the above algorithm is O(1) as we do not use any extra space.
Deletion using Functions
first , end & given position
#include<iostream>
#include<list>
using namespace std;
int main()
{
// Add elements to the linked list
list<string> list;
list.push_back("CodeXam");
list.push_back("is");
list.push_back("Best");
list.push_back("for");
list.push_back("Developers");
// Displaying the linked list
cout << "Linked list: ";
for (auto it = list.begin(); it != list.end(); it++)
cout << *it << " ";
// Removing an element at first position
list.pop_front();
// Displaying the linked list
cout << " "
<< "Linked list after removing first element: ";
for (auto it = list.begin(); it != list.end(); it++)
cout << *it << " ";
// Removing an element at last position
list.pop_back();
// Displaying the linked list
cout << " "
<< "Linked list after removing last element: ";
for (auto it = list.begin(); it != list.end(); it++)
cout << *it << " ";
// Removing an element at specified position
list.remove("Best");
// Displaying the linked list
cout << " "
<< "Linked list after removing 3rd element: ";
for (auto it = list.begin(); it != list.end(); it++)
cout << *it << " ";
return 0;
}
output
Linked list: [CodeXam, is, Best, for, Developers]
Linked list after removing first element: [is, Best, for, Developers]
Linked list after removing last element: [is, Best, for]
Linked list after removing 3rd element: [is, Best]