HOWTO · C++
C++에서 벡터 셔플
이 기사에서는 C++에서 벡터를 섞는 방법을 소개합니다.
이 페이지의 내용
C++ 벡터의 요소 순서를 제자리에서 무작위로 바꾸려면 벡터의 begin() 및 end() 반복자와 난수 엔진을 std::shuffle에 전달하면 됩니다. 이 알고리즘은 지정한 범위의 요소를 재배열하며, 별도의 벡터를 만들지는 않습니다. 의사 난수 선택 순서를 반복하려면 엔진에 고정 시드를 사용하고, 실행할 때마다 대체로 다른 순서를 원한다면 적절한 출처의 값으로 엔진을 초기화하세요.
std::shuffle로 벡터 섞기
std::shuffle은 <algorithm> 헤더에 선언되어 있습니다. 첫 두 인수는 반열린 반복자 범위를 지정합니다. 첫 번째 반복자는 포함할 첫 요소를 가리키고, 두 번째 반복자는 마지막 요소 바로 다음을 가리킵니다. 따라서 벡터에서는 values.begin()과 values.end()가 벡터 전체를 가리킵니다. 세 번째 인수는 UniformRandomBitGenerator이며, 흔히 std::mt19937 같은 엔진을 사용합니다. 엔진은 순열을 선택하는 데 필요한 난수 비트를 제공하며, 이미 섞인 벡터를 반환하는 콜백이 아닙니다.
이 완전한 예제는 프로그램을 실행할 때마다 엔진이 같은 상태에서 시작하도록 고정 시드를 사용합니다. std::shuffle은 특정한 섞기 순서를 보장하지 않습니다. 표준 라이브러리 구현에 따라 결과가 달라질 수 있으므로 아래 출력은 보장된 순서가 아니라 한 가지 예로 보세요.
이 예제를 실행하세요:
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <random>
#include <vector>
int main() {
std::vector<int> values{12, 32, 43, 53, 23, 65, 84};
std::mt19937 engine(42);
std::shuffle(values.begin(), values.end(), engine);
for (std::size_t i = 0; i < values.size(); ++i) {
if (i != 0) {
std::cout << ' ';
}
std::cout << values[i];
}
std::cout << '\n';
}
입력 벡터는 12 32 43 53 23 65 84입니다. 제공된 성공 실행에서 프로그램은 다음과 같은 순서로 요소를 출력했습니다.
23 12 43 53 84 65 32
고정 시드를 사용하면 같은 구현과 설정에서 의사 난수 엔진의 순서를 재현할 수 있습니다. 하지만 알고리즘이 모든 표준 라이브러리에서 동일한 선택 순서를 사용하도록 정해져 있지는 않으므로, 모든 구현에서 섞인 결과까지 같다고 보장하지는 않습니다. 실행마다 결과를 바꾸려면 엔진을 한 번 초기화한 뒤 여러 번 섞을 때 재사용하세요. 각 요소마다 또는 호출할 때마다 새 엔진을 만들지는 마세요. std::random_device를 시드 출처로 자주 사용하지만, 동작은 구현과 환경에 따라 다릅니다. 따라서 비결정성이나 암호학적 난수성을 보장한다고 설명해서는 안 됩니다.
표준 반복자 유틸리티를 사용하면 std::begin(values)와 std::end(values)로도 범위를 지정할 수 있습니다. 컨테이너 유형이나 내장 배열을 받아 처리하는 일반화된 함수를 작성할 때 유용한 형식입니다. 벡터만 다룬다면 멤버 반복자를 직접 사용하는 편이 간결하고 명확합니다. 어느 형식을 사용하든 양 끝 반복자는 같은 컨테이너에서 가져오고, 섞으려는 요소가 범위에 포함되도록 하세요. 이 연산은 벡터의 순서를 제자리에서 바꾸므로 이후에 벡터를 읽거나 순회하는 코드는 섞인 순서를 보게 됩니다.
std::random_shuffle을 사용하는 레거시 코드 다루기
std::random_shuffle은 기존 C++ 코드에서 볼 수 있는 오래된 표준 라이브러리 알고리즘입니다. 사용할 수 있는지는 프로젝트가 선택한 언어 표준과 라이브러리 구현에 따라 달라집니다. 이런 코드를 유지보수할 때는 해당 이름을 사용할 수 있다고 가정하기 전에 설정을 확인하세요. 이전 오버로드는 구현이 정한 난수 출처를 사용할 수 있으며, 생성기를 받는 오버로드는 std::shuffle의 엔진 인수와 요구사항이 다릅니다.
새 코드나 수정하는 코드에는 명시적인 난수 엔진을 전달하는 std::shuffle을 우선 사용하세요. 이렇게 하면 난수 출처가 분명해지고, 시드로 재현성을 제어할 수 있으며, 오래된 인터페이스에 의존하지 않아도 됩니다. 코드베이스에 std::random_shuffle이 있다는 이유만으로 모든 컴파일러 모드에서 사용할 수 있다고 판단하지 마세요. 반대로 모든 오래된 환경에서 std::shuffle을 사용할 수 없다고 추론해서도 안 됩니다. 호환성은 프로젝트의 표준 라이브러리와 언어 표준 설정에 따라 결정됩니다. 레거시 코드를 유지해야 한다면 해당 프로젝트에만 호환성 선택을 적용하고, 실제 빌드에 사용하는 컴파일러 설정으로 확인하세요.