요즘은 ATL에서 CString을 지원하면서 std::string을 사용할 일이 줄어들긴 했지만, 여전히 유용한 클래스임에는 틀림없다.

가끔 MFC등 윈도용으로 개발된 클래스를 포팅해야 할 때 제일 문제가 되는 것 중에 하나가 CString이기도 한데 -_-
여튼. std::string에서 아쉬운 부분중에 하나인 ReplaceAll 함수를 간단히 구현해 보자.

   

#include <string>

 

typedef std::basic_string<TCHAR> _tstring;

 

_tstring replace_all( const _tstring& source, const _tstring& pattern, const _tstring& replace )

{

_tstring result = source;

_tstring::size_type pos = 0;

_tstring::size_type offset = 0;

_tstring::size_type pattern_len = pattern.size();

_tstring::size_type replace_len = replace.size();

 

while ( ( pos = result.find( pattern, offset ) ) != _tstring::npos )

{

result.replace( result.begin() + pos, result.begin() + pos + pattern_len, replace );

offset = pos + replace_len;

}

return result;

}

 

출처 : http://blog.daum.net/studiocoma/6800925

블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소

댓글을 달아 주세요

 map과 multimap은 '연관 컨테이너'입니다. 모든 연관 컨테이너(set, multiset, map, multimap)는 '노드 기반 컨테이너'입니다. 또 모든 연관 컨테이너는 균형 2진 트리로 구현됩니다. 균형 2진 트리는 보통 레드-블랙 트리를 사용합니다. map은 key와 value의 쌍으로 구성된 데이터 셋의 집합입니다. 여기서 key는 유니크합니다. multiset도 map과 같이 key와 value의 쌍으로 구성된 데이터 셋의 집합입니다. 단, multiset은 map과 달리 중복된 key가 존재할 수 있습니다.

 

map의 주요 개념을 그림으로 표현하면

map_개념.png 

set과 map은 데이터의 key가 유니크합니다.

 

multiset의 주요 개념을 그림으로 표현하면

multimap_개념.png 

multiset과 multimap은 같은 key값의 데이터를 컨테이너에 저장할 수 있습니다.

 

map, multimap의 주요 특징과 함수

 map도 set처럼 데이터를 추가하는 push_? 류의 함수를 가지고 있지 않습니다. 삽입(insert)한다는 의미에서 insert() 함수를 가지고 있습니다.

map의 특징은 key와 value의 쌍으로 데이터를 저장합니다. 그리고 key값을 이용하여 빠르게 value값을 찾을 수 있습니다. 연관 컨테이너에서 유일하게 [] 연산자 중복을 제공합니다.

 

기본적인 map 예제

#include <iostream>
#include <map>
using namespace std;
void main( )
{
    map<int , int > m;

    m[5] = 100;
    m[3] = 50;
    m[7] = 80;
    m[2] = 100;
    m[4] = 100;

    cout << m[5] << endl;
    cout << m[3] << endl;
    cout << m[7] << endl;
    cout << m[2] << endl;
    cout << m[4] << endl;
}
  1. 100
    50
    80
    100
    100

map은 key와 value의 쌍으로 구성된 데이터들의 집합입니다. []연산자의 인덱스는 key이며 인덱스가 가리키는 메모리 값이 value입니다.

주의할 점은 m[5] = 100 연산에서 5라는 key가 없으면 노드 '추가'가되며 5라는 key가 있으면 '갱신'이 됩니다. 아래에서 공부합니다.

그림으로 설명하면..

map_간단_코드.png

map의 트리 그림입니다.

map_데이터_추가.png 

map의 key값 5로 value를 접근하는 그림입니다.

map_데이터_접근.png 

 

 map은 key와 value의 쌍을 pair 객체로 저장합니다. STL의 쌍을 이루는 모든 요소는 pair 객체를 사용합니다.

위 예제는 insert()함수를 사용하여 아래 예제로 바꿀 수 있습니다.

#include <iostream>
#include <map>
using namespace std;
void main( )
{
    map<int , int > m;

    m.insert( pair<int,int>( 5, 100) );
    m.insert( pair<int,int>( 3, 50) );
    m.insert( pair<int,int>( 7, 80) );
    m.insert( pair<int,int>( 2, 100) );
    pair<int,int> pr( 4, 100);
    m.insert( pr );

    cout << m[5] << endl;
    cout << m[3] << endl;
    cout << m[7] << endl;
    cout << m[2] << endl;
    cout << m[4] << endl;
}

  1. 100
    50
    80
    100
    100

 map은 key, value를 pair 객체로 각각 first와 second에 저장합니다.

