반응형

cpp mutex

include <mutex>


+ mutex 사용하기

std::mutex mtx ;


void func(int id, int &v) {

   for (int i=0; i<10; i++) {

     mtx.lock() ;

    ++v ;

    mtx.unlock() ;

   }

}

int v=0 ;

std::thread t1 (func, 0, std::ref(v) ) ;

std:;thread t2(func, 1, std::ref(v) ) ;

t1.join();

t2.join() ;


-lock() ; 다른 쓰레드에 의해 lock되어 있지 않는 경우, 현재 쓰레드에서 락을 건다. unlock을 할 때까지 현재 쓰레드가 뮤텍스를 소유함. 

이미 다른쓰레드가 뮤텍스를 소유하고 있으면, 해제될때까지 블로킹 된다.

- lock을 얻은 상태에서 또 lock()을 하면 안된다. 데드락 발생.  (중복 lock을 하려면 recursive_mutex 사용)


+ bool try_lock() ; lock을 얻지 못하면 바로 리턴한다. 블로킹되지 않는 것이 lock()과 차이. 

뮤텍스를 얻었으면 true를 리턴하고, 작업 완료시 unlock()을 해주어야 한다.

다른 쓰레드가 뮤텍스 소유하고 있으면 false를 바로 리턴한다.


+ recursive_mutex  ; mutex와 비슷하나, lock 등급이 가능.

락을 얻은 상태에서 또 락을 얻을 수 있다. 뮤텍스 소유 레벨을 올림.

나중에 unlock()을 lock() 횟수만큼 해줘야 한다.



==> Mutex를 직접사용하지 말고 아래(lock_guard, unique_lock) 를 사용하기를 권장함.


+ lock_guard  ; 함수 내부에서 사용하여 간단하게 동기화 처리.

내부적으로 mutex를 사용하여 항상 락이 되도록 유지.

constructor에서 락을 얻고, destructor에서 언락을 한다.

std::mutex mtx ;

void func(int id) {

try {

   std::lock_guard<std::mutex> lck(mtx) ;

} catch ( std::logic_error & ) {

}

}


+unique_lock ; 뮤텍스를 사용하여 동기화 처리. lock_guard와 비슷하나 구동 시점을 지정할 수 있다.

lock, unlock을 사용 가능하며, 굳이 사용 안 해도 lock_guard 처럼 작동한다.

함수 일부분내에서 동기화 해제해도 되는 구간이 있을 경우에 사용하면 될 것 같다.

생성시점에 락을 안 걸 수도 있다.

guard(mutex, std::defer_lock) ; 이렇게 초기화하면 락을 얻지 않는다.






'Develop > C&CPP' 카테고리의 다른 글

stack / queue  (0) 2018.06.12
cstring  (0) 2018.06.11
thread  (0) 2018.06.09
utility  (0) 2018.06.08
fstream 1 basic_ifstream  (0) 2018.06.07
반응형

cpp thread

include <thread>


+간단한 thread 예

void func() { cout << "aaa" << endl ; }


thread t(&func) ; // func함수가 쓰레드로 실행.

t.join() ;    // thread t가 종료 될때 까지 기다림.


+ thread 함수에 파라미터 주기

void func(int x) {..} ;

thread t1(&func, 10) ;

thread t2(&func, 20) ;

t1.join() ;

t2.join() ;


+global 변수를 다중 thread로 카운팅하기

std::atomic<int> global_cnt(0) ;    // atomic 하게 작업.

void increase_global(int n) { 

   for (int i=0; i<n; i++) ++global_cnt; 

}

std::vector<std::thread> threads ;

for (int i=0; i<5; i++)

   threads.push_back( std::thread( increase_global, 100) ) ;

// 5개의 쓰레드로 100번씩 돌림. global_cnt=>500


+다른 방식

void increase_ref(std::atomic<int> &v , int n) {

   for (int i=0; i<n; i++) ++v; 

}

std::atomic<int> foo(0) ;

for (int i=0; i<5; i++)

   threads.push_back( std::thread( increase_ref, std::ref(foo), 100) ) ;

// 5개의 쓰레드로 100번씩 돌림. foo=500



+ main thread인지 아닌지 체크
std::thread::id main_thread_id = std::this_thread::get_id() ;    // thread id 얻기

void is_main_thread() {
if ( main_thread_id == std::this_thread::get_id() ) { cout << "Main thread" << endl ;}
else { cout <<"not main thread" << endl ; }
}

is_main_thread();
std::thread t (is_main_thread) ;
t.join() ;





'Develop > C&CPP' 카테고리의 다른 글

