array, vector, forward_list 함수

이선아·2021년 8월 22일
1

📌 std::array

std::array 는 원소의 타입과 배열 크기를 매개변수로 사용하는 클래스 템플릿으로 메모리를 자동으로 할당하고 해제합니다.

std::array<int, 10> arr1; //크기가 10인 int 타입 배열 선언
std::array<int, 4> arr2={1, 2, 3, 4};

C 스타일과 똑같은 방식으로 배열 원소에 접근할 수 있는 [ ] 연산자를 제공합니다. at(index) 형식의 함수도 함께 제공하며, index 값이 유효하지 않으면 std::out_of_range 예외(Exception)를 발생시킵니다.

std::cout<<arr2.at(4)<<std::endl; //std::out_of_range 예외 발생

만약 다양한 크기의 std::array 객체에 대해 동작하는 범용적인 배열 출력 함수를 만들기를 원할 땐, print( )를 함수 템플릿으로 선언하고, 배열 크기를 템플릿 매개변수로 전달해야 합니다.

template <size_t N>
void print(const std::array<int, N>& arr);

  • begin( )과 end( ) 멤버 함수
    for 반복문을 사용할 때는 배열의 크기를 정확하게 지정해야지 그렇지 않으면 에러가 발생합니다. std::array에서는 begin( )과 end( ) 라는 멤버 함수를 제공하는데, 이들은 가장 첫 번째 원소와 가장 마지막 원소의 위치를 반환해 줍니다.
    반복자를 사용하여 소스 코드의 재사용, 유지 보수, 가독성 측면에서 이점을 얻을 수 있습니다.
for(auto it=arr2.begin(); it!=arr2.end(); it++) {
	auto element=(*it);
    std::cout<<element<<" ";
}


📌 std::vector

vector는 가변 크기 배열입니다. array가 가진 단점 중 하나인 '고정된 크기'의 문제를 해결할 수 있습니다.

using namespace std;

//크기가 0인 벡터 선언
vector<int> vec;

//초깃값으로 크기가 정해지는 벡터 선언(크기 5)
vector<int> vec = {1, 2, 3, 4, 5};

//크기가 10이고, 모든 원소가 6으로 초기화된 벡터 선언
vector<int> vec(10, 6);

벡터에 새로운 원소를 추가할 때는 벡터의 맨 마지막에 원소를 추가하는 push_back() 함수, 또는 삽입할 위치를 나타내는 반복자를 첫 번째 인자로 받아 원하는 위치에 원소를 추가할 수 있는 insert() 함수를 사용합니다.

push_back( ) 함수의 평균 시간 복잡도 O(1)
insert( ) 함수의 평균 시간 복잡도 O(n)

using namespace std;

vector<int> vec={1, 2, 3, 4, 5};

//벡터의 맨 앞에 새로운 원소 추가 {0, 1, 2, 3, 4, 5}
vec.insert(int.begin(), 0); 

//맨 뒤에 3추가 {0, 1, 2, 3, 4, 5, 3}
vec.push_back(3);

//1 앞에 4 추가 {0, 4, 1, 2, 3, 4, 5, 3}
vec.insert(find(vec.begin(), vec.end(), 1), 4);

하지만 push_back() 함수와 insert() 함수의 단점 중 하나는 추가할 원소를 먼저 임시로 생성한 후, 벡터 버퍼 내부로 복사하거나 이동을 수행한다는 점입니다.
그렇지만 emplace_back(), emplace() 함수를 이용하면 새로운 원소가 추가될 위치에서 해당 원소를 생성하는 방식으로 최적화할 수 있게 됩니다.
이 함수들은 새 원소의 위치에서 바로 객체가 생성되기 때문에 함수 인자에 객체를 전달하는 것이 아니라, 생성자에 필요한 매개변수를 전달해야합니다.


벡터는 원소 제거를 위한 pop_back() 과 erase() 함수도 제공합니다.
pop_back() 함수는 벡터의 맨 마지막 원소를 제거하고 벡터 크기도 1만큼 줄어듭니다. erase() 함수는 반복자 하나를 인자로 받아 해당 위치의 원소를 제거할 수도 있고, 범위의 시작과 끝을 반복자로 받아 원소를 제거할 수 있습니다.

using namespace std;

vector<int> vec={0, 1, 2, 3, 4, 5}

//맨 마지막 원소 제거 {0, 1, 2, 3, 4}
vec.pop_back();

//맨 처음 원소 제거 {1, 2, 3, 4}
vec.erase(vec.begin());

//범위 원소 제거(1번째 원소부터 3번째 앞 원소까지) {1, 4}
vec.erase(vec.begin()+1, vec.begin()+3);

pop_back( ) 함수의 평균 시간 복잡도 O(1)
erase( ) 함수의 평균 시간 복잡도 O(n)


  • vector의 추가적인 멤버 함수들
    clear( ) : 모든 원소를 제거하여 비어있는 벡터로 만든다.
    reserve(capacity) : 벡터에서 사용할 용량을 지정해준다.
    shrink_to_fit( ) : 여분의 메모리 공간을 해제하는 용도로 사용한다. 벡터의 크기가 변경되지 않을 때 사용하면 좋다.


📌 std::forward_list

forward_list는 배열과 벡터 같은 연속된 자료 구조에서의 자료 추가와 삭제의 비효율성을 해결하기 위한 연결 리스트입니다.
기본적인 연결 리스트를 구성하기 위해선 포인터를 사용하며 new와 delete 연산자를 이용하여 메모리의 할당과 해제가 필요합니다.

forward_list는 전체 리스트의 크기 반환과 첫 번째 원소에 접근하는 것 이외의 나머지 원소에 직접 접근하는 기능은 없습니다. 대신 원소의 삽입, 삭제, 순서 뒤집기, 분할을 위한 기능은 제공합니다.

원소를 삽입할 때는 맨 앞에 새로운 원소를 삽입하는 push_front() 와 특정 위치레 원소를 삽입하는 insert_after() 함수를 사용할 수 있습니다. 이들의 시간 복잡도는 O(1) 로 매우 빠르게 동작합니다.

using namespace std;

forward_list<int> fwd_list={1, 2, 3};

fwd_list.push_front(0); // 맨 앞에 새로운 원소 0 추가

auto it=fwd_list.begin();

fwd_list.insert_after(it, 5); // 맨 처음 원소 뒤에 5 추가 { 0, 5, 1, 2, 3}

fwd_list.insert_after(it, 6); // {0, 6, 5, 1, 2, 3}

forward_list는 벡터의 emplace() 함수와 비슷한 emplace_front()emplace_after() 함수도 제공합니다. 삽입 함수와 같은 기능을 수행하지만 추가적인 복사 또는 이동은 하지 않기에 더 효율적입니다.

원소의 삭제는 pop_front()erase_after() 함수를 이용합니다. pop_front()는 맨 처음 원소를 제거하고 시간 복잡도는 O(1) 이며, erase_after() 함수는 특정 원소를 가리키는 반복자를 인자로 받아 바로 다음 위치의 원소를 삭제하거나, 삭제할 범위의 시작 원소와 끝 원소를 가리키는 반복자를 인자로 받아 제거할 수 있습니다.

using namespace std;

forward_list<int> fwd_list={0, 1, 2, 3};

fwd_list.pop_front(); // 맨 앞 원소 삭제 {1, 2, 3}

auto it=fwd_list.begin();

fwd_list.erase_after(it); // 맨 처음 다음 원소 삭제 {1, 3}

fwd_list.erase_after(it, fwd_list.end()); // 맨 처음 다음 원소부터 맨 끝 원소까지 삭제 {1}

  • 기타 멤버 함수
    remove(), remove_if() : 원소 값을 검사하여 삭제하는 함수
    remove() 함수는 삭제할 원소 값 하나를 매개변수로 받아 저장된 데이터 타입에 정의된 등호 연산자를 사용하여 전달된 값과 일치하는 모든 원소를 찾아 삭제합니다. 만약 저장된 데이터 타입에서 등호 연산이 지원되지 않으면 이 함수를 사용할 수 없습니다.
    remove()는 오직 등호 연산에만 근거하여 원소를 삭제하지만 조건부를 붙이고 싶다면 remove_if() 함수를 사용할 수 있습니다.
profile
깃허브 놀러오세용 -> Tistory로 블로그 이전합니다.

0개의 댓글