Eat Study Love

먹고 공부하고 사랑하라

SW 만학도/C++

3. C++ Standard Library (3)

eatplaylove 2024. 3. 24. 16:46

https://eglife.tistory.com/35

 

2. C++ Standard Library (2)

https://eglife.tistory.com/34 1. C++ Standard Library (1) 아 ~ 이게 무슨 영어, 중국어 배우는 것도 아니고 코딩하나 하는데도 프로그래밍 언어가 너무 많다;; 이거 누가 통일 좀 안 시키나ㅠㅠ 그래도 써먹을

eglife.tistory.com

 

 

요번엔 Vector의 Container를 다뤄보려고 한다.

 

문자 그대로 Container, 뭔가 Data를 담는 구조? 의 종류를 알아보는 것!

 

Vector

 

- Vector는 연속된 컨테이너로, dynamic-size array이고 Python의 List와 유사하다.

 

- Data들은 연속된 메모리에 저장된다.

 

- Random Access를 지원한다. ( Direct access by index )

 

- 끝으머리에 data Insertion / Deletion 지원한다.

 

- Element가 추가되면서 Resize는 자동으로 한다.

 

 

 

- Vector는 기본적으로 begin / end / size / capacity 정보를 갖고 있다.

 

Vector - Initialization

 

- <vector> header 파일이 필요하다.

 

- vector 안에 data에 대해선 type을 명확히 해줘야 한다. 그리고 python List와는 달리 vector는 오직 한 종류의 data를 가질 수 있다.

 

#include <iostream>
#include <vector>

int main(void)
{
    //Direct vector initialization
    std::vector<int> vec1 = {1,3,5,7,2};

    //From an array
    int arr[] = {9,10,11,8};
    std::vector<int> vec2(std::begin(arr),std::end(arr));

    //With a specific size and value
    std::vector<int> vec3(5,10);

    std::cout<<vec1.at(3)<<std::endl;
    std::cout<<vec2.at(3)<<std::endl;
    std::cout<<vec3.at(3)<<std::endl;
// 7
// 8
// 10
    return 0;
}

 

 

- vec3(5,10) 의 경우 size 5를 10으로 채워야 해서 {10, 10, 10, 10, 10} 꼴로 vector가 만들어진다.

 

Vector - Insertion

 

 

- push_back / insert method를 이용하면 된다. 문자 그대로 push back! 뒤에서 Element하나씩 툭툭!

 

#include <iostream>
#include <vector>
int main(void)
{
using namespace std;
    
    vector<int> vec1;

    //add by push back
    vec1.push_back(11);
    vec1.push_back(22);
    vec1.push_back(11);

    //print

    cout << vec1.at(0)<< vec1.at(1)<< vec1.at(2) << endl;
    //112211
    return 0;
}

 

 

Vector - Deletion

 

- pop_back / erase method로 element를 지울 수 있다.

 

#include <iostream>
#include <vector>

int main(void)
{   
    std::vector<int> vec1 = {1,2,3,4};

    // 마지막 element를 뺍시다
    vec1.pop_back();

    std::vector<int> vec2 = {1,2,3,4};
    // 3번 째 element를 빼라
    vec2.erase(vec2.begin()+2);

    return 0;
}

 

 

- vec2.begin()은 첫 번째 element에 iterator를 의미한다. iterator가 무엇이냐? 그건 아래에 계속..

 

알아두면 좋은 vector 관련 Method

 

Iteration - Range - Based for Loops

 

- C++11 에선 range-based for loops를 지원한다.

 

- for ( declaration : range ) statements;  -->  for ~ in ~ 요런 Python 구문과 유사하다.

 

- 중간에 auto 라는게 쓰이는데, 이것은 data type을 적절하게 알아서 매칭해주는 Key다. 유용!

 

#include <iostream>
#include <vector>