cstring  (0) 2018.06.11
thread mutex  (0) 2018.06.10
utility  (0) 2018.06.08
fstream 1 basic_ifstream  (0) 2018.06.07
functional 1 plus,minus,bind1st, bind2nd, equal_to, greater  (0) 2018.06.07
반응형

cpp utility

include <utility>


+swap ; 두 객체의 값들을 바꾼다.

int x=10, y=20 ;

std::swap(x,y) ;    // x=20, y=10


int foo[4] ;

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

std::swap(foo, bar) ;    // foo=1,2,3,4


+make_pair ; 두 객체를 pair로 만들어 리턴한다. 타입이 맞지 않으면 알아서 컨버팅 해준다.

std::pair<int,int> foo ;

foo = std::make_pair(10,20) ;

// access value: foo.first, foo.second



'Develop > C&CPP' 카테고리의 다른 글

thread mutex  (0) 2018.06.10
thread  (0) 2018.06.09
fstream 1 basic_ifstream  (0) 2018.06.07
functional 1 plus,minus,bind1st, bind2nd, equal_to, greater  (0) 2018.06.07
algorithm 4 merge, heap, min, max  (0) 2018.06.06
반응형

cpp fstream

include <fstream>


++ basic_ifstream

Input file stream

ios_base <- basic_ios <- basic_istream <- basic_ifstream


+constructor

explicit basic_ifstream(const char * filename, ios_base::openmode mode=ios_base::in) ;

const char *filename 대신 const string &filename도 지원.

ex)

std::ifstream ifs("test.txt", std::ifstream::in) ;

char c = ifs.get() ;

or

std::ifstream ifs ;

ifs.open( "test.txt", std::ifstream::in) ;

char c = ifs.get() ;


+ bool is_open() const ;  // 파일이 열려있는지 체크. true/false

+ void close() ;    // file close


+operator >>

스트림에서 타입에 맞게 읽음.

int n ;

std::cin >> n ;


+get

int_type get() ;

basic_istream& get(char_type &c) ;

basic_istream& get(char_type *s, streamsize n) ;    // n-1까지 읽음. 마지막은 null

basic_istream& get(char_type *s, streamsize n, char_type delim) ;


char str[256] ;
std::cin.get(str, 256) ;


+getline()
라인을 읽음 또는 구분자 까지 읽음.  버퍼크기는 null을 포함한 크기로 지정.
getline(char_type *s, streamsize n) ;
getline(char_type *s, streamsize n, char_type dilim) ;

std::cin.getline(name, 256) ;

+read()

null 체크없이 무조건 크기대로 읽음. 

read(char_type *s, streamsize n) ;

ex)

std::ifstream is("test.txt", std::ifstream::binary) ;

if ( is ) {

   is.seekg(0, is.end) ;    // move to last

 int length = is.tellg();    // file size

is.seekg(0, is.beg) ;    // move to first


char *buf = new char[length] ;

is.read(buf, length) ;

if ( is ) // read ok

else // read only is.gcount() ;

is.close() ;

delete[] buf;

}


+gcount() ; 읽은 데이터 크기

input operation이 읽은 데이터 크기.

std::cin.getline(str, 20) ;

std::cin.gcount() ;    // 실제 읽은 데이터 크기.


+ignore() ; 데이터를 읽고 버림.

ignore(streamsize n=1, int_type delim) ;

n개의 문자가 추출되거나 delim일 때까지 읽고 버림.


+peek() ; 다음 문자를 읽어 리턴하지만 스트림에서 뽑아내지는 않고 내비둠.

ex) 수 또는 문자열 읽기

std::cout << "input number or wrod:";

std::cout.flush() ;    // ouput 버퍼 출력하여 비움.


std::cin >> std::ws ;     // 앞에오는 white space를 지움

std::istream::int_type c ;

c = std::cin.peek() ;    // 문자 한 개를 미리 보기.

if ( c==std::char_traits<char>::eof() ) return 1 ;    // eof

if ( std::isdigit( c ) ) {

int n ;

std::cin >> n ;

} else {

std::string str ;

std::cin >> str ;

}


+putback(char_type c)

문자 하나를 버퍼에 집어 넣고, 마지막 추출 위치를 back 시킨다.

위의 예제와 동일한 기능을 다음과 같이 사용할 수  있다.

char c = std::cin.get() ;

if ( (c>='0') && (c<='9') ) {

   int n ;

   std::cin.putback(c) ;    // 또는 std.cin.unget() ;

   std::cin >> n ;

}


+ tellg    / tellp

tellg ; 입력스트림에서 현재의 위치를 리턴한다. (파일 오프셋이 마지막에 있으면 파일 크기가 된다.)

tellp ; 출력 스트림에서는 tellp를 쓴다. 

is.seekg(0, is.end ) ;

int filesize = is.tellg() ;


