Mastering STL

Sohil_TamboliSohil_Tamboli
21 min read

Introduction of STL

What is STL in C++? ๐Ÿค”

The Standard Template Library (STL) is like the IKEA of C++ programming ๐Ÿ› ๏ธโ€”it gives you all the pieces you need to build complex programs without starting from scratch. Think of it as a magic toolbox where you can pull out ready-made parts for data structures (like vectors and maps) and algorithms (like sorting and searching). You donโ€™t need to reinvent the wheel every timeโ€”just pick the right tool, plug it in, and youโ€™re good to go. For example, if youโ€™re trying to organize your playlist ๐ŸŽต, std::sort() will shuffle things into perfect order without you lifting a finger!

STL also works like an all-you-can-eat buffet ๐Ÿฝ๏ธโ€”it doesnโ€™t matter if youโ€™re working with integers, strings, or custom objects, thereโ€™s something for everyone. Want to store your collection of Pokรฉmon cards? Use a std::set to make sure there are no duplicates. Need to search for a name in a long list of people? std::binary_search() is like Ctrl+F but on steroids ๐Ÿ’ช. STL combines efficiency, flexibility, and simplicity, making coding feel less like work and more like a cheat code for solving problems.

Why Use STL in C++? ๐Ÿš€

The Standard Template Library (STL) is like your personal coding superhero ๐Ÿฆธโ€โ™‚๏ธโ€”always ready to save the day! Instead of sweating over writing tedious sorting or searching functions, just call in STLโ€™s pre-built tools like std::sort() or std::binary_search() and watch the magic happen. Itโ€™s like ordering fast food ๐Ÿ” instead of cooking a 5-course mealโ€”it saves time and works flawlessly every time! Plus, STL is battle-tested, so you can trust it to handle your data structures like stacks, queues, or maps without breaking a sweat.

What makes STL even cooler is its ability to work with any data type, thanks to templates. Need to store your gaming scores? Use a std::vector. Want to map student names to their marks? Try std::map. Navigating your data with STL iterators is like flipping through a Netflix menu ๐ŸŽฅโ€”easy and efficient! And if youโ€™re picky, STL lets you customize how things work, like sorting tasks by deadlines using custom comparators. In short, STL doesnโ€™t just make coding easierโ€”itโ€™s the ultimate life hack for every C++ programmer. Who wouldnโ€™t want a Swiss Army knife for their code? ๐Ÿ› ๏ธ

Array โ€“The Organized Squad of Elements ๐Ÿ—‚๏ธ

Think of std::array like a pizza box with fixed slices ๐Ÿ•โ€”the size is constant, and each slice (element) is neatly organized!

  1. You can declare it, initialize it, and access its contents with ease, but no sneaking in extra slices. Here's how:
#include <iostream>
#include <array>

int main() {
    // Declaration and Initialization ๐Ÿ•
    std::array<int, 5> pizzaSlices = {10, 20, 30, 40, 50};

    // Accessing Elements ๐Ÿด
    std::cout << "First slice has " << pizzaSlices[0] << " calories.\n";  // Output: 10
    std::cout << "Last slice has " << pizzaSlices[4] << " calories.\n";   // Output: 50

    // Using `.at()` for safe access
    std::cout << "Middle slice has " << pizzaSlices.at(2) << " calories.\n";  // Output: 30

    return 0;
}
  1. predictable and structured. Let's see how it works with some cool (and relatable) examples:
#include <iostream>
#include <array>
#include <algorithm>  // for sort
#include <numeric>    // for accumulate
#include <iterator>   // for std::find

