본문 바로가기
개발/C++ (98,03,11,14,17,20,23)

Modern C++ : 직접 구현한 표준 알고리즘, equal, fill_n, iota, copy, accumulate (98, 11)

by snowoods 2025. 9. 14.

Modern C++

직접 구현한 표준 알고리즘: equal, fill_n, iota, copy, accumulate

 

개요

C++ 표준 라이브러리의 <algorithm> 헤더에 포함된 기본 알고리즘들을 직접 구현해보는 예제입니다. 반복자(Iterator)를 사용하여 컨테이너의 원소를 순회하고 조작하는 방법을 이해하는 데 도움이 됩니다. 이 문서에서는 equal, fill_n, iota, copy, accumulate 함수의 구현과 사용법을 다룹니다.

 

C++ 버전별 주요 키워드 도입 시기

  • C++98: std::vector, 반복자(iterator) 개념, <algorithm> 헤더의 기본 함수들
  • C++11: cstdint (예: std::int32_t), std::boolalpha

 

내용 설명

mystd 네임스페이스 안에 표준 라이브러리 함수와 유사하게 동작하는 함수들을 구현했습니다.

  • equal: 두 범위(range)의 원소들이 모두 같은지 순서대로 비교하여 bool 값을 반환합니다.
  • fill_n: 주어진 시작 위치부터 지정된 개수(count)만큼의 원소를 특정 값으로 채웁니다.
  • iota: 주어진 범위에 시작 값부터 1씩 증가하는 연속된 값들을 채웁니다.
  • copy: 한 범위의 원소들을 다른 범위의 시작 위치로 복사합니다.
  • accumulate: 주어진 범위의 모든 원소 값을 초기값(init)에 더하여 누적 합계를 반환합니다.

 

예제 코드

#include <cstdint>
#include <iostream>
#include <vector>

// print_vector from utils.h
template <typename T>
void print_vector(const std::vector<T> &vector)
{
    for (std::size_t i = 0; i < vector.size() - 1; i++)
    {
        std::cout << vector[i] << ", ";
    }
    std::cout << vector[vector.size() - 1] << '\n';
}


namespace mystd
{
using Iterator = std::vector<std::int32_t>::iterator;

bool equal(Iterator first1, Iterator last1, Iterator first2)
{
    for (; first1 != last1; ++first1, ++first2)
    {
        if (*first1 != *first2)
        {
            return false;
        }
    }
    return true;
}

Iterator fill_n(Iterator first, std::size_t count, const std::int32_t &value)
{
    for (std::size_t i = 0; i < count; ++i)
    {
        *first = value;
        ++first;
    }
    return first;
}

void iota(Iterator first, Iterator last, std::int32_t value)
{
    while (first != last)
    {
        *first = value;
        ++first;
        ++value;
    }
}

Iterator copy(Iterator first, Iterator last, Iterator d_first)
{
    while (first != last)
    {
        *d_first = *first;
        ++d_first;
        ++first;
    }
    return d_first;
}

std::int32_t accumulate(Iterator first, Iterator last, std::int32_t init)
{
    while (first != last)
    {
        init += *first;
        ++first;
    }
    return init;
}

} // namespace mystd

int main()
{
    auto vec1 = std::vector<std::int32_t>(5, 0);
    auto vec2 = std::vector<std::int32_t>(5, 0);
    std::cout << std::boolalpha
              << mystd::equal(vec1.begin(), vec1.end(), vec2.begin()) << '\n';

    mystd::fill_n(vec1.begin(), 5, 1);
    print_vector(vec1);

    mystd::iota(vec2.begin(), vec2.end(), 0);
    print_vector(vec2);
    std::cout << std::boolalpha
              << mystd::equal(vec1.begin(), vec1.end(), vec2.begin()) << '\n';

    mystd::copy(vec2.begin(), vec2.end(), vec1.begin());
    std::cout << std::boolalpha
              << mystd::equal(vec1.begin(), vec1.end(), vec2.begin()) << '\n';

    const auto sum = mystd::accumulate(vec1.begin(), vec1.end(), 0);
    std::cout << sum << '\n';

    return 0;
}

 

실행 결과

true
1, 1, 1, 1, 1
0, 1, 2, 3, 4
false
true
10

 

활용 팁

  • 학습 목적: 표준 라이브러리 알고리즘을 직접 구현하면 반복자와 템플릿의 작동 방식에 대한 이해를 크게 높일 수 있습니다.
  • 실무 적용: 실제 프로젝트에서는 직접 구현하기보다 최적화되고 검증된 표준 라이브러리(std::) 버전을 사용하는 것이 안전하고 효율적입니다.
  • 유연성 확장: 예제에서는 Iteratorstd::vector<std::int32_t>::iterator로 고정했지만, 함수를 템플릿으로 만들면 다양한 타입의 컨테이너와 데이터에 대응할 수 있는 더 유연하고 재사용성 높은 코드를 작성할 수 있습니다.