+seekg / seekp

seekg ; 입력 스트림에서 추출할 다음 문자 위치를 지정한다.

seekp ; 출력 스트림에서는 seekp를 쓴다.

seekg(pos_type pos) ;    // 시작 위치 기준으로 위치.

seekg(off_type off, ios_base::seekdir_way) ;    // 상대 위치, 기준.

seekdir_way ; ios_base::beg, ios_base::cur, ios_base::end


std::ofstream outfile ;

outfile.open("test.txt") ;

outfile.write("This is an apple", 16) ;

long pos = outfile.tellp() ;    // file size ; 16. ==> point <EOF>

outfile.seekp(pos-7) ;    // ==> point 'n'

outfile.write(" sam", 4) ;

outfile.close() ;    // => This is a sample












'Develop > C&CPP' 카테고리의 다른 글

thread  (0) 2018.06.09
utility  (0) 2018.06.08
functional 1 plus,minus,bind1st, bind2nd, equal_to, greater  (0) 2018.06.07
algorithm 4 merge, heap, min, max  (0) 2018.06.06
alrorigthm 3 partition, sort, search  (0) 2018.06.05
반응형

cpp functional

#include <functional>


++ operator class


++ 파라미터 바인더

+bind1st ; 함수객체를 리턴한다. 첫번째 파라미터를 지정.

ex) 10을 값으로 갖는 요소의 개수.

cnt = count_if( numbers, numbers+6,  bind1st( equal_to<int>(), 10 ) ) ;


+bind2nd ; 함수 객체를 리턴한다. 두번째 파라미터를 지정.

ex) 0보다 작은 값의 요소 개수.

cnt = count_if( numbers, numbers+6, bind2nd( less<int>(), 0 ) ) ;


++ 연산

+plus ; 두 객체를 더함.

template <class T> struct plus : binary_function <T,T,T> {

T operator() (const T&x, const T&y) const { return x+y ; }

ex) 두 컨테이너를 순서대로 요소별로 더하기

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

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

int results[5] ;

std::transform( first, first+5, second, results, std::plus<int>()) ;


+minus: 두 객체를 뺌.

상동

ex)

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

int result ;

result = std::accumulate( numbers, numbers+3, 100, std::minus<int>() ) ;

// 100 -10-20-30 = 40


+multiplies ; 두 객체를 더함.

int numbers[]={1,2,3,4,5,6,7,8,9} ;

int factorials[9] ;    // 각각의 factorial을 구함.

std::partial_sum( numbers, numbers+9, factorials, std::multiplies<int>() ) ;

// 시작값=1, 두개의 곲=2, 다음 곱=6, ...

//factorials =  1! 2! 3! 4! 5! 6! 7! 8! 9! 


+divides ; 두 객체를 나눔. first/second

// first = 10, 40, 90, 40, 10 

// second=1,2, 3, 4, 5

std::transform(first, first+5, second, second+5, results, std::divides<int>() ) ;

// results=10, 20, 30, 10, 2


+modulus ; 나눈 나머지. first%second

// numbers= 1,2,3,4,5

std::transform(numbers, numbers+5, remainders, std::bind2nd( std::modulus<int>(), 2) ) ;

// remainders = 1 0 1 0 1


+negate ; nagative   ; -1*x

std::transform(numbers, numbers+5, numbers, std::negate<int>() ) ;

// numbers 값들의 부호를 모두 바꿈.


++비교함수

+equal_to  ; 두 값이 같은 지 확인. 같으면 true, 다르면 false.

// foo = 10,20,30,40,50

// bar = 10,20,40,80,160

// 두 개를 비교하여 처음으로 다른 부분의 값을 각각 구하면

std::pair<int*,int*> ptiter = std::mismatch( foo, foo+5, bar,  std::equal_to<int>() ) ;

// *ptiter.first, *ptiter.second  = 30, 40


+not_equal_to

// 처음으로 나온 다른 값 찾기

// numbers = 10,10,10,20,20

int *pt = std::adjacent_find( numbers, numbers+5, std::not_equal<int>() ) +1 ;

// *pt = 20


+greater

// 내림차순 정렬

std::sort(numbers, numbers+5, std::greater<int>() ) ;    // prev > next


+less

// 오름차순 정렬

std::sort(numbers, numbers+5, std::less<int>() ) ;    // prev < next


+greater_equal

// 0이상인 원소의 개수

cnt = std::count_if( numbers, numbers+5, std::bind2nd(std::greater_equal<int>(), 0) ) ;


+less_equal

// 100이하인 원소의 개수

cnt = std::count_if( numbers, numbers+5, std::bind2nd(std::less_equal<int>(), 100) ) ;


++ 논리 연산

logical_and

