Sequence Containers std::list in C++

Anatomy of std::list

Lists supports non-contiguous memory allocation. Unlike vectors, which offer faster traversal, lists have slower traversal times. However, they excel in insertion and deletion operations, which are performed in constant time.

std::list is a doubly-linked list, meaning each element in the list points to both its previous and next elements. This architecture allows for constant-time insertions and deletions at any position within the list, distinguishing it from containers like std::vector and std::deque.

  • A list in C++ STL is a doubly-linked list, which allows elements to be efficiently inserted or deleted from both ends as well as from the middle. Unlike arrays or vectors, lists do not provide fast random access but are highly efficient in insertion and deletion operations

Creating and Initializing a std::list

#include <list>
#include <iostream>

int main() {
    // Initializing a list with values
    std::list<int> myList = {1, 2, 3, 4, 5};

    // Iterating through elements
    for (int num : myList) {
        std::cout << num << " ";
    }

    return 0;
}

Accessing Elements

Access elements in a std::list is slightly different from random-access containers like std::vector. Since it is a doubly-linked list, accessing elements involves traversing the list sequentially.

#include <list>
#include <iostream>

int main() {
    std::list<int> myList = {1, 2, 3, 4, 5};

    // Accessing elements using an iterator
    auto it = std::find(myList.begin(), myList.end(), 3);
    if (it != myList.end()) {
        std::cout << "Element found: " << *it << std::endl;
    }

    return 0;
}

Insertions and Deletions

One of the key strengths of std::list is its ability to efficiently insert and delete elements anywhere in the container.

#include <list>
#include <iostream>

int main() {
    std::list<int> myList = {1, 2, 3, 4, 5};

    // Inserting elements
    auto it = std::find(myList.begin(), myList.end(), 3);
    if (it != myList.end()) {
        myList.insert(it, 6);  // Inserts 6 before the element with value 3
    }

    // Deleting elements
    myList.remove(2);  // Removes all elements with value 2

    // Iterating through elements
    for (int num : myList) {
        std::cout << num << " ";
    }

    return 0;
}

1 push_front / emplace_front

The push_front function inserts a new element at the beginning of the list, while emplace_front constructs an element in place at the beginning. These operations are efficient since they only involve adjusting a few pointers.

#include <bits/stdc++.h>
        using namespace std;
        
        int main() {
            list<int> lst;
            lst.push_front(20);
            lst.emplace_front(10);  // Constructs 10 at the beginning
            for (int i : lst) {
                cout << i << " ";
            }
            return 0;
        }
10 20

2 front

The front function returns a reference to the first element in the list. This is useful for accessing or modifying the element at the front without affecting the rest of the list.

#include <bits/stdc++.h>
        using namespace std;
        
        int main() {
            list<int> lst = {10, 20, 30};
            cout << "Front element: " << lst.front();
            return 0;
        }
Front element: 10

Advantages of std::list

  1. Constant-Time Insertions and Deletions: Regardless of the position within the list, insertion and deletions take constant time due to the doubly-linked nature of the list.
  2. No Reallocation: Unlike dynamic arrays (std::vector), std::list does not need to reallocate when elements are inserted or removed. This makes it suitable for scenarios with frequent modifications.
  3. Efficient for Small Inserts and Deletes: For relatively small collections or scenarios with frequent insertions and deletions, std::list can outperform other containers.

Drawbacks of std::list

  1. Slower Element Access: Accessing elements in a std::list is slower compared to random-access containers like std::vector since it requires sequential traversal.
  2. Higher Memory Overhead: The doubly-linked structure requires additional memory per element compared to singly-linked lists or arrays.