그림으로 표현하면

map_pair_객체.png 

 

 

반복자를 사용한 모든 key, value 출력 예제

#include <iostream>
#include <map>
using namespace std;

void main( )
{
    map<int , int > m;

    m[5] = 100;
    m[3] = 50;
    m[7] = 80;
    m[2] = 100;
    m[4] = 100;

    map<int, int>::iterator iter;
    for( iter = m.begin(); iter != m.end() ; iter++)
        cout << "m["<<(*iter).first <<"]: " << (*iter).second << endl;

    cout << "==============" << endl;
    for( iter = m.begin(); iter != m.end() ; iter++)
        cout << "m["<<iter->first <<"]: " << iter->second << endl;
}
  1. m[2]: 100
    m[3]: 50
    m[4]: 100
    m[5]: 100
    m[7]: 80
    ==============
    m[2]: 100
    m[3]: 50
    m[4]: 100
    m[5]: 100
    m[7]: 80

 map도 양방향 반복자를 제공합니다.

그림으로 간단하게..

 map_반복자.png

 

 

연관 컨테이너는 모두 동일한 함수군을 가지며 동작 방식도 같습니다.

map의 검색 함수들입니다.

#include <iostream>
#include <map>
using namespace std;

void main( )
{
    map<int , int > m;

    m[5] = 100;
    m[3] = 50;
    m[7] = 80;
    m[2] = 100;
    m[4] = 100;

    map<int, int >::iterator iter;

    iter = m.find( 5 );
    if( iter == m.end() )
        cout << "없음!" << endl;
    else
        cout << "m["<<iter->first <<"]: " << iter->second << endl;

    iter = m.lower_bound( 5 );
    if( iter == m.end() )
        cout << "없음!" << endl;
    else
        cout << "m["<<iter->first <<"]: " << iter->second << endl;

    iter = m.upper_bound( 5 );
    if( iter == m.end() )
        cout << "없음!" << endl;
    else
        cout << "m["<<iter->first <<"]: " << iter->second << endl;

    pair< map<int, int>::iterator, map<int, int>::iterator> iter_pair;
    iter_pair = m.equal_range(5);

    if( (iter_pair.first) == m.end() && (iter_pair.second == m.end()) )
        cout << "없음!" << endl;
    else
    {
        cout << "m["<< iter_pair.first->first <<"]: " << iter_pair.first->second <<" ~ ";
        cout << "m["<< iter_pair.second->first <<"]: " << iter_pair.second->second <<endl;
    }
}
  1. m[5]: 100
    m[5]: 100
    m[7]: 80
    m[5]: 100 ~ m[7]: 80

 동작은 set에서 설명했으므로 패스~!

그림으로 설명하면...

map_검색_함수.png 

 

 

 

마지막으로 multimap 예제입니다.

map과 다른 점은 [] 연산자가 없으며 key 값이 중복될 수 있습니다.

#include <iostream>
#include <map>
using namespace std;

void main( )
{
    multimap<int , int > m;

    m.insert( pair<int,int>( 5, 100) );
    m.insert( pair<int,int>( 3, 50) );
    m.insert( pair<int,int>( 7, 80) );
    m.insert( pair<int,int>( 2, 100) );
    m.insert( pair<int,int>( 4, 100) );
    m.insert( pair<int,int>( 7, 200) );
    m.insert( pair<int,int>( 7, 300) );

    pair<multimap<int,int>::iterator, multimap<int, int>::iterator > iter_pair;
    iter_pair = m.equal_range( 7 );
    multimap<int,int>::iterator iter;
    for( iter = iter_pair.first ; iter != iter_pair.second ; iter++)
        cout << "m["<< iter->first <<"]: " << iter->second <<' ';
    cout << endl;

}
  1. m[7]: 80 m[7]: 200 m[7]: 300

 설명은 multiset과 같습니다.

아래는 위 예제의 그림입니다.

multimap_equal_range(1).png  

 

 

 

여기까지 STL의 컨테이너를 마무리합니다.

C++ 표준에 추가된 해쉬 컨테이너는 다음에 공부합니다. 

출처 : http://coolprogramming.springnote.com/pages/4826369

 

최근엔 hesh_map 등이 더 인기가 있는거 같은..

쓰기에는 map 과 같은 인터페이스에 using namespase std 가 아닌 stdext 를 쓴다

자세한 레퍼렌스는 http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(HASH_MAP);k(DevLang-%22C%2B%2B%22);k(TargetOS-WINDOWS)&rd=true 를 참고하자