logical_or

logical_not

ex) 

bool foo[]={true,false, true,false} ;

bool bar[]={true, true, false, false} ;

bool result[4] ;

std::transform(foo, foo+4, bar, result, std::logical_and<bool>() ) ;

// and 결과 ; true, false, false, false

std::transform(foo, foo+4, bar, result, std::logical_or<bool>() ) ;

// or 결과 ; true, true, true, false

std::transform(foo, foo+4, result, std::logical_not<bool>() ) ;

// not 결과 ; false, true, false, true



+not1  ; 결과를 not한 unary function 객체를 리턴함.

// 홀수가 아닌 원소의 개수.

struct isodd {

bool operator() (const int &x) { return i%2==1 ; }

typedef int argument_type ;

} ;

cx = std::count_if(values, values+5, std::not1(isodd()) ) ;


+not2 ; 결과를 not한 binary function 객체를 리턴함.

firstmismatch = std::mismatch( foo, foo+5, bar, std::not2( std::equal_to<int>() ) ) ;


+ptr_fun ; 함수포인터를 함수객체로 만들어 리턴해 준다.

char* foo[]={"10","20","30"} ;

int bar[3] ;

transform( foo, foo+5, bar, ptr_fun(atoi)) ;


+mem_fun ; 멤버함수를 함수객체로 만들어 리턴해 준다.

vector<string> v ; 

v.push_back( new string("one") ) ;

v.push_back( new string("three") ) ;

vector<int> lens ( v.size() ) ;

transform( v.begin(), v.end(), lens.begin(),  mem_fun( &string::length ) ) ;


+mem_fun_ref ;상동.  레퍼런스 버전.


+ref ; c++11

reference_wrapper 생성자.

객체의 적절한 참조 타입을 생성.

ex)

int foo (10) ;

auto bar = std::ref(foo) ;

bar++ ;

// foo => 11로 업데이트 된다. (참조형인 bar 변경의 영향)















'Develop > C&CPP' 카테고리의 다른 글

utility  (0) 2018.06.08
fstream 1 basic_ifstream  (0) 2018.06.07
algorithm 4 merge, heap, min, max  (0) 2018.06.06
alrorigthm 3 partition, sort, search  (0) 2018.06.05
algorithm 2 copy,swap,transform,replace,fill,generate,remove,unique,..  (0) 2018.06.04
반응형

cpp algorithm


++merge

+merge() ; 정렬된 범위를 합친다. 자동 정렬됨.

merge(first1, last1, first2, last2, result (,comp) )

std::merge( first, first+5, second, second+5, v.begin()) ;    // first와 second는 이미 sort 상태여야 함. 둘 을 합쳐 오름차순으로 v에 기록.


+includes() ; 범위 [first1, last1)내에 범위[fisrt2, last2)를 포함하는지 테스트. 둘 다 정렬된 상태여야 함.

bool includes(first1, last1, first2, last2 (,comp)) ;

+set_union ; 합집합. 두 개의 소팅된 범위를 합친다. 중복 제거.

std::sort(first, first+5) ;

std::sort(second, second+5) ;

it = std::set_union(first, first+5, second, second+5, v.begin()) ;

v.resize( it-v.begin() ) ;


+set_intersection ; 교집합. 두 개의 영역에 모두 해당되는 값들을 추출. (정렬상태)

it = std::set_intersection(first, first+5, second, second+5, v.begin()) ;

v.resize(it-v.begin()) ;


+set_difference ; 차 집합. A-B. (정렬상태)

 상동

+set_symmetric_difference ; 차이 집합 (A-B , B-A). 다른 것들로 구성

상동 




++heap ; 정렬된 컨테이너. 검색이나 추가가 빠르다.

+make_heap(first, last (,comp)) ; 요소들을 재배열한다. first가 항상 최대값이 오게 한다.

std::make_heap(v.begin(), v.end()) ;

v.front() ==> 최대값.


+push_heap() ; 요소를 힙에 푸시함. [first, last-1)이 힙인데, last의 값을 힙에 포함시킨다. [first, last) 로 구간이 확장됨.

데이터 추가시

v.push_back(99) ;

std::push_heap(v.begin(), v.end()) ;    // 마지막에 추가한 99를 힙 영역에 넣는다.

+pop_heap() ; first가 가리키는 값을 힙에서 뺀다. first의 값은 가장 뒤로 가게 되고, 힙은 재구성됨.

데이터 제거시

std::pop_heap(v.begin(), v.end()) ;

v.pop_back() ;


+sort_heap() ;오름차순으로 힙을 소팅한다.

std::sort_heap(v.begin(), v.end()) ;



++min/max

+min() ; 작은값을 찾는다.

