반응형

cpp algorithm

include <algorithm>


순서 변경,  수정 api


+copy 

OutputIterator copy(InputIterator first, last, OutputIterator result) ;

[first, last) 범위의 데이터를 result 위치에 복사한다. 

리턴값은 목적지 범위의 마지막 이터레이터.

while(first!=last) {

 *result = *first ;

 result++ ; first++ ;

}

return result ;


ex) 

int myints[]={10,20,30,40,50,60,70} ;

std::vector<int> myvec(7) ;

std::copy(myints, myints+7, myvec.begin()) ;    // myints의 모든 요소를 벡터로 복사.


+copy_n(first, n, result) ;    // c++11

first위치에서 n개 까지만 result로 복사한다.

std::copy_n(myints, 7, myvec.begin()) ;    // myints에서 7개의 요소를 벡터로 복사.


+copy_if(first, last, result, UnaryPredicate pred) ;    // c++11

지정범위에서 조건을 만족하는 것만 복사.

auto it = std::copy_if( foo.begin(), foo.end(), bar.begin(), [](int i) { return i>=0; } ) ;    // 양수만 복사.

bar.resize( std::distance(bar.begin(), it) ;    // 요소크기만큼 크기를 줄임.


+copy_backward() ; 뒤에서 부터 복사.

myvec ; 10,20,30,40,50

myvec.resize( myvec.size()+3) ;    // 크기를 3 늘림.

std::copy_backward( myvec.begin(), myvec.begin()+5, myvec.end() ) ; // myvec의 [0,5) 범위를 myvec.size()의 가장 뒤에서 부터 거꾸로 채움.  

10,20,30,40,50, ? , ? ,? ==> 

10,20,30,10,20,30,40,50


+move() ; 요소를 이동시킴 // c++11

이동한 데이터는 남아있음.

move와 copy의 차이는 기본적으로 같은데, move는 같은 버퍼내에서의 복사를 보장해 준다.

[first, last)의 데이터는 유효하고 unspecified로 남아있다.

- move_backward()    // c++11


-swap ;  두 값이나 컨테이너를 바꾼다.

int x=10, y=20 ;

std::swap(x,y) ;        // x, y의 값이 바뀐다. 따라서 x=20, y=10

std::vector<int> foo(4,x),   bar(6,y) ;    // foo=20,20,20,20,    bar=10,10,10,10,10,10

std::swap(foo, bar) ;        // foo=10,10,10,10,10,10, bar=20,20,20,20


-swap_ranges ; 범위내에서 바꿈.

std::vector<int> foo(5,10) ;    // foo=10,10,10,10,10

std::vector<int> bar(5,33) ;    // bar=33,33,33,33,33

std:;swap_ranges(foo.begin()+1, foo.end()-1, bar.begin()) ;    // foo의 범위 [1,4) ; 즉 가운데 3개를 bar의 시작부터 3개와 바꾼다.

// foo = 10,33,33,33,10,    bar=10,10,10,33,33


-iter_swap ; 두 개의 이터레이터가 가리키는 값을 서로 바꾼다.

int myints[]={10,20,30,40,50} ;

std::vector<int> myvec(4, 99) ;    // 99,99,99,99

std::iter_swap( myints, myvec.begin() ); // myints=99,20,30,40,50,   myvec=10,99,99,99

std::iter_swap( myints+3, myvec.begin()+2) ; // myints=99,20,30,99,50,  myvec=10,99,40,99


-transform() ; 한개의 값 또는  두 컨테이너의 값을 순차적으로 어떤 작업을 하여 저장한다.

transform(InputIterator first1, last1, OutputIterator result, UnaryOperation op) ;

transform(first1, last1, first2, result, BinaryOperation binary_op) ;

ex)  모든 원소를 1씩 증가

int op_increase(int i) { return ++i ; } 

std::vector<int> bar ;

bar.resize(foo.size()) ;

std::transform( foo.begin(), foo.end(), bar.begin(), op_increase) ;

ex) 두 컨테이너의 값을 더함.

std::transform( foo.begin(), foo.end(), bar.begin(), scott.begin(), std::plus<int>()) ;

// foo, bar의 각각 요소를 순차적으로 더해서 scott에 추가.   plus는 include <functional>


-replace() ; [first, last) 범위에서 old_value를 new_value로 교체한다.

std::replace( myvec.begin(), myvec.end(), 20, 99) ;    // 20을 99로 모두 교체함. 


-replace_if() ; [first, last) 범위에서 조건에 따라 new_value로 바꾼다.

ex) 홀수를 0으로 바꿈.

bool isodd(int i) { return (i%2)==1 ; }

std::replace_if( myvec.begin(), myvec.end(), isodd, 0) ;


-replace_copy, replace_copy_if ; replace와 비슷하지만 원본 자체를 변경하지 않고, 대상으로 복사한다.

std::replace_copy( myints, myints+8, myvec.begin(), 20, 99) ;    // myints에서 20을 99로 바꾸어 myvec에 복사.

std::replace_copy_if( foo.begin(), foo.end(), bar.begin(), isodd, 0) ;


-fill ; 특정 값으로 채움.

fill(first, last, value)

std::vector<int> myvec(8) ;            // 0,0,0,0,0,0,0,0

std::fill(myvec.begin(), myvec.begin()+4, 5) ;    // 5,5,5,5,0,0,0,0