int main(void)
{
    std::vector<int> num = {5,4,1};

    for(int val : num)
    {
        std::cout << val << std::endl;
    } 
    for(auto val : num)
    {
        std::cout << val << std::endl;
    } 
// 5
// 4
// 1
// 5
// 4
// 1
    return 0;
}

 

 

 - 이번엔 iterator를 이용해서 vector iteration을 돌려보자

 

#include <iostream>
#include <vector>

int main(void)
{
    std::vector<int> vec = {3,1,2};
// using iterator

for(std::vector<int>::iterator iter = vec.begin();iter !=vec.end(); ++iter)
{
    std::cout << *iter << std::endl;
}
// 3
// 1
// 2
return 0;
}

 

Iterator

 

 

 

- C++ iterator는 C에서 pointer와 비슷한 역할을 한다. --> container에 접근하고, 메모리를 돌아댕길 수 있게 해 줌

 

- Container마다 iterator type은 명확히 해서 선언해줘야 한다.

 

- Vector의 경우 begin() / end() method로 iterator의 포인팅을 지정해 줄 수 있는데,

 --> begin의 경우 첫 번째 element 위치를 가르키고, end의 경우 마지막 + 1 번 째 element 위치를 가르킨다.

 

- 위 vector delete에서 봤던 erase 함수 활용의 경우, iterator를 사용한 case!

 

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> vec = {1,2,3,4};
    vec.erase(vec.begin()+1);
    // index 1에 해당하는(여기선 값 2) 부분 제거

    std::cout << vec.at(1);
    //3

}

 

Finding Elements

 

- std::find function으로 element를 찾을 수 있다. 

 

- find 함수는 찾으려는 element의 위치를 포인팅하고 있는 iterator를 반환한다.

 

- std::distance의 경우 element 위치의 offset을 반환해줘서 index를 계산할 수 있게 해준다.

 

int main()
{
    std::vector<int> vec = {4,3,1,2};
    // 2 라는 놈 위치를 찾아보자

    std::vector<int>::iterator iter = std::find(vec.begin(),vec.end(),2);

    if( iter != vec.end())
    {
        std::cout<<"find it:"<<std::distance(vec.begin(),iter) << std::endl; //DISTANCE!로 index계산이용!!
    }
    // find it:3
    else
    {
        std::cout << "No data" <<std::endl;
    }
return 0;

}

 


 

와나 .. Accumulate / list 에 대해서 쓰고 있었는데 글이 날라 갔다..

 

아 다시 쓰긴 구찮고, 코드 적어놨던 걸로 대체

 

ㅡㅡ 아 짜증나

 

int main(void)
{
    std::vector<int> vec = {3,6,9,12};

    // SUM all elements in the vector
    
    int sum = std::accumulate(vec.begin(),vec.end(),0);
    // 초기 seed 값 0이면 SUM 구할 때 0을 더함,
    // 그 외 Calculation이 하고 싶으면 원하는 custom 함수를 만들고 4번 째 인자로 추가

    std::cout << "sum : " << sum << std::endl;
    // sum : 30

    return 0;
}

 

- Accumulate는 container 안에 element들을 다 더해주는 함수인데, #include <numeric> header파일이 필요하다.

 

List

 

 

- list는 vector와 달리 non-contigious memory allocation을 지원하며 역시 #include <list>가 필요하다.

 

- Element 삽입/제거가 어느 포인트에서나 가능고 random access는 지원하지 않는다.(Python의 deque 구조란다)

 