const T & min(const T&a, const T&b) 

const T & min(const T&a, const T&b, Compare comp)

std::min(1,2) ;

std::min('a','z') ;

+max() ; 큰값을 찾는다.

상동

+min_element() ; 범위에서 최소값을 찾는다. 이터레이터 리턴 주의

iterator min_element(first, last, (comp)) ;

*std::min_element(v.begin(), v.end()) ;    // 최소값

+max_element() ; 범위에서 최대값을 찾는다.

상동


+minmax() ; c++11 , 최소값, 최대값 결과를 pair로 리턴. 리스트도 가능.

auto result = std::minmax({5,4,3,2,1}) ;

result.first => 1

result.second => 5

+minmax_element() ; c++11 ; 최소위치, 최대위치 결과를 pair로 리턴. pair의 요소는 이터레이터

auto result = std::minmax_element( foo.begin(), foo.end() ) ;

*result.first => 최소값.  *result.second=>최대값.



+lexicographical_compare(first1, last1, first2, last2 (,comp)) ; 사전식 비교

char foo[]="Apple" ;

char bar[]="apartment" ;

std::lexicographical_compare(foo, foo+5, bar, bar+9);         // => true ; foo < bar

std::lexicographical_compare(foo, foo+5, bar, bar+9, mycomp);         // => false ; foo > bar

bool mycomp(char c1, char c2) { return std::tolower(c1)<std::tolower(c2) ; }     // case-insensitive compare


+next_permutation(first, last) ; 

lexicographically 큰 다음 순열로 재배열한다.

// myints; 1 2 3

std::next_permutation(myints, myints+3) ;

// 1 3 2 로 변경. 마지막 두 개를 변경.

// 게속 permutation 반복시 

// 2 1 3 ,  2 3 1,    3 1 2,  3 2 1,    1 2 3 (처음으로 다시 환원됨). n! 개의 순열


반대 방향은 prev_permutation()





 



반응형

cpp


+is_partitioned(first, last, UnaryPredicate pred) ; c++11

범위가 나눠졌는지 확인. true/false 리턴

std::array<int, 7> foo {1,2,3,4,5,6,7} ;

std::is_partitioned(foo.begin(), foo.end(), isodd) ; // foo -> 파티션 안됨.


+partition(first, last, pred)    ; 두 개로 나눈다.

pred가 true인 그룹과 false인 그룹으로 나눈다. 순서가 바뀜.

리턴값은 두 번째 그룹의 첫번째 요소의 이터레이터.

컨테이너에서 앞에서 부터 하나씩 pred가 true인 동안 계속 다음으로 진행하고 false인 곳에서 멈춘다음, 컨테이너 뒤에서 부터 앞으로 하나씩 멈춘곳까지 진행하면서 pred가 true이면 값을 멈춘곳의 값과 바꾸고 멈춘 지점 인덱스를 증가시킨다. 

// myvec ; 1~9

std::vector<int>::iterator bound ;

bound = std::partition(myvec.begin(), myvec.end(), isodd) ;    // 홀수 그룹과 짝수그룹으로 나누고, 짝수 그룹 시작 위치를 리턴한다.

// 홀수그룹은 [myvec.begin(), bound )  ; 1 9 3 7 5

// 짝수 그룹은 [bound, myvec.end() ) ; 6 4 8 2


+stable_partition(first, last, pred) ; 두 개의 그룹으로 나누는데, 원래의 순서를 보장한다.

// 1 3 5 7 9 , 2 4 6 8


+partition_copy(first, last, result_true, result_false, pred) ; c++11

두 그룹으로 나눈다. 원본은 유지. 

std::partition_copy( foo.begin(), foo.end(), odd.begin(), even.begin(), isodd) ;


+partition_point(first, last, pred) ; 파티션 구분 이터레이터 (두 번째 그룹 시작위치)를 리턴 ; c++11

auto it = std::partition_point( foo.begin(), foo.end(), isodd) ;

odd.assign( foo.begin(), it ) ;


++ sorting

+sort ; 정렬

void sort(first, last) ;    // 디폴트 오름차순.

void sort(first, last, Compare comp) ;    // 앞, 뒤 요소가 comp 조건을 만족하도록 정렬된다. 

std::sort( myvec.begin(), myvec.begin()+4) ;    // 앞에서 4개만 소팅함. 뒤에는 그대로 유지. (오름차순 정렬,)


std::sort(myvec.begin()+4, myvec.end(), myfunc) ;    // 앞에 4개뺀 나머지를 myfunc로 정렬.

bool myfunc(int i, int j) { return (i<j); }     // 오름 차순 정렬


std::sort(myvec.begin(), myvec.end(), myobj) ;    // 전체를 myobj 객체로 정렬.