std::fill(myvec.begin()+3, myvec.end()-2, 8) ;    // 5,5,5,8,8,8,0,0


-fill_n ; 특정 값으로 채움. 시작위치, 개수, 값.

std::fill_n(myvec.begin(), 4, 20) ;    // 앞에서 부터 4개를 20으로 채움.

std::fill_n(myvec.begin()+3, 3, 30) ;    // 인덱스3번(네번째요소) 부터 3개를 30으로 채움.


-generate ; 컨테이너의 일부 범위를 gen함수로 만든 값으로 채움.

include ; iostream, algorithm, vector, 

ctime ; for std::time

cstdlib ; for std::rand, std::srand


int RandomNumber() { return (std::rand()%100) ; }

struct c_unique() {

   int current ;

   c_unique() { current=0 ; }

   int operator() { return ++current ; }

} UniqueNumber ;


std::srand( unsigned(std::time(0)) ) ;

std::vector<int> myvec(8) ;

std::generate(myvec.begin(), myvec.end(), RandomNumber) ; // 0~99범위 랜덤하게 8개.

std::generate(myvec.begin(), myvec.end(), UniqueNumber) ;    // 1,2,3,4,5,6,7,8


-generate_n(first, n, generator) ; 상동.


-remove ; 범위에서 값과 일치하는 것을 삭제하여 붙임. 뒤에는 빈공간. 삭제된 결과의 마지막 위치를 리턴.  원본 size가 수정되지 않음. 주의!

remove(first, last, val) ;

int myints[]={10,20,30,30,20,10,10,20} ;

int* pbegin = myints ;

int* pend = myints+sizeof(myints)/sizeof(int) ;

pend = std::remove( pbegin, pend, 20) ;    // 20을 삭제.  10,30,30,10,10,?,?,?

// pend는 마지막 10 뒤의 ? 위치.


-remove_if(first, last, UnaryPredicate pred) ;

pred가 true리턴하면 요소 삭제. 삭제방식은 remove와 같다.

pend = std::remove_if(pbegin, pend, isodd) ;

bool isodd(int i) { return (i%2)==1 ; } 


-remove_copy(first, last, result, val) ;

원본을 수정하지 않고, 결과를 복사한다.

std::vector<int> myvec(8) ;

std::remove_copy( myints, myints+8, myvec.begin(), 20) ;    // myints의 해당 범위에서 20을 제외하고 복사함.

myvec에서 복사된 크기를 알려면 리턴결과의 iterator를 통해 길이 계산이 필요함. 위에서 pend 

std::vector<int>::iterator iend = std::remove_copy(...) ;

데이터 유효범위는 [myvec.begin(), iend) 이다.


-remove_copy_if(first, last, result, UnaryPredicate pred) ;


-unique(first, last) ; 연속된 중복 제거. 주의; 전체에서 유일한 값이 아님.  컨테이너 크기는 변하지 않음.

// myvec ; 10,20,20,20,30,30,2020,10

it = std::unique( myvec.begin(), myvec.end()) ;    // 10,20,30,20,10,?,?.?,?

// shrink 하려면

myvec.resize( std::distance(myvector.begin(), it) ) ;    // 10,20,30,20,10


-unique(first, last, BinaryPredicate pred) ;

-unique_copy(first, last, result) ;

-unique_copy(first, last, result, pred) ;


-reverse() ; 순서를 거꾸로 만든다.

reverse(first, last) ;

myvec ; 1,2,3,4,5

std::reverse(myvec.begin(), myvec.end()) ;    // 5 4 3 2 1


-reverse_copy(first, last, result) ;    

int myints[]={1,2,3,4,5} ;

std::vector<int> myvec(5) ; // or myvec.resize(5) ;

std::reverse)copy(myints, myints+5, myvec.begin()) ;

// 원본은 그대로고, myvec은 5 4 3 2 1


-rotate(first, middle, last) ;    // 쉬프트 시킨다.

middle부터 있는 데이터들을 first위치부터 일련되게 이동한다.

// myvec ; 1 2 3 4 5 6 7 8 9

std::rotate( myec.begin(), myvec.begin()+3, myvec.end() ); // 인덱스3을 인덱스0으로 이동. 일련되게 모든 요소를 이동.

// myvec ; 4 5 6 7 8 9 1 2 3


// left shift

std::rotate(myvec.begin(), myvec.begin()+1, myvec.end()) ;    // 2 3 4 5 6 7 8 9 1

// right shift

std::rotate(myvec.begin(), myvec.end()-1, myvec.end()) ;     // 9 1 2 3 4 5 6 7 8

-rotate_copy(first, middle, last, result) ; 결과를 복사. 원본 유지


-random_shuffle(first, last) ;순서를 랜덤하게 섞는다.

std::random_shuffle(myvec.begin(), myvec.end()) ;
랜덤함수 지정 가능.
std::random_shuffle(myvec.begin(), myvec.end(), gen) ;
int gen(int i) { return std::rand()%i; }     // 0~ (i-1) 까지 랜덤.
마지막원소를 gen(n)으로 발생시킨 인덱스 원소와 바꾸고, 마지막 전 원소를 gen(n-1)의 인덱스와 바꾸고 계속 한다.

-shuffle(first, last, g) ; C++11
순서를 랜덤하게 섞는다. 랜덤은 uniform random number generator를 사용한다.

















+ Recent posts