int main() {
    // 1. Create an array of exam scores ๐ŸŽ“
    std::array<int, 5> scores = {85, 90, 78, 92, 88};

    // Empty - Is the pizza box empty? ๐Ÿ•โŒ
    std::cout << "Empty? " << (scores.empty() ? "Yes" : "No") << "\n"; // Output: No

    // Size - How many slices in the box? ๐Ÿ•๐Ÿ“ฆ
    std::cout << "Size: " << scores.size() << "\n"; // Output: 5

    // Fill - Everyone gets the same score (tough teacher!) ๐Ÿ‘ฉโ€๐Ÿซ๐Ÿ˜…
    scores.fill(100);
    std::cout << "After fill: ";
    for (int score : scores) std::cout << score << " "; // Output: 100 100 100 100 100
    std::cout << "\n";

    // Sort - Sort exam scores in ascending order ๐Ÿ“Š
    scores = {85, 90, 78, 92, 88};
    std::sort(scores.begin(), scores.end());
    std::cout << "Sorted: ";
    for (int score : scores) std::cout << score << " "; // Output: 78 85 88 90 92
    std::cout << "\n";

    // Find - Where is the 88 hiding? ๐Ÿ”
    auto it = std::find(scores.begin(), scores.end(), 88);
    std::cout << "88 found at index: " << (it - scores.begin()) << "\n"; // Output: 2

    // Accumulate - What's the total score? ๐Ÿงฎ
    int total = std::accumulate(scores.begin(), scores.end(), 0);
    std::cout << "Total score: " << total << "\n"; // Output: 433

    return 0;
}

Vector โ€“ The Magical Expanding Wallet ๐Ÿ’ณ

Imagine std::vector as your stretchy backpack ๐Ÿงณโ€”it grows as you add more items! Unlike fixed-size containers, itโ€™s perfect for carrying dynamic loads, but be careful not to overpack (you still need logic)! Letโ€™s look at how it works:

#include <iostream>
#include <vector>

int main() {
    // Declaration and Initialization ๐Ÿ“ฆ
    std::vector<int> nums = {100, 200, 300, 400, 500};

    // Accessing Elements ๐ŸŽฏ
    std::cout << "First item: " << nums[0] << "\n";  // Output: 100
    std::cout << "Last item: " << nums.back() << "\n"; // Output: 500
    std::cout << "Third item: " << nums.at(2) << "\n"; // Output: 300

    // Adding a new item ๐Ÿ”ผ
    nums.push_back(600);
    std::cout << "New last item: " << nums.back() << "\n"; // Output: 600

    return 0;
}

"A vector is like your wallet ๐Ÿชชโ€”you always manage to fit in one more card, but make sure not to lose track of whatโ€™s already inside!" ๐Ÿ˜„

Imagine a vector as your wallet that magically grows to hold all your cash ๐Ÿ’ต. You can easily add money, check the amount, update it, and even spend it (remove). Plus, it tells you how much space it has left for more! Here's a crash course:

#include <iostream>
#include <vector>

int main() {
    // Create an empty vector (your wallet ๐Ÿ’ณ)
    std::vector<int> wallet;

    // Add elements (earn some cash ๐Ÿ’ต)
    wallet.push_back(100);
    wallet.push_back(200);
    wallet.push_back(500);

    // Access elements (count your money ๐Ÿ’ฐ)
    std::cout << "First note: " << wallet.front() << "\n";  // Output: 100
    std::cout << "Last note: " << wallet.back() << "\n";    // Output: 500

    // Change elements (exchange 500 for 50s ๐Ÿ’ฑ)
    wallet[2] = 50;

    // Remove elements (spend your money ๐Ÿ’ธ)
    wallet.pop_back(); // Removes the last element (50)

    // Check size and capacity ๐Ÿ“
    std::cout << "Wallet size: " << wallet.size() << "\n";        // Output: 2
    std::cout << "Wallet capacity: " << wallet.capacity() << "\n"; // Capacity might be >= 3

    // Iterators to see what's inside ๐Ÿ”
    std::cout << "Wallet contents: ";
    for (auto it = wallet.begin(); it != wallet.end(); ++it)
        std::cout << *it << " ";  // Output: 100 200
    std::cout << "\n";

    // Check if wallet is empty ๐Ÿ™ƒ
    std::cout << "Wallet empty? " << wallet.empty() << "\n"; // Output: 0 (false)

    // Clear all money (oh no! ๐Ÿ˜ญ)
    wallet.clear();
    std::cout << "Wallet size after clear: " << wallet.size() << "\n";  // Output: 0
    std::cout << "Wallet empty? " << wallet.empty() << "\n";            // Output: 1 (true)

    return 0;
}