struct myclass {

bool operator()(int i, int j) { return (i<j); } // 오름차순 정렬

} myobj ;

+stable_sort() ; sort와 같다. 단, 크기가 같은 항목(==)에 대해서는 원본 순서를 보장해 준다.


+partial_sort(first, middle, last) ; 일부를 구간까지를 정렬순서를 만든다. 

[first, middle) 위치까지 오름 차순 정렬을 만드는데, 전체요소들에서 순서대로 만들어 준다.  middle위치 부터는 정렬되지 않는다.

+partial_sort_copy(first, last, result_first, result_last) ; (,comp)

result의 범위가 더 작으면 할당된 크기만큼만 복사된다.


+is_sorted() ; 정렬 여부 // c++11 

ex) //정렬될때까지 permutation 시도.

do {

std::prev_permutation( foo.begin(), foo.end() ) ;

for (int&x :foo) std::cout << ' ' <<x ;

std::cout << '\n' ;

} while ( !std::is_sorted(foo.begin(), foo.end()) ) ;


+ is_sorted_until() ; // c++11

처음 발견된 비정렬 데이터의 위치를 리턴

it = std::is_sorted_until( foo.begin(), foo.end() ) ;

// foo ; 2 3 4 1 ; it = point 1.  it-foo.begin() => 3(index) ; 3개까지 유효한 정렬임.


+nth_element() ; 오름차순 정렬시 index n번의 요소를 기준으로 좌(low) 우(over)로 나눈다. 순서보장 안 됨.

// myvec; 0~9 까지 랜덤한 순서로 있을 때.

std::nth_element(myvec.begin(), myvec.begin()+5, myvec.end() ) ;

// 숫자 5 (오름차순 정렬시 인덱스 5번)를 기준으로 작은 값, 큰 값으로 구분하여 정렬된다. (작은 값, 큰 값 내부는 정렬이 안된다.)


++ binary search

+lower_bound() ; lower bound를 리턴한다. [first, last) 범위내에서 val보다 작지 않은 첫번째 위치를 리턴. 

+upper_bound() ; upper bound ; [first, last)범위내에서 val보다 큰 첫번째 위치.

즉, val값에 해당되는 영역의 [시작,끝) 위치를 찾는다. 

// myvec ; 10 10 10 20 20 20 30 30 

std::vector<int>::iterator low,up ;

low = std::lower_bound(myvec.begin(), myvec.end(), 20) ;    // 3

up = std::upper_bound(myvec.begin(), myvec.end(), 20) ;    // 6

// 따라서 20에 해당되는 영역은 [3, 6) 가 된다. 

3번재 파라미터로 Compare 함수를 주어 비교루틴을 적용할 수도 있다.! (특정 값이 아닌 특정범위에 해당되는 영역 검색)


+equal_range() ; 특정 값의 영역을 가져온다. 리턴결과는 범위 pair<iterator, iterator>

equal_range(first, last, val) ;

equal_range(first, last, val, comp) ;


std::pair<std::vector<int>::iterator, std::vector<int>::iterator> bounds ;

bounds = std::equal_range( v.begin(), v.end(), 20) ; // lower, upper bound를 리턴한다.

bounds.first, bounds.second


+binary_search(); 정렬된 컨테이너에서 값이 존재하는지 테스트한다. true/false

std::binary_search(v.begin(), v.end(), 3) ;    // 3이 존재하면 true
















반응형

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를 사용한다.

















반응형

cpp algorithm 1

include <algorithm>


+ test ; C++11

all_of() ; 모두 성공인지 테스트

any_of() ; 하나라도 성공인지 테스트

none_of() ; 모두 실패인지 테스트.

ex)

std::array<int, 8> foo = {3,5,7,11,13,17,19,23} ;

if ( std::all_of( foo.begin(), foo.end(), [](int i){ return i%2 ;} ) )

std::cout << " all the elements are odd numbers.\n" ;

std::array<int, 7> foo={0, 1, -1, 3, -3, 5, -5} ;

if ( std::any_of(foo.begin(), foo.end(), [](int i) { return i<0 ; }) )

std::cout << "there are negative elements.\n" ;

if ( std::none_of(foo.begin(), foo.end() [](int i) { return i<0 ; } ) )

std::cout << "there are no negative elements.\n" ;


+for_each ; 모든 엘리먼트에 함수 적용.

void myfunction(int i) { std::cout << i << ' '; } 

struct myclass { 

void operator() (int i) {std::cout << i << ' ';}

} myobj ;

std::vector<int> myvec ;

myvec.push_back(1) ;

myvec.push_back(2) ;

myvec.push_back(3) ;


for_each( myvec.begin(), myvec.end(), myfunction) ;

