[2026] C++ Algorithm Replace | 치환 알고리즘 가이드
이 글의 핵심
C++ replace, replace_if, replace_copy로 범위 치환. 원본 수정과 복사본 생성의 차이·조건 치환 실무 예를 다룹니다.
들어가며
C++ STL의 replace 알고리즘은 컨테이너의 요소를 효율적으로 치환할 수 있게 해줍니다. 값 기반 치환과 조건 기반 치환을 모두 지원합니다.
코딩 테스트 준비하며 깨달은 것
알고리즘 문제를 풀다 보면 “이게 실무에 무슨 도움이 될까?” 하는 의문이 들 때가 있습니다. 저도 그랬습니다. 하지만 실제 프로젝트에서 성능 문제에 부딪히면, 알고리즘 지식이 얼마나 중요한지 깨닫게 됩니다. 예를 들어, 사용자 검색 기능이 느려서 고민하다가 해시 테이블을 적용하니 응답 시간이 10초에서 0.1초로 줄어든 경험이 있습니다. 코딩 테스트는 단순히 취업을 위한 관문이 아니라, 문제 해결 능력을 키우는 훈련장입니다. 처음엔 브루트 포스로 풀다가, 시간 복잡도를 개선하는 과정에서 “아, 이렇게 생각하면 되는구나” 하는 깨달음을 얻을 때의 쾌감은 말로 표현하기 어렵습니다. 이 글에서는 단순히 정답 코드만 제시하는 게 아니라, 문제를 어떻게 접근하고 최적화하는지 사고 과정을 함께 공유하겠습니다.
1. std::replace
기본 사용
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 2, 4, 2, 5};
std::cout << "원본: ";
for (int x : v) {
std::cout << x << " "; // 1 2 3 2 4 2 5
}
std::cout << std::endl;
// 2를 9로 치환
std::replace(v.begin(), v.end(), 2, 9);
std::cout << "치환 후: ";
for (int x : v) {
std::cout << x << " "; // 1 9 3 9 4 9 5
}
std::cout << std::endl;
}
문자열 치환
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <string>
int main() {
std::string text = "Hello World";
// 공백을 밑줄로 치환
std::replace(text.begin(), text.end(), ' ', '_');
std::cout << text << std::endl; // Hello_World
// 특정 문자 치환
std::string code = "int x = 10;";
std::replace(code.begin(), code.end(), ' ', '\t');
std::cout << code << std::endl; // int x = 10;
}
함수 시그니처:
template<class ForwardIt, class T>
void replace(ForwardIt first, ForwardIt last,
const T& old_value, const T& new_value);
핵심 개념:
- 원본 수정: 컨테이너를 직접 수정
- 모든 일치: 일치하는 모든 요소 치환
- 시간 복잡도: O(n)
2. std::replace_if
조건 기반 치환
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// 짝수를 0으로 치환
std::replace_if(v.begin(), v.end(),
{ return x % 2 == 0; }, 0);
for (int x : v) {
std::cout << x << " "; // 1 0 3 0 5 0 7 0 9 0
}
std::cout << std::endl;
}
복잡한 조건
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> scores = {45, 67, 89, 34, 92, 78, 56};
// 60점 미만을 0으로
std::replace_if(scores.begin(), scores.end(),
{ return score < 60; }, 0);
std::cout << "점수: ";
for (int score : scores) {
std::cout << score << " "; // 0 67 89 0 92 78 0
}
std::cout << std::endl;
}
3. std::replace_copy
원본 유지하며 치환
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> src = {1, 2, 3, 2, 4, 2, 5};
std::vector<int> dst;
// 복사하며 치환 (원본 유지)
std::replace_copy(src.begin(), src.end(),
std::back_inserter(dst), 2, 9);
std::cout << "원본: ";
for (int x : src) {
std::cout << x << " "; // 1 2 3 2 4 2 5 (변경 없음)
}
std::cout << std::endl;
std::cout << "복사본: ";
for (int x : dst) {
std::cout << x << " "; // 1 9 3 9 4 9 5
}
std::cout << std::endl;
}
std::replace_copy_if
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> src = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::vector<int> dst;
// 짝수를 0으로 치환하며 복사
std::replace_copy_if(src.begin(), src.end(),
std::back_inserter(dst),
{ return x % 2 == 0; }, 0);
std::cout << "원본: ";
for (int x : src) {
std::cout << x << " "; // 1 2 3 4 5 6 7 8 9 10
}
std::cout << std::endl;
std::cout << "복사본: ";
for (int x : dst) {
std::cout << x << " "; // 1 0 3 0 5 0 7 0 9 0
}
std::cout << std::endl;
}
4. 실전 예제
예제 1: 데이터 정제
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
// 센서 데이터 (오류 값 -1 포함)
std::vector<int> sensorData = {23, -1, 25, 24, -1, 26, 23, -1};
// 오류 값을 평균값으로 치환
int validSum = 0;
int validCount = 0;
for (int value : sensorData) {
if (value != -1) {
validSum += value;
validCount++;
}
}
int average = validSum / validCount;
std::replace(sensorData.begin(), sensorData.end(), -1, average);
std::cout << "정제된 데이터: ";
for (int value : sensorData) {
std::cout << value << " "; // 23 24 25 24 24 26 23 24
}
std::cout << std::endl;
}
예제 2: 텍스트 처리
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <string>
int main() {
std::string text = "Hello, World! How are you?";
// 구두점을 공백으로
std::replace_if(text.begin(), text.end(),
{ return c == ',' || c == '!' || c == '?'; }, ' ');
std::cout << text << std::endl;
// Hello World How are you
// 연속된 공백 제거는 unique 사용
}
예제 3: 범위 치환
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> grades = {95, 45, 78, 34, 89, 67, 23, 91};
// 60점 미만을 60점으로 상향 (최소 점수 보장)
std::replace_if(grades.begin(), grades.end(),
{ return grade < 60; }, 60);
std::cout << "조정된 점수: ";
for (int grade : grades) {
std::cout << grade << " "; // 95 60 78 60 89 67 60 91
}
std::cout << std::endl;
}
5. 치환 알고리즘 정리
알고리즘 비교
| 알고리즘 | 원본 수정 | 조건 | 시간 복잡도 |
|---|---|---|---|
replace | ✅ | 값 비교 | O(n) |
replace_if | ✅ | Predicate | O(n) |
replace_copy | ❌ | 값 비교 | O(n) |
replace_copy_if | ❌ | Predicate | O(n) |
함수 시그니처
다음은 cpp를 활용한 상세한 구현 코드입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// 값 치환 (원본 수정)
template<class ForwardIt, class T>
void replace(ForwardIt first, ForwardIt last,
const T& old_value, const T& new_value);
// 조건 치환 (원본 수정)
template<class ForwardIt, class UnaryPredicate, class T>
void replace_if(ForwardIt first, ForwardIt last,
UnaryPredicate pred, const T& new_value);
// 복사하며 값 치환
template<class InputIt, class OutputIt, class T>
OutputIt replace_copy(InputIt first, InputIt last, OutputIt d_first,
const T& old_value, const T& new_value);
// 복사하며 조건 치환
template<class InputIt, class OutputIt, class UnaryPredicate, class T>
OutputIt replace_copy_if(InputIt first, InputIt last, OutputIt d_first,
UnaryPredicate pred, const T& new_value);
6. 자주 발생하는 문제
문제 1: 원본 수정 vs 복사
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 2, 4};
// replace: 원본 수정
std::replace(v.begin(), v.end(), 2, 9);
std::cout << "원본 수정: ";
for (int x : v) {
std::cout << x << " "; // 1 9 3 9 4
}
std::cout << std::endl;
// ✅ 원본 유지하려면 replace_copy
std::vector<int> v2 = {1, 2, 3, 2, 4};
std::vector<int> dst;
std::replace_copy(v2.begin(), v2.end(),
std::back_inserter(dst), 2, 9);
std::cout << "원본: ";
for (int x : v2) {
std::cout << x << " "; // 1 2 3 2 4 (변경 없음)
}
std::cout << std::endl;
}
문제 2: 여러 값 치환
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// ❌ 비효율적: 여러 번 순회
std::replace(v.begin(), v.end(), 2, 0);
std::replace(v.begin(), v.end(), 4, 0);
// ✅ 효율적: 한 번 순회
std::vector<int> v2 = {1, 2, 3, 4, 5};
std::replace_if(v2.begin(), v2.end(),
{ return x == 2 || x == 4; }, 0);
for (int x : v2) {
std::cout << x << " "; // 1 0 3 0 5
}
std::cout << std::endl;
}
문제 3: std::string::replace와 혼동
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <string>
int main() {
std::string text = "hello world";
// std::replace (알고리즘): 문자 하나씩 치환
std::replace(text.begin(), text.end(), 'l', 'L');
std::cout << text << std::endl; // heLLo worLd
// std::string::replace (멤버 함수): 부분 문자열 치환
text.replace(0, 5, "HELLO");
std::cout << text << std::endl; // HELLO worLd
// 다른 기능!
}
문제 4: 반복자 무효화
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// ✅ replace는 반복자를 무효화하지 않음
auto it = v.begin();
std::replace(v.begin(), v.end(), 3, 99);
std::cout << *it << std::endl; // 1 (여전히 유효)
// 주의: 크기 변경 연산(insert, erase)은 반복자 무효화
}
7. transform vs replace
차이점
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2 = {1, 2, 3, 4, 5};
// replace: 특정 값만 치환
std::replace(v1.begin(), v1.end(), 2, 9);
std::cout << "replace: ";
for (int x : v1) {
std::cout << x << " "; // 1 9 3 4 5
}
std::cout << std::endl;
// transform: 모든 요소 변환
std::transform(v2.begin(), v2.end(), v2.begin(),
{ return x * 2; });
std::cout << "transform: ";
for (int x : v2) {
std::cout << x << " "; // 2 4 6 8 10
}
std::cout << std::endl;
}
언제 무엇을 사용할까
| 상황 | 사용할 알고리즘 |
|---|---|
| 특정 값을 다른 값으로 | replace |
| 조건에 맞는 값만 치환 | replace_if |
| 모든 요소를 변환 | transform |
| 원본 유지하며 치환 | replace_copy |
8. 실전 예제: 데이터 전처리
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
class DataPreprocessor {
public:
// 이상치 제거 (평균으로 치환)
static void replaceOutliers(std::vector<double>& data, double threshold) {
double mean = std::accumulate(data.begin(), data.end(), 0.0) / data.size();
std::replace_if(data.begin(), data.end(),
[mean, threshold](double x) {
return std::abs(x - mean) > threshold;
}, mean);
}
// 음수를 0으로
static void replaceNegatives(std::vector<int>& data) {
std::replace_if(data.begin(), data.end(),
{ return x < 0; }, 0);
}
// 결측치 처리
static void replaceMissing(std::vector<int>& data, int missingValue, int replacement) {
std::replace(data.begin(), data.end(), missingValue, replacement);
}
};
int main() {
// 센서 데이터
std::vector<double> temperatures = {23.5, 24.0, 100.0, 23.8, 24.2, -50.0, 24.5};
std::cout << "원본: ";
for (double t : temperatures) {
std::cout << t << " ";
}
std::cout << std::endl;
// 이상치 제거 (평균에서 50 이상 차이)
DataPreprocessor::replaceOutliers(temperatures, 50.0);
std::cout << "전처리 후: ";
for (double t : temperatures) {
std::cout << t << " ";
}
std::cout << std::endl;
}
정리
핵심 요약
- replace: 특정 값을 다른 값으로 치환 (원본 수정)
- replace_if: 조건에 맞는 값 치환
- replace_copy: 복사하며 치환 (원본 유지)
- replace_copy_if: 복사하며 조건 치환
- 시간 복잡도: 모두 O(n)
실전 팁
- 선택 기준
- 원본 수정 가능:
replace,replace_if - 원본 유지:
replace_copy,replace_copy_if - 특정 값:
replace,replace_copy - 조건 기반:
replace_if,replace_copy_if
- 원본 수정 가능:
- 성능 최적화
- 여러 값 치환 시
replace_if사용 - 단일 패스로 처리
- 불필요한 복사 피하기
- 여러 값 치환 시
- 주의사항
std::string::replace와 다름- 반복자는 유효 (크기 변경 없음)
- Predicate는 부작용 없어야 함
다음 단계
- C++ Algorithm Reverse
- C++ Algorithm Remove
- C++ Algorithm Transform