int main()
{
    // Default Initialization ( empty list )
    std::list<std::string> list1;

    // Direct Initialization
    std::list<std::string> list2 =
    {"DATA","SCIENTIST","YEAH"};

    // Initialize with a specific number of elements with a specific value

    std::list<std::string> list3(5,"Hi");
    
    for(auto str : list1)
    {
        std::cout << str << std::endl;
    }

    return 0;
#include <string>

int main()
{
    std::list<int> list1 = {5,3,1,2,4};

    list1.push_back(6);
    list1.push_front(0);
    //0,5,3,1,2,4,6

    auto it = list1.begin();
    std::advance(it,4);
    list1.insert(it,9);
    //0,5,3,1,9,2,4,6

    std::advance(it,-4);
    list1.erase(it);
    //5,3,1,9,2,4,6

    list1.pop_back();
    //5,3,1,9,2,4
    list1.pop_front();
    //3,1,9,2,4

    return 0;
}

 

 

- list의 iteration은 forward / backward interaor를 사용한다.

 

#include <iostream>
#include <list>

int main()
{
    using namespace std;
    list<int> lst = {5,3,1,2,4};

    //Forward iteration
    for(auto it = lst.begin();it!=lst.end();++it)
    {
        cout << *it << " ";
    }

    cout << endl;

    //5 3 1 2 4 

    // //Reverse iteration
    for(auto rit = lst.rbegin();rit!=lst.rend();++rit)
    {
        cout << *rit << " ";
    }
    // //4 2 1 3 5

}

 

여기까지가 날라간 부분이고 ㅜㅜ 다시 정신차리고 공부 시작

 

list - Iteration

 

- list에서 end()는 마지막 element + 1 위치를 가르키고, rend()는 맨 처음 element - 1 위치를 가르킨다.

 

- 개념적으로 보면 맨 처음과 끝을 이어주는 Sentinel이 있다고 보면 되는데, 이는 C++ Implementation 시스템에 따라 다르므로 무조건 옳다고 말할 순 없다.

 

 

 

 

list - Memory

 

- list memory 주소 찍어보기

 

#include <iostream>
#include <set>
#include <list>
using namespace std;
int main()
{   
    std::list<int> lst = {3,2,5,1};

    for(std::list<int>::iterator it = lst.begin();
    it != lst.end();++it)
    {
        std::cout << &(*it) << " ";
    }
    std::cout << &(*lst.end()) << std::endl;
    std::cout << &(*lst.begin());
    // 0xfa6b50 0xfa6b70 0xfa6b90 0xfa6bb0 0x61fdd0
    // 0xfa6b50
}

 

using namespace std;
int main()
{   
    std::list<int> lst = {3,2,5,1};

    for(std::list<int>::reverse_iterator rit = lst.rbegin();
    rit != lst.rend();++rit)
    {
        std::cout << &(*rit) << " ";
    }
        std::cout << &(*lst.rbegin())<<std::endl;;
        std::cout << &(*lst.rend());

    // 0x736bb0 0x736b90 0x736b70 0x736b50 0x736bb0
    // 0x61fdd0

}
#include <iostream>
#include <set>
#include <list>
using namespace std;
int main()
{   
    std::list<int> lst = {3,2,5,1};

    for(std::list<int>::iterator it = lst.begin();
    it != lst.end();++it)
    {
        std::cout << &(*it) << " ";
    }
    std::cout << &(*lst.end()) << std::endl;
    std::cout << &(*lst.begin()) << std::endl;

    for(std::list<int>::reverse_iterator rit = lst.rbegin();
    rit != lst.rend();++rit)
    {
        std::cout << &(*rit) << " ";
    }
        std::cout << &(*lst.rbegin())<<std::endl;;
        std::cout << &(*lst.rend());
// 0xf76b50 0xf76b70 0xf76b90 0xf76bb0 0x61fdb0
// 0xf76b50
// 0xf76bb0 0xf76b90 0xf76b70 0xf76b50 0xf76bb0
// 0x61fdb0
}

 

- forward iterator에서 lst.end()의 주소 값과, backward에서 lst.rend()의 주소값이 같은 것으로 보아 list는 sentinel로 순환구조를 가질 수 있다는 추정가능 ( C++ 작업환경에 따라 달라질 수 있는 내용이므로 확실시는 X )

 

도움이 될만한 list method

 

 

map

 

- Map은 key - value 꼴로 element들을 저장하는 container다.

 

- Map에서 key는 unique value이고 sort / identify 할 때 사용되며 value는 중복된 값을 가져도 된다.

 

- Default로, map에 있는 element들은 key의 오름차순으로 정렬된다.(hash table과 다른점)

 

map의 구조

 

 

TREE 모양

 

- Node는 std::pair object이고 key 와 value를 각각 first , second attribute으로 갖는다.

 

- Binary Search / Balanced Tree 이다. --> Time complexity를 계산 시 O(log(n))의 구조를 갖는다.

 

 

map - Initialization

 

- #include <map> header 필요

 

- Key와 value의 Data type이 명확히 선언되어야 한다.

 

#include <iostream>
#include <map>
#include <string>

int main()
{
    // Initialization an empty map

    std::map<std::string , int> map1;

    // Using an initializer list

    std::map<std::string, int> map2 =
    {
        {"ACE",19},{"MARCUS",30},{"BINNY",30}
        
    };
    return 0;
}

 

 

map - Insertion

 

- Key / Value 쌍을 insert function 또는 [ ] 를 통해서 추가한다.

 

#include <iostream>
#include <map>
#include <string>

int main()
{
    using namespace std;

    map<string,int> ageMap;

    // 첫 번 째 방법
    ageMap.insert({"ACE",30});
    // 두 번 째 방법
    ageMap["MARCUS"] = 30l;
    // 세 번 째 방법
    ageMap.insert(make_pair("ROLE",40));

    // 만약!
    ageMap.insert({"ACE",29}); //<-- 이미 key가 있어서 무시
    ageMap["ACE"] = 29; // 이렇게 하면 Data Update 가능

    cout << ageMap["ACE"]<<endl;
    cout << ageMap["MARCUS"]<<endl;
    cout << ageMap["ROLE"]<<endl;
    cout << ageMap["ACE2222"]<<endl;
    // 29
    // 30
    // 40
    // 0

    return 0;
}

 

- 없는 key에 대해선 아무 값 반환 ( 여기선 0 )

 

 

map - Search

 

- find라는 finction으로 key 값을 찾으며 이는 key 값을 포인팅하는 iterator를 반환한다.

 

#include <iostream>
#include <map>
#include <string>

int main()
{
    using namespace std;

    map<string , int>agemap={
        {"A",1},
        {"B",2},
        {"C",3}
    };

    string name = "B";

    if(agemap.find(name) != agemap.end())
    {
        cout << agemap[name]<<endl;
    } // agemap이라는 것이 있는가 check, 이걸 아래와 같이 효율화가능
    //2
    auto it = agemap.find("B");
    if(it != agemap.end())
    {
        cout << it->first << ":" << it->second <<endl;
    }
    // B:2
    return 0;
}

 

 

- find가 element를 못 찾으면 agemap.find(name) --> agemap.end()로 포인팅 한다.

 

    if(agemap.find(name) != agemap.end())
    {
        cout << agemap.find(name)->first<<":"<<agemap[name]<<endl;
    }
    //C:3
    
    //요런식으로도 표현 가능

 

- find가 iterator를 return 한다는 것을잊지 말자!!

 

 

map - Deletion

 

#include <iostream>
#include <map>
#include <string>

int main()
{

    std::map<std::string,int> map1 =
    {
        {"A",100},
        {"B",2}
    };
    std::cout << map1["A"] << std::endl;
    // 100
    map1.erase("A");

    std::cout << map1["A"] << std::endl;
    std::cout << map1["RANDOM"] << std::endl;
    // 0
    // 0
    map1.erase("C"); // No Error, 항상 KEY값이 존재하는 지 체크


    return 0;
}

 

 - map은 없는 KEY 값에 대해선 Value를 Read 하려고 할 때, 없는 Value라고 Error를 띄우지 않고 0을 반환하네

 

 

map - Iteration

 

- range-based for 문 이나 iterator로 map 값을 반환하며, KEY의 오름차순 순서로 진행한다.

 

#include <iostream>
#include <map>
#include <string>

 int main()
 {
    std::map<std::string,int> map1 = 
    {
        {"A",11},
        {"B",22},
        {"C",33}
    };

    // Range - Based for loop [ Pair란 놈 등장;;;;]
    for(std::pair<std::string,int> pair : map1)
    {
        std::cout << pair.first << ":" << pair.second << std::endl;
    }
    // A:11
    // B:22
    // C:33

    // Iterator

    for(std::map<std::string,int>::iterator it=map1.begin();it!=map1.end();++it)
    {
        std::cout<<it->first<<":"<<it->second<<std::endl;
    }
    // A:11
    // B:22
    // C:33
    return 0;
 }

map의 method! 어느 container나 size() , empty() 는 거의 항상 있는듯 하다

 

 

이제 Last!!!

 

set

 

- set은 unique한 element들을 저장하는 container이다.

 

- element들의 key = value이다.

 

- 기본적으로 sorting이 된 구조로 저장되어 있다.

 

- set은 balanced binary search tree 구조이다. 

 

- #include <set> header 파일 필요

 

#include <iostream>
#include <set>

int main(void)
{
    //initialization
    std::set<int> set1;

    //initialize with list
    std::set<int> set2 = {3,2,4,1,5};
    return 0;
}

 

 

set의 Insertion / Search / Deletion

 

 

- Insert는 insert 함수를 이용하고

 

- Delete는 erase 함수를 쓰거나 iterator를 사용한다.

 

 

    //initialize with list
    std::set<int> set2 = {3,2,4,1,5};

    //Add
    set2.insert(6);

    //Remove
    set2.erase(1); // by value

    auto it = set2.find(2);
    if(it != set2.end())
    {
        set2.erase(it); 
    } // by iterator

    return 0;

 

set - Iteration

 

- map 때와 비슷하게 range-based for문이나 iterator를 통해 접근한다.

 

    std::set<int> set2 = {3,2,4,1,5};

    //Add
    set2.insert(6);

    //Remove
    set2.erase(1); // by value

    auto it = set2.find(2);
    if(it != set2.end())
    {
        set2.erase(it); 
    } // by iterator

    // Iterate using a range-based for loop

    for(auto elem : set2)
    {
        std::cout << elem << " ";
    }//3 4 5 6
    std::cout << std::endl;
    
	//Iterator로 접근
    for(auto it = set2.begin();it!=set2.end();++it)
    {
        std::cout << *it << " ";
    }//3 4 5 6

 

- SET는 중복을 허용하지 않기 때문에, 극단적으로 아래와 같이 선언해도 결과값은 중복제거!! + 자동 SORTING 오름차순

 

#include <iostream>
#include <set>

int main()
{

    std::set<int> set2 = {3,3,1,3,3,3,3,3,2,4,5,7,7,7};

    //Add
    set2.insert(6);
    set2.insert(6);
    set2.insert(6);
    set2.insert(6);
    set2.insert(6);
    set2.insert(6);

    //Remove
    set2.erase(1); // by value

    for(auto elem : set2)
    {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
    
	//Iterator로 접근
    for(auto it = set2.begin();it!=set2.end();++it)
    {
        std::cout << *it << " ";
    }

// 2 3 4 5 6 7
// 2 3 4 5 6 7
}

 

 

- auto만 잘 쓰면 쉽게 쉽게 접근 가능하다

 

- auto 아니면 요렇게 복잡하게 접근 ㅠㅠ

 

 for(std::set<int>::iterator it=set2.begin();it!=set2.end();++it)

 

 

 

 

- 자세히 다룬 Container 외 에도 이렇게 많은 종류의 Container가 있다.

 

C++과 Python 자료구조 비교

 

 

이번엔 요기까지..!

 

'SW 만학도 > C++' 카테고리의 다른 글

6. Out_of_class Definition & Operator Overloading  (0) 2024.04.10
5. Classes  (0) 2024.04.09
4. Functions and Memory Management  (1) 2024.03.29
2. C++ Standard Library (2)  (1) 2024.03.22
1. C++ Standard Library (1)  (0) 2024.03.21