for_each( myvec.begin(), myvec.end(),  myobj) ;


+find ; 엘리먼트 값 찾기
찾아서 이터레이터 리턴. 없으면 last.return
ex) 3의 위치 찾기. 
int myints[]={1,2,3,4} ;
int *p ;
p  = std::find (myints, myints+4, 3) ;
if ( p!=myints+4 )    std::cout << "found : " << *p << '\n' ;
else  std::cout << "not found\n" ;

std::vector<int> myvec(myints, myints+4) ;
std::vector<int>::iterator it ;
it = find( myvec.begin(), myvec.end(), 3) ;
if ( it!=myvec.end() ) std::cout << "found:" << *it << '\n' ;
else std::cout << "not found\n" ;


+find_if ; 조건을 만족하는 처음 위치 찾기 (엘리먼트별)
bool isOdd(int i) { return ( (i%2)==1 ) ; }
ex) 처음 나온 홀수 찾기 
it = std::find_if( myvec.begin(), myvec.end(), isOdd) ;
if ( it!=myvec.end() ) std::cout << "the first odd value is " << *it << '\n';
else std::cout << "not found\n" ;

조건을 반대로 쓰려면 find_if_not(C++11) 사용.



+find_end ; 조건을 만족하는 마지막 위치 찾기 ( 그룹별)
ex) 1,2,3,4,5,1,2,3,4,5 에서 1,2,3 시퀀스를 만족하는 마지막 발견 위치 찾기
int myints[]={1,2,3,4,5,1,2,3,4,5} ;
std::vector<int> myvec (myints, myints+10) ;
int needle[] = {1,2,3} ;

it = std::find_end( myvec.begin(), myvec.end(),  needle, needle+3 ) ;
=> it는 2번째 나온 1을 가리킴.
index는  it - myvec.begin() ;

it = std::find_end( myvec.begin(), myvec.end(),  needle, needle+3, myfunction ) ;

bool myfunction(int i, int j) { return i==j ; } 

+find_first_of ; 조건을 만족하는 처음 위치 찾기 ( 그룹별)
ex) 1,2,3이 처음 나온 곳 찾기.
it = find_first_of( myvec.begin(), myvec.end(), needle, needle+3) ;
it = find_first_of( myvec.begin(), myvec.end(), needle, needle+3, myfunction) ;
bool myfunction(char c1, char c2) {  return (std::tolower(c1)==std::tolower(c2)) ; }    // case-insensitive compare.

+adjacent_find ; 처음으로 조건을 만족하는 위치 찾기. (2개씩 그룹으로 자체 비교)
ex) 처음으로  연속된 값이 2개 나오는 곳 찾기
int myints[]={5,20,5,30,30,20,10,10,20} ;
std::vector<int> myvec(myints, myints+9) ;
it = std::adjacent_find( myvec.begin(), myvec.end()) ;
// *it 의 값은 30
it = std::adjacent_find( ", ", myfunction) ;    // 조건을 별도로 설정 가능.
bool myfunction (int i, int j) { return i==i; }


+count ; 특정값의 엘리먼트 개수 세기
int mycount = std::count(myints, myints+8, 10) ;    // 원소값이 10인 것 개수 세기.
mycount = std::count(myvec.begin(), myvec.end(), 20) ;    // 원소값이 20인 것 개수 세기.

+count_if ; 조건에 맞는 엘리먼트 수 세기
// 홀수 개수 세기
mycount = std::count_if(myvec.begin(), myvec.end(), isOdd) ;


+mismatch ; 두 컨테이너의 값을 비교하여 처음으로 틀린 곳 찾기
std::pair<std::vector<int>::iterator,  int*> mypair ;
mypair = std::mismatch( myvec.begin(), myvec.end(),  myints ) ;
// *mypair.first => 처음 틀린 myvec의 원소값.,    *mypair.second  => 처음 틀린 myints의 원소값. 
mypair.first++;  mypair.second++ ;    // 찾은 곳 다음 위치로 이동.
mypair = std::mismatch( mypair.first, myvec.end(),  mypair.second, mypredict ) ;
//  찾은 곳 다음부터 비교함수를 통해 언매치된 곳을 또 찾음.


+equal ; 두 컨테이너의 값이 일치하는지 테스트. (범위 지정 가능)
std::equal( myvec.begin(), myvec.end(), myints)    ==> true/false 리턴, myints 대신 myvec2.begin() 이렇게도 가능.
std::equal( myvec.begin(), myvec.end(), myints, mypredict)      // 비교함수 지정.