블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소

댓글을 달아 주세요


실전 STL 플밍.. 소스 참고..
블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소

댓글을 달아 주세요

블로그 > 박후의 블로그
원본 http://blog.naver.com/parkhooman/90006821404

데브피아의  윤용한 / yonghany 님의 STL 강좌를 퍼 담았습니다.

님두 어떤 원서를 기초로 해서 쓰신건데 STL 기초에 도움이 많이 될것 같네요.


블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소

Tag 강좌

댓글을 달아 주세요

//////////////// 파일의 모든 내용 읽고 출력 //////////////// p161
//cout를 위해, ifstream을 위해, vector를 위해, string을 위해, for_each를 위해 각각 해더 추가

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>

//for_each에서 string출력에 사용할 단항 함수 정의
void print_str(const std::string &str)
{
 std::cout << str << std::endl;
}

...

using namespace std;

ifstream file("test.txt");
if(!file)
{
 cerr << "Can't open file " << enld;
 exit(0);
}

// file로부터 문자열을 읽으면서 vector에 저장
vector<string> strlist;
string temp;
while(file >> temp)
{
 strlist.pushback(temp);
}
file.close();

// vector에 담긴 모든 string을 출력
for_each(strlist.begin(), strlist.end(), print_str);


//////////////// 파일 복사 //////////////// p140
#include <iostream>
#include <fstream>
#include <string>

int main(int argc, char *argv[])
{
 using namespace std;

 if(argc != 3) return 1;

 string file1(argv[1]), file2(argv[2]);
 ifstream in(file1.c_str(), ios_base::binary); // 복사할 파일 바이너리로 읽고
 ofstream out(file2.c_str(), iso_base::binary); // 복사본 파일 바이너리로 쓸준비

 out << in.rdbuf();  // 여기서 복사 진행

 return 0;
}

//////////////// 조건이 맞으면 출력 //////////////// p141
#include <iostream>
#include <fstream>
#include <string>

template<typename t>
void if_cond_is_true_write_rst(
 std::string filename,
 std::streampos cond_pos, t cond,
 std::streampos target_pos, t rst)
{
 using namespace std;
 
 // 읽기 쓰기 가능하게 파일을 연다
 fstream file(filename.c_str(), ios_base::in | ios_base::out);

 // 지정된 위치로 cond_pos 이동
 file.seekg(cond_pos);

 t real;
 file.read(&real, sizeof real);

 if(real == cond)
 {
  file.seekg(target_pos);
  file.write(&rst, sizeof rst);
 }
}
... 중략 (main 함수 등)
if_cond_is_true_rst("cond.txt", 10, 'J', 0, '-');

//////////////// 파일 크기 출력 //////////////// p144
#include <iostream>
#include <fstream>
#include <iterator>
#include <limits>

...
using namespace std;
string filename;
...

// 파일을 열고 맨 끝으로 옮긴다. (ate는 파일을 열자마다 EOF로 가게 한다)
ifstream in1(filename.c_str(), ios_base::ate);
streampos end = in1.tellg();  // EOF인 현재 위치를 받아온다
cout << "Size : " << end << endl; // 출력
in1.close();

ifstream in2(filename.c_str(), ios_base::binary);
// 파일 크기 계산
streamsize size = distance(istreambuf_iterator<char>(in2),
 istreambuf_iterator<char>());
cout << "Size : " << size << endl;
in2.close();

//////////////// 정렬 문제 //////////////// p149
//영수증 출력 문제

#include <iostream>
#include <iomainp>
#include <string>

using namespace std;

struct item{ char name[32]; int price; int num;};

void print_title(
 const string &kind, const string &price, const string &number)
{
 cout << setw(15) << kind << setw(10) << price <<setw(10) << number << endl;
}

void print_item(const item & item)
{
 cout << setw(15) << item.name << setw(8) << item.price << "원"
  << setw(8) << item.num << "개" << endl;
}

void print_total(int price)
{
 cout << setw(33) << price << "원" << endl;
}

...
item itmes[3] = {
 {"가나초콜릿", 900, 1}, { "파워에이드", 900, 1}, {"감자깡",450,2}
};

print_title("종류", "가격", "수량");
int price(0);
for(size_t i(0); i < sizeof items / sizeof (item); i++)
{
 print_item(items[i]);
 price += items[i].num * items[i].price;
}
print_total(price);


블로그 이미지

프로그래머 지향자 RosaGigantea

바쁜 일상 생활중의 기억 장소

댓글을 달아 주세요