List - The Train of Numbers ๐Ÿš‚

Think of std::list as a train where each coach (element) is connected to the next, but you can freely add or remove coaches anywhere! ๐Ÿš‹ Itโ€™s great for when you need dynamic flexibility in organizing your data. Here's a quick tour:

#include <iostream>
#include <list>

int main() {
    // Declaration and Initialization ๐Ÿš‹
    std::list<int> train = {10, 20, 30, 40, 50};  // A train with 5 coaches

    // Accessing elements (Front and Back ๐Ÿš‚๐Ÿšƒ)
    std::cout << "First coach: " << train.front() << "\n";  // Output: 10
    std::cout << "Last coach: " << train.back() << "\n";    // Output: 50

    // Adding coaches (Add elements ๐Ÿ› ๏ธ)
    train.push_front(5);  // Add at the front
    train.push_back(60);  // Add at the back

    // Removing coaches (Remove elements ๐Ÿ› ๏ธ)
    train.pop_front();  // Remove the first coach
    train.pop_back();   // Remove the last coach

    // Displaying the train coaches ๐Ÿš‚
    std::cout << "Train coaches: ";
    for (int coach : train)
        std::cout << coach << " ";  // Output: 10 20 30 40 50
    std::cout << "\n";

    return 0;
}
FunctionDescription
reverse()Reverses the order of the elements
sort()Sorts the list elements in a particular order.
unique()Removes consecutive duplicate elements.
size()Returns the number of elements in the list.
empty()Checks whether the list is empty.
clear()Clears all the values from the list
merge()Merges two sorted lists.

Queue - The Line at the Ticket Counter ๐ŸŽŸ๏ธ

A std::queue is like a ticket queue at a movie theater ๐ŸŽฅโ€”first person in, first person out (FIFO). People (elements) line up at the back and leave from the front, no cutting allowed! Here's how it works:

#include <iostream>
#include <queue>

int main() {
    // Declaration and Initialization ๐ŸŽŸ๏ธ
    std::queue<int> ticketQueue;

    // Adding people to the queue (enqueue ๐Ÿ› ๏ธ)
    ticketQueue.push(101);  // Person with ticket 101
    ticketQueue.push(102);  // Person with ticket 102
    ticketQueue.push(103);  // Person with ticket 103

    // Accessing front and back of the queue (Front and Back ๐Ÿšช)
    std::cout << "First in line: " << ticketQueue.front() << "\n";  // Output: 101
    std::cout << "Last in line: " << ticketQueue.back() << "\n";    // Output: 103

    // Removing from the queue (dequeue ๐Ÿšถโ€โ™‚๏ธ)
    ticketQueue.pop();  // Person with ticket 101 leaves the queue

    // Check the new first in line
    std::cout << "New first in line: " << ticketQueue.front() << "\n";  // Output: 102

    // Checking the size of the queue
    std::cout << "People still in queue: " << ticketQueue.size() << "\n";  // Output: 2

    return 0;
}

With std::queue, keep the line moving smoothlyโ€”first come, first served! No sneaky line-jumpers allowed! ๐Ÿ˜Ž๐ŸŽฅ.

FunctionDescription
push()Inserts an element at the back of the queue.
pop()Removes an element from the front of the queue.
front()Returns the first element of the queue.
back()Returns the last element of the queue.
size()Returns the number of elements in the queue.
empty()Returns true if the queue is empty.

Stack โ€“ The Pancake Pile ๐Ÿฅž

A std::stack is like a stack of pancakesโ€”last pancake added is the first one you eat (LIFO: Last In, First Out). You keep stacking them up and munching from the top. Here's how to whip up your own stack:

#include <iostream>
#include <stack>

int main() {
    // Declaration and Initialization ๐Ÿฅž
    std::stack<int> pancakeStack;

    // Adding pancakes to the stack (push ๐Ÿณ)
    pancakeStack.push(1);  // First pancake (bottom-most)
    pancakeStack.push(2);  // Second pancake
    pancakeStack.push(3);  // Third pancake (top-most)

    // Accessing the top pancake ๐Ÿฝ๏ธ
    std::cout << "Top pancake: " << pancakeStack.top() << "\n";  // Output: 3

    // Eating the top pancake (pop ๐Ÿฅข)
    pancakeStack.pop();  // Removes pancake 3

    // Accessing the new top pancake
    std::cout << "New top pancake: " << pancakeStack.top() << "\n";  // Output: 2

    // Checking the number of pancakes left
    std::cout << "Pancakes left: " << pancakeStack.size() << "\n";  // Output: 2

    // Checking if the stack is empty ๐Ÿฝ๏ธ
    std::cout << "Is the pancake stack empty? " << (pancakeStack.empty() ? "Yes" : "No") << "\n";  // Output: No

    return 0;
}

With std::stack, keep stacking and snackingโ€”just donโ€™t let them topple over! ๐Ÿ˜‹โœจ

OperationDescription
push()adds an element into the stack
pop()removes an element from the stack
top()returns the element at the top of the stack
size()returns the number of elements in the stack
empty()returns true if the stack is empty

Map Mayhem: Choosing the Right Partner for Your Data Journey ๐Ÿš€

Map: The Strict and Orderly Librarian ๐Ÿ“š

A map is like a librarian who insists on keeping books in alphabetical order. Itโ€™s perfect for tasks where order matters, but donโ€™t expect her to rush!

#include <iostream>
#include <map>
using namespace std;

int main() {
    map<string, int> studentMarks = {{"Alice", 85}, {"Bob", 92}, {"Charlie", 78}};

    // Accessing
    cout << "Alice's marks: " << studentMarks["Alice"] << endl;

    return 0;
}

Multimap: The Party Host with Duplicate Keys ๐ŸŽ‰

A multimap is like a party host who allows multiple guests with the same name. Itโ€™s great for handling duplicates but can get messy!

#include <iostream>
#include <map>
using namespace std;

int main() {
    multimap<string, int> movieRatings = {{"Inception", 9}, {"Interstellar", 10}, {"Inception", 8}};

    // Accessing
    for (auto &pair : movieRatings) {
        cout << pair.first << " rated: " << pair.second << endl;
    }

    return 0;
}
//output :-
//Inception rated: 9  
//Inception rated: 8  
//Interstellar rated: 10

Unordered_map: The Quick and Chaotic Friend โšก

An unordered_map is like your friend who throws things in a box. No order, but super quick to find stuff (most of the time)!

#include <iostream>
#include <unordered_map>
using namespace std;

int main() {
    unordered_map<string, string> countryCodes = {{"India", "IN"}, {"United States", "US"}, {"Germany", "DE"}};

    // Accessing
    cout << "Country code of India: " << countryCodes["India"] << endl;

    return 0;
}
//Output:
//Country code of India: IN

When to Use What?

  • map: When order matters ๐Ÿง‘โ€โš–๏ธ. (Think: Keeping sorted records.) O(log n)

  • multimap: When you expect duplicates ๐Ÿคน. (Think: Movies with multiple reviews.) O(log n)

  • unordered_map: When speed is king ๐ŸŽ๏ธ. (Think: Quickly finding country codes.)

  • Average: O(1), Worst: O(n)

MethodDescription
insert()adds an element (key-value pair) to the map
erase()removes an element or range of elements from the map
clear()removes all the elements from the map
find()searches the map for the given key
size()returns the number of elements in the map
empty()returns true if the map is empty
count()returns total number of occurrences of the specified key #multimap
at()returns the element at the specified key #unordered_map

Pro Tip: If you care about efficiency, unordered_map can be your BFF unless you need order or duplicates! ๐Ÿ˜Š

Set It Right: Your Unique Squad of STL Containers ๐ŸŽฏ

Set: The No-Nonsense Gatekeeper ๐Ÿšช

A set is like a bouncer at a partyโ€”no duplicates allowed, and everyone is sorted before they enter!

#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> numbers = {5, 2, 8, 2, 1};

    // Accessing
    for (int num : numbers) {
        cout << num << " ";
    }

    return 0;
}
Output:
1 2 5 8
(Duplicates removed, sorted order)

Multiset: The Chill Collector ๐ŸŒธ