+is_permutation ; 순서가 달라도 범위내에 모든 엘리먼트들이 매치하는지 검사 (C++11)
std::array<int, 5> foo={1,2,3,4,5} ;
std::array<int, 5> bar={3,1,4,5,2} ;
if ( std::is_permutation(foo.begin(), foo.end(), bar.begin()) )
std::cout << "foo and bar contain the same elements.\n" ;


+search ; 일부분을 찾음. 스트링으로 치면 find로 일부분 찾기.

it = std::search(myvec.begin(), myvec.end(), needle1, needle1+4) ;
// it는 needle1이 myvec에 있는 첫번째 지점 시작위치를 가리킴. 없으면 myvec.end() 위치를 가리킴. 인덱스는 it-myvec.begin()
ex) 1,2,3,4,5 에서 2,3을 찾기

+search_n ; n개의 같은 값을 찾음. (시작,끝, 반복횟수, 값)

it = std::search_n(myvec.begin(), myvec.end(), 2, 30) ;    // 30,30 이렇게 두 개 가 있는 곳을 찾음.
ex), 10, 20, 30,30,40,50,50 에서 30,03찾기.














반응형

cpp numeric


#include <numeric>


+accumulate ;  범위의 값들을 축적( 디폴트는 합)한다. 현재 계산된 값(처음은 초기값)에 요소의 값을 연산하는 것을 모든 요소에 대하여 순차적으로 수행.

; 현재결과 operation(+,..) 각각의 요소  => 하나의 값 출력

T accumulate(first, last, T init  (,binary_op) ) ;    // init=초기값. binary_op=요소별 축적 작업

ex) 초기값 100에 {10,20,30}을 모두 더함.

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

std::accumulate( numbers, numbers+3, 100) ;    // = 160


std::accumulate( numbers, numbers+3, 100, std::minus<int>() ) ;

// 100-10-20-30 = 40


std::accumulate( numbers, numbers+3, 100, myfunc) ;

int myfunc(intx, int y) { return x+ 2*y ; }

// 100+10*2+20*2+30*2 = 220


std::accumulate( numbers, numbers+3, 100, myobj) ;

struct myclass {

int operator() (int x, int y) { return x+ 3*y ; }

} myobj ;

// 100+3*10+3*20+3*30 = 280


+ adjacent_difference ; 옆에 있는 요소와의 차이. 차이를 구하는 함수 별도 설정가능

; 앞의 요소 operation 각각의 요소  => 요소 개수 크기의 리스트.

adjacent_difference ( first, last, result  (,binary_op) ) ;  범위, 저장, ( diff로 쓸 함수 )

ex) // val = 1,2,3,5,9,11,12 

int result[7] ;

std::adjacent_difference( val, val+7, result) ;

// result =>  (시작값)1, 1 1 2 4 2 1     // 자신의 값 - 앞의 값.

std::adjacent_difference( val, val+7, result, std::multiplies<int>() ) ;

// result => (시작값)1 2 6 15 45 99 132    // 앞의 값과 자신의 값을 곱함.


+ inner_product ; 두 벡터의 내적을 구함.

두 벡터의 요소들간에 곱한 것들을 더함.

T inner_product(first1, last1, fist2, T init) ;    // init;초기값

뒤에 추가 파라미터로 binary_op1, binary_op2 가 올 수 있음. 

// 연산은  binary_op1 ( init,  binary_op2 (*first1, *first2) ) 이렇게 반복됨.

// 디폴트는 op2= multiply,  op1 = plus

ex)

s1 = 10,20,30

s2 = 1,2,3

std::inner_product(s1, s1+3, s2, 1000) ;        // 내적을 구함 => 140, 초기값을 합침 = 1140

// 1140


+partial_sum ; 부분 합. 합말고 곱이나 다른 함수 사용 가능.

단계별로 accumulate한 것을  list 로 만든다.

ex)

// val = 1,2,3,4,5

std::partial_sum(val, val+5, result) ;

//result= 1 3 6 10 15


std::partial_sum(val, val+5, result, std::multiplies<int>() ) ;    // 작업함수 변경

// result= 1 2 6 24 120



+iota ; c++11 스펠링주의. itoa가 아님.

연속적인 값들을 범위를 할당.

즉, 지정된 범위에 1,2,3,4... 이렇게 증가되는 값을 할당.

int numbers[10] ;

std::iota(numbers, numbers+10, 100) ;

// numbers => 100 101 102 103 ... 109    ; 100부터 1씩 증가된 값을 할당한다.















'Develop > C&CPP' 카테고리의 다른 글

algorithm 2 copy,swap,transform,replace,fill,generate,remove,unique,..  (0) 2018.06.04
algorithm 1. test, find, count, search, foreach  (0) 2018.06.01
string function  (0) 2018.05.31
string  (0) 2018.05.30
map  (0) 2018.05.29

+ Recent posts