Worldscope

algorithm transform() function

Palavras-chave:

Publicado em: 06/08/2025

Understanding the `std::transform` Algorithm in C++

The `std::transform` algorithm in C++ is a powerful tool for applying a function to a range of elements and storing the results in another range. This article aims to provide a comprehensive understanding of `std::transform`, covering its usage, implementation details, complexity analysis, and alternative approaches.

Fundamental Concepts / Prerequisites

Before diving into `std::transform`, it's beneficial to have a basic understanding of the following concepts:

  • Iterators: Iterators are essential for traversing elements within containers in C++. You should be familiar with different iterator categories (input, output, forward, bidirectional, random access).
  • Lambda Expressions (or Function Objects): `std::transform` often uses lambda expressions or function objects to define the operation to be performed on the elements.
  • Containers: Basic knowledge of C++ containers like `std::vector`, `std::array`, etc., is needed to understand how to use `std::transform` with different data structures.

Implementation in C++

The following code demonstrates a common usage of `std::transform`. It applies a squaring operation to a vector of integers and stores the squared values in another vector.


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

int main() {
  // Input vector
  std::vector<int> numbers = {1, 2, 3, 4, 5};

  // Output vector (initially empty)
  std::vector<int> squared_numbers(numbers.size());

  // Apply the square function using std::transform
  std::transform(numbers.begin(), numbers.end(), squared_numbers.begin(), [](int n){ return n * n; });

  // Print the squared numbers
  std::cout << "Original numbers: ";
  for (int num : numbers) {
    std::cout << num << " ";
  }
  std::cout << std::endl;

  std::cout << "Squared numbers: ";
  for (int num : squared_numbers) {
    std::cout << num << " ";
  }
  std::cout << std::endl;

  return 0;
}

Code Explanation

1. #include <iostream>, #include <vector>, #include <algorithm>: These lines include the necessary header files for input/output, vectors, and the `std::transform` algorithm, respectively.

2. std::vector<int> numbers = {1, 2, 3, 4, 5};: This creates a vector named `numbers` initialized with integer values from 1 to 5. This is the input range to be transformed.

3. std::vector<int> squared_numbers(numbers.size());: This creates a vector named `squared_numbers` with the same size as `numbers`. Crucially, the output vector must be pre-allocated with the correct size, or you risk out-of-bounds writes.

4. std::transform(numbers.begin(), numbers.end(), squared_numbers.begin(), [](int n){ return n * n; });: This is the core of the example. It applies the transformation:

  • numbers.begin() and numbers.end(): Define the input range (from the beginning to the end of the `numbers` vector).
  • squared_numbers.begin(): Specifies the beginning of the output range (where the transformed elements will be stored).
  • [](int n){ return n * n; }: This is a lambda expression that defines the transformation function. It takes an integer `n` as input and returns its square.

5. The remaining code prints the original and transformed vectors to the console.

Complexity Analysis

The `std::transform` algorithm iterates through each element in the input range once. Therefore, its time complexity is directly proportional to the number of elements in the range.

  • Time Complexity: O(n), where n is the number of elements in the input range.
  • Space Complexity: The space complexity depends on the lambda or function object used for the transformation. In the example above, the space complexity is O(1) as the lambda function performs a simple multiplication operation, requiring constant additional space. However, if the transformation function involves creating new data structures or objects for each element, the space complexity could increase. Critically, `std::transform` *requires* the output range to be pre-allocated, so the memory for the *output* isn't part of the space complexity of the algorithm itself. The space complexity accounts for the *additional* space used during the transformation beyond the input and output.

Alternative Approaches

Instead of `std::transform`, you could use a traditional `for` loop to iterate through the input vector and apply the transformation manually. This approach provides more control but can be more verbose and error-prone. For example:


#include <iostream>
#include <vector>

int main() {
  std::vector<int> numbers = {1, 2, 3, 4, 5};
  std::vector<int> squared_numbers(numbers.size());

  for (size_t i = 0; i < numbers.size(); ++i) {
    squared_numbers[i] = numbers[i] * numbers[i];
  }

  // Print the squared numbers (same as before)
  std::cout << "Squared numbers (using for loop): ";
  for (int num : squared_numbers) {
    std::cout << num << " ";
  }
  std::cout << std::endl;

  return 0;
}

The main trade-off is readability and maintainability. `std::transform` clearly expresses the intent (applying a function to a range), while the `for` loop approach mixes iteration logic with the transformation itself. For more complex transformations, `std::transform` can often lead to more concise and readable code, especially when used with well-defined function objects or lambdas.

Conclusion

The `std::transform` algorithm is a versatile tool in C++ for applying a function to a range of elements. Its efficiency (O(n) time complexity) and expressive power make it suitable for various data processing tasks. Remember to pre-allocate memory for the output range and consider using lambda expressions or function objects to define the transformation logic clearly. While alternative approaches like `for` loops exist, `std::transform` often provides a more readable and maintainable solution.