A multiset is like your grandmaโ€™s cookie jarโ€”duplicates are welcome, and everything is neatly arranged.

#include <iostream>
#include <set>
using namespace std;

int main() {
    multiset<int> numbers = {5, 2, 8, 2, 1};

    // Accessing
    for (int num : numbers) {
        cout << num << " ";
    }

    return 0;
}
Output:
1 2 2 5 8
(Duplicates retained, sorted order)

Unordered_set: The Fast and Free-Spirited ๐ŸŽข

An unordered_set is like a free spiritโ€”no order, but everyoneโ€™s unique. Perfect for speed!

#include <iostream>
#include <unordered_set>
using namespace std;

int main() {
    unordered_set<int> numbers = {5, 2, 8, 2, 1};

    // Accessing
    for (int num : numbers) {
        cout << num << " ";
    }

    return 0;
}
Output (example):
8 1 2 5
(Order is unpredictable, no duplicates)

Unordered_multiset: The Unpredictable Hoarder ๐ŸŽ’

An unordered_multiset is like that friend who keeps everythingโ€”duplicates includedโ€”but doesnโ€™t care about tidiness.

#include <iostream>
#include <unordered_set>
using namespace std;

int main() {
    unordered_multiset<int> numbers = {5, 2, 8, 2, 1};

    // Accessing
    for (int num : numbers) {
        cout << num << " ";
    }

    return 0;
}
Output (example):
5 2 2 8 1
(Duplicates retained, no specific order)

When to Use What?

  • set: When order and uniqueness are key ๐Ÿง‘โ€โš–๏ธ. (Think: Unique usernames.)

  • multiset: When duplicates matter, but order is nice ๐ŸŒŸ. (Think: Word frequency in a document.)

  • unordered_set: When speed is all you care about โšก. (Think: Quickly finding unique items.)

  • unordered_multiset: When you need duplicates, fast ๐Ÿƒ. (Think: Counting items without worrying about order.)

OperationDescription
insert()Insert elements into a set. set multiset
erase()Delete elements from a set.set multiset
clear()Remove all the elements from a set.set multiset
empty()Check if the set is empty.set multiset
size()Returns the size of the set.set multiset
found()Find the occurrence of a value. unordered_multiset
count()Count the frequency of a value. unordered_set
find()returns the iterator to the element with the specified value unordered_set

Pro Tip: unordered_set and unordered_multiset are fast but trade memory for speed, while set and multiset are memory-friendly but slower for large data! ๐Ÿง 

Bitset: The Superpower of Compact Data Handling ๐Ÿฆธโ€โ™‚๏ธ

Bitset: The Compact Genius ๐ŸŽฏ

A bitset is like a high-tech switchboard operatorโ€”it handles multiple on/off switches (bits) efficiently while saving space. Perfect for memory-conscious situations like flags in games! ๐ŸŽฎ

#include <iostream>
#include <bitset>
using namespace std;

int main() {
    // Declaration & Initialization
    bitset<8> lights("10101010"); // 8 lights, alternating ON (1) and OFF (0)

    // Accessing
    cout << "Initial state of lights: " << lights << endl;
    cout << "Is light 3 ON? " << lights[2] << endl; // Access 3rd bit (index starts at 0)

    // Modifying
    lights.flip(2); // Toggle the 3rd light
    cout << "After flipping light 3: " << lights << endl;

    return 0;
}
output
Initial state of lights: 10101010  
Is light 3 ON? 1  
After flipping light 3: 10101110

Pro Tip: Use bitset for tasks like permissions, binary operations, or optimizing boolean flags!

  1. Basic Operations

FunctionPurposeExample
size()Returns the number of bits in the bitset.cout << b.size();
count()Counts the number of 1s (set bits).cout << b.count();
any()Checks if any bit is set to 1.cout << b.any();
none()Checks if all bits are 0.cout << b.none();
all()Checks if all bits are 1.cout << b.all();
  1. Access and Modification

FunctionPurposeExample
b[i]Accesses the bit at position i.cout << b[2];
set(pos)Sets the bit at position pos to 1.b.set(3);
reset(pos)Resets (sets to 0) the bit at position pos.b.reset(3);
flip(pos)Toggles (inverts) the bit at position pos.b.flip(3);
set()Sets all bits to 1.b.set();
reset()Resets all bits to 0.b.reset();
flip()Toggles all bits.b.flip();
  1. Conversion

FunctionPurposeExample
to_string()Converts bitset to a string.cout << b.to_string();
to_ulong()Converts bitset to an unsigned long.cout << b.to_ulong();
to_ullong()Converts bitset to an unsigned long long.cout << b.to_ullong();

Bitwise Operators

OperatorPurposeExample
~Bitwise NOT (inverts all bits).~b
&Bitwise AND with another bitset.b1 & b2
` Bitwise OR with another bitset.
^Bitwise XOR with another bitset.b1 ^ b2
ยซLeft shift. Moves bits left by n positions.b << 2
ยปRight shift. Moves bits right by n positions.b >> 2

STL Algorithms: The Magic Toolbox of C++ ๐Ÿงฐ

STL algorithms are like the Swiss army knives of C++. They let you perform tasks like sorting, searching, and modifying data with ease, making your life much simpler when working with containers. ๐ŸŒŸ All these algorithms are available in the <algorithm> and <numeric> header files.

We can classify these algorithms into Manipulative and Non-Manipulative based on whether they modify the container or not.

Manipulative Algorithms: The Movers & Shakers ๐Ÿ”„

Manipulative algorithms are the life of the STL party! Theyโ€™re like the dance moves that shake things up in your containers, rearranging or modifying their elements to fit your needs. Here are some key moves:

1. copy()

Copying, like sharing cookies ๐Ÿช!

Copies elements from one range to another.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> original = {1, 2, 3, 4};
    std::vector<int> copied(4);
    std::copy(original.begin(), original.end(), copied.begin());

    // Output: 1 2 3 4
    for (int num : copied) std::cout << num << " ";
    return 0;
}

2. fill()

When you want all your cups full ๐Ÿต!

Assigns a specified value to all elements in a range.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v(4);
    std::fill(v.begin(), v.end(), 7);

    // Output: 7 7 7 7
    for (int num : v) std::cout << num << " ";
    return 0;
}

3. transform()

Transforming like a magic spell! ๐Ÿ”ฎ

Applies a function to each element and stores the result in another range.

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>

int main() {
    std::vector<int> v = {1, 4, 9, 16};
    std::vector<int> transformed(v.size());
    std::transform(v.begin(), v.end(), transformed.begin(), [](int x) { return std::sqrt(x); });

    // Output: 1 2 3 4
    for (int num : transformed) std::cout << num << " ";
    return 0;
}

4. replace()

Say goodbye to the old, hello to the new ๐Ÿ‘‹!

Replaces all occurrences of a specific value in a range with a new value.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 2, 3};
    std::replace(v.begin(), v.end(), 2, 5);

    // Output: 1 5 5 3
    for (int num : v) std::cout << num << " ";
    return 0;
}

5. swap()

Switching places, like two best friends! ๐Ÿ‘ฏ

Exchanges the values of two variables.

#include <iostream>
#include <algorithm>

int main() {
    int a = 5, b = 10;
    std::swap(a, b);

    // Output: a = 10, b = 5
    std::cout << "a = " << a << ", b = " << b << std::endl;
    return 0;
}

6. reverse()

The perfect flip! ๐Ÿ”„

Reverses the order of elements in a range.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4};
    std::reverse(v.begin(), v.end());

    // Output: 4 3 2 1
    for (int num : v) std::cout << num << " ";
    return 0;
}

7. rotate()

Spin those elements around! ๐ŸŽก

Rotates the elements in a range such that a specific element becomes the first.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4};
    std::rotate(v.begin(), v.begin() + 2, v.end());

    // Output: 3 4 1 2
    for (int num : v) std::cout << num << " ";
    return 0;
}

8. remove()

Out with the old! ๐Ÿšฎ

Removes all elements with a specified value from a range but does not reduce the container size.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 2, 4};
    auto it = std::remove(v.begin(), v.end(), 2);

    // Output: 1 3 4 (container size remains the same, but 2s are removed)
    for (int num : v) std::cout << num << " ";
    return 0;
}

9. unique()

When youโ€™ve had enough of duplicates! ๐Ÿ‘ฏโ€โ™‚๏ธ

Removes consecutive duplicate elements from a range.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {1, 1, 2, 3, 3, 4};
    auto it = std::unique(v.begin(), v.end());

    // Output: 1 2 3 4 (remaining unique elements)
    for (int num : v) std::cout << num << " ";
    return 0;
}

These algorithms are your secret weapon to make containers in STL behave just the way you want whether you're filling them with love (or values) or transforming them into something new. Keep dancing! ๐Ÿ’ƒ

STL Non-Manipulative Algorithms: Keeping Things Chill ๐Ÿ˜Ž

Non-manipulative algorithms are like the chill friends at a partyโ€”just observing and offering advice without getting involved in the drama. They donโ€™t change anything, they just analyze and help you find things. Here's how they work:

1. max_element()

Finding the rockstar of the group! ๐ŸŒŸ

Finds the maximum element in a given range.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {3, 5, 7, 2, 8};
    auto maxElem = *std::max_element(v.begin(), v.end());

    // Output: 8
    std::cout << "Max Element: " << maxElem << std::endl;
    return 0;
}

2. min_element()

The underdog who deserves the spotlight ๐Ÿ†

Finds the minimum element in a given range.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {3, 5, 7, 2, 8};
    auto minElem = *std::min_element(v.begin(), v.end());

    // Output: 2
    std::cout << "Min Element: " << minElem << std::endl;
    return 0;
}

3. accumulate()

Bringing everyone together for the greater good ๐Ÿ’ฐ

Finds the sum of elements in a given range.

#include <iostream>
#include <numeric>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4};
    int sum = std::accumulate(v.begin(), v.end(), 0);

    // Output: 10
    std::cout << "Sum: " << sum << std::endl;
    return 0;
}

4. count()

How many times have we seen this face? ๐Ÿ‘€

Counts the occurrences of a specific element in a range.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 2, 3, 4, 2};
    int countTwo = std::count(v.begin(), v.end(), 2);

    // Output: 3
    std::cout << "Count of 2: " << countTwo << std::endl;
    return 0;
}

5. find()

Whereโ€™s Waldo? ๐Ÿ‘“

Returns an iterator to the first occurrence of an element in the range.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    auto it = std::find(v.begin(), v.end(), 3);

    // Output: Found at position 2
    if (it != v.end()) std::cout << "Found 3 at position: " << std::distance(v.begin(), it) << std::endl;
    return 0;
}

6. is_permutation()

Twinsies! ๐Ÿคฉ

Checks if one range is a permutation of another.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v1 = {1, 2, 3};
    std::vector<int> v2 = {3, 2, 1};

    if (std::is_permutation(v1.begin(), v1.end(), v2.begin())) {
        // Output: Yes, they are permutations!
        std::cout << "Yes, they are permutations!" << std::endl;
    }
    return 0;
}

7. is_sorted()

Are we in order? โœ…

Checks if the elements in a range are sorted in non-decreasing order.

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    if (std::is_sorted(v.begin(), v.end())) {
        // Output: Yes, sorted!
        std::cout << "Yes, sorted!" << std::endl;
    }
    return 0;
}

8. partial_sum()

Adding up the vibes ๐Ÿ”ฅ

Computes the cumulative sum of elements in a range.

#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>

int main() {
    std::vector<int> v = {1, 2, 3, 4};
    std::vector<int> result(v.size());
    std::partial_sum(v.begin(), v.end(), result.begin());

    // Output: 1 3 6 10
    for (int num : result) std::cout << num << " ";
    return 0;
}

Non-manipulative algorithms are like your super cool, chill friends who keep things running smoothly without interfering. They help you analyze, find, and verify things without changing the flow of your data. So sit back, relax, and let these algorithms do their thing! ๐Ÿ˜Ž

1
Subscribe to my newsletter

Read articles from Sohil_Tamboli directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sohil_Tamboli
Sohil_Tamboli