[C++] STL List Container 사용 방법 정리

반응형
반응형

* 개인적인 공부 내용을 기록하는 용도로 작성한 글 이기에 잘못된 내용을 포함하고 있을 수 있습니다.

* 다음 포스팅은 C++ STL List Container의 사용 방법에 대한 내용에 대해 기술하고 있으며, Linked List (연결 리스트) 의 개념 혹은 구현 방법에 대한 내용을 원하시는 분은 다음 포스팅을 참고해 주시기 바랍니다.

 

_ Related

→ [DataStructure] 연결 리스트 : Linked List 개념 정리

→ Linked List 구현 Witch C/C++ (미완성)


_Content

#0 Access List Container With For & at & []

#1 List Container Initialization : List 초기화 & 선언

#1.1 생성자를 이용한 초기화

#1.2 assign memeber function 을 이용한 초기화

#2 List Push & Pop

#3 List insert & erase : List 삽입 & 삭제

#4 List Sort : List 정렬

#5 List Copy : 리스트 복사

#5.1 복사 생성자를 이용한 복사

#5.2 대입 연산자를 이용한 복사

#6 List Size : 리스트 크기 확인


#0 Access List Container With For & at & []

STL List Container는 다른 Vector Deque Queue와 같은 시퀀스 컨테이너들과 달리 for문을 사용해 인덱스로 데이터에 접근하거나 접근 지정자 at & [] 을 사용해 원소에 접근하는 것이 불가능합니다.

그 이유는 연결 리스트 (Linked List) 의 구조를 알고 있으면 당연한데, Linked List는 원소들이 메모리에 연속되게 저장된 구조가 아닌 각 원소가 다음 원소의 주소를 포함하고 있는 노드 기반 구조이기 때문입니다.

따라서 특정 지점의 요소에 직접 접근하는 것은 구조상 불가능합니다.

그렇기에 list에서 for문을 사용해 원소에 순차적으로 접근하고자 한다면 다음과 같이 iterator를 사용해야 합니다.

#include <iostream>
#include <list>
using namespace std;
int main(){
	list<int> list_int(5, 1);
	for(list<int>::iterator it  = list_int.begin(); it != list_int.end(); it++)
		cout << *it << ", ";
	cout << '\n';
	return 0;
}

 

하지만 C++11 이상 부터는 Range-Based-For 문법을 사용해 인덱스에 순차적으로 접근하는 것을 허용합니다.

Range-Based-For 문법을 모르시는 분들은 다음 포스팅을 참고해 주세요.

[C++] range-based-for 범위 기반 for문

#include <iostream>
#include <list>
using namespace std;
int main(){
	list<int> list_int(5, 1);
	for(const auto& i : list_int)
		cout << i << ", ";
	cout << '\n';
	return 0;
}

#1  List Container Initialization : List 초기화 & 선언

#1.1 생성자를 이용한 초기화

기본 형태 : list<DataType> ListName

 

#생성자를 이용해 특정 공간을 Default Value로 초기화 합니다.

What is Default Value?

DataType Int, Double의 Default Value는 0, DataType Char의 Default Value 는 ' ' 입니다.

 

#include <iostream>
#include <list>
using namespace std;
int main(){
	list<int> list_int(5);
	for(const auto& i : list_int)
		cout << i << ", ";
	cout << '\n';
	
	list<double> list_double(5);
	for(const auto& i : list_double)
		cout << i << ", ";
	cout << '\n';
	
	list<char> list_char(5);
	for(const auto& i : list_char)
		cout << i << ", ";
	cout << '\n';
	return 0;
}
[Result] 
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
, , , , ,

 

#생성자를 이용해 요소의 개수, 특정 값을 지정하여 초기화 합니다.

[example] list<int> list_int(5, 1) - int 자료형 요소 5개를 1로 초기화한 list 를 선언합니다.

#include <iostream>
#include <list>
using namespace std;
int main(){
	list<int> list_int(5, 1);
	for(const auto& i : list_int)
		cout << i << ", ";
	cout << '\n';
	return 0;
}
[Result] 1, 1, 1, 1, 1,

 

#C++11 Uniform Initialization { } 를 사용해 특정 개수, 특정 값을 지정해 초기화 합니다.

[example] list<int> list_int {1, 2, 3, 4, 5} - 원소 1, 2, 3, 4, 5 를 가지는 int 자료형 list를 선언합니다.

#include <iostream>
#include <list>
using namespace std;
int main(){
	list<int> list_int {1, 2, 3, 4, 5};
	for(const auto& i: list_int) cout << i << " ";
	cout << '\n';
	return 0;
}
[Result] 1 2 3 4 5

 

#1.2 assign member function 을 이용한 초기화

assign memeber function 을 사용하면 list를 선언한 후에 초기화 하는 것이 가능합니다.

[example] list_name.assign(개수,값)

#include <iostream>
#include <list>
using namespace std;
int main(){
	list<int> list_int;
	// listValueName.assign(개수, 값);
	list_int.assign(3, 4);
	for(const auto& i : list_int)
		cout << i << " ";
	cout << '\n';
	return 0;
}
[Result] 4 4 4

#2 List Push & Pop

List Container는 다른 STL Container과 마찬가지로 가장 앞의 원소를 추가 & 제거 하는 push_front() & pop_front() member function 과 가장 뒤에 원소를 추가 & 제거 하는 push_back() & pop_back() member function을 제공합니다.

참고로 List의 Push & Pop 연산은 모두 시간 복잡도 O(1)에 수행합니다.

 

push_back(k) - List의 가장 뒤에 원소 k를 삽입합니다. 

push_front(k) - List의 가장 앞에 원소 k를 삽입합니다.

pop_back() - List의 가장 뒤에 있는 원소를 제거합니다.

pop_front() - List의 가장 첫 번째 원소를 제거합니다.

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

int main(){
	list<int> myList {1, 2, 3, 4, 5};
	cout << "push_back(6) - ";
	myList.push_back(6);
	for(const auto& i : myList) cout << i << " ";
	cout << '\n';
	
	cout << "push_front(0) - ";
	myList.push_front(0);
	for(const auto& i : myList) cout << i << " ";
	cout << '\n';
	
	cout << "pop_back() - ";
	myList.pop_back();
	for(const auto& i : myList) cout << i << " ";
	cout << '\n';
	
	cout << "pop_front() - ";
	myList.pop_front();
	for(const auto& i : myList) cout << i << " ";
	cout << '\n';
	
	return 0;
}
push_back(6) - 1 2 3 4 5 6
push_front(0) - 0 1 2 3 4 5 6
pop_back() - 0 1 2 3 4 5
pop_front() - 1 2 3 4 5

#3 List insert & erase : List 삽입 & 삭제

List에서 중간에 원소를 삽입 혹은 삭제하는 연산 또한 시간 복잡도 O(1)에 수행합니다.

 

insert(iterator, k) - iterator가 가리키는 위치에 k를 삽입합니다.

erase(iterator) - iterator가 가리키는 위치의 원소를 삭제합니다.

* erase member function 사용 시 주의점

remove(k) - k에 해당하는 원소를 모두 삭제합니다.

remove_if(predicate) - predicate 조건에 해당하는 원소를 모두 삭제합니다.

 

insert & erase example

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

int main(){
	list<int> myList {1, 2, 3, 4, 5};
	myList.insert(myList.begin(), 0);
	for(const auto& i : myList) cout << i << " ";
	cout << '\n';
	
	myList.erase(myList.begin());
	for(const auto& i : myList) cout << i << " ";
    	return 0;
}
[Result]
0 1 2 3 4 5
1 2 3 4 5

 

remove example

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

int main(){
	list<int> myList {1, 1, 2, 2, 3, 3, 4, 4, 5, 5};
	myList.remove(1);
	for(const auto& i : myList) cout << i << " ";
}
[Result] 2 2 3 3 4 4 5 5

 

remove_if example

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

bool predicate(int n){
	return n <= 2;
}

int main(){
	list<int> myList {1, 1, 2, 2, 3, 3, 4, 4, 5, 5};
	myList.remove_if(predicate);
	for(const auto& i : myList) cout << i << " ";
}

#4 List Sort : 리스트 정렬

sort() - List의 원소를 오름차(default) 정렬합니다.

reverse() - List의 원소를 뒤집습니다.

 

sort example

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

int main(){
	list<int> myList {5, 4, 3, 2, 1};
	cout << "Before Sort - ";
	for(const auto& i : myList) cout << i << " ";
	cout << '\n';
	
	cout << "After Sort - ";
	myList.sort();
	for(const auto& i : myList) cout << i << " ";
	cout << '\n';
}
[Result]
Before Sort - 5 4 3 2 1
After Sort - 1 2 3 4 5

 

reverse example

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

int main(){
	list<int> myList {1, 2, 3, 4, 5};
	cout << "Before Reverse - ";
	for(const auto& i : myList) cout << i << " ";
	cout << '\n';
	
	cout << "After Reverse - ";
	myList.reverse();
	for(const auto& i : myList) cout << i << " ";
	cout << '\n';
}
Before Reverse - 1 2 3 4 5
After Reverse - 5 4 3 2 1

#5 List Copy : 리스트 복사

#5.1 복사 생성자를 이용한 복사

[example] list<Data Type> new_list(old_list)

new_list : old_list의 원소들이 복사 될 리스트

old_list : new_list로 복사할 원소들이 저장되어 있는 리스트

#include <iostream>
#include <list>
using namespace std;
int main(){
	list<int> old_list {1, 2, 3, 4, 5};
	list<int> new_list(old_list);
	for(const auto& i : new_list)
		cout << i << " ";
	cout << '\n';
	return 0;
}
[Result] 1 2 3 4 5

 

#5.2 대입 연산자를 이용한 복사

[example] list<Data Type> new_list = old_list

#include <iostream>
#include <list>
using namespace std;
int main(){
	list<int> old_list {1, 2, 3, 4, 5};
	list<int> new_list = old_list;
	for(const auto& i : new_list)
		cout << i << " ";
	cout << '\n';
	return 0;
}
[Result] 1 2 3 4 5

#6 List Size : 리스트 크기 확인

size() - 리스트의 사이즈를 반환합니다.

#include <iostream>
#include <list>
using namespace std;
int main(){
	list<int> myList {1, 2, 3, 4, 5};
	cout << myList.size() << '\n';
	return 0;
}
[Result] 5

C++ STL List 컨테이너에 대한 사용방법에 대해 정리해 보았습니다.

도움이 되셨다면 공감 부탁드립니다!

 

... 연결 리스트 연습에 도움이 되는 문제

→ 백준 1406 에디터

반응형

댓글

Designed by JB FACTORY