[C++] STL list 사용법

 

STL list

list는 양방향 연결 리스트( doubly-linked list ) 구조를 이루는 선형 컨테이너입니다.

그렇기 때문에, 데이터의 위치와 상관없이 효율적인 삽입과 삭제가 가능하고,

앞쪽과 뒤쪽, 모든 방향으로의 순환이 가능한 컨테이너입니다.

 

 

양방향 연결 리스트

 

이 list를 사용하려면 다음의 헤더를 포함해야 합니다.

#include <list>

 

list의 선언

list의 선언은 다음과 같습니다.

std::list<T> list_name;

여기서 T는 list의 데이터 타입을 나타냅니다.

 

그리고, namespace를 선언함으로써, std를 매번 명시해야 하는 번거로움을 덜 수도 있습니다.

using namespace std;

list<int> int_list;	// int 타입의 리스트 선언

 

list의 초기화

list를 초기화하는 방법은 여러 가지가 있습니다.

1. 초기화 리스트를 사용하는 방법입니다.

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

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };	// 초기화 리스트

    for( int data : int_list){
        cout << data << " ";
    }
}


2. 유니폼 초기화( uniform initialization )를 사용하는 방법입니다.

list<int> int_list { 1, 2, 3, 4, 5 };	// uniform 초기화


3. 직접 크기와 값을 설정할 수도 있습니다.

list<int> int_list (5, 10);	// 5개의 원소를 값 10으로 초기화합니다.

list<int> int_list = { 10, 10, 10, 10, 10 };	// 위의 줄과 동일합니다.


4. 다른 list를 복사하여 초기화할 수도 있습니다.

list<int> int_list = { 1, 2, 3, 4, 5 };

list<int> copy_list(int_list);

 

 

list의 반복자( Iterator )

list 반복자는 list 내의 원소들에 접근하고, 원소들 간의 이동을 위해서 사용됩니다.
list의 반복자는 양방향 반복자( bidirectional iterator )입니다.

반복자( iterator )의 전반적인 내용은 여기에 정리해 두었습니다.

 

[C++] 반복자( Iterator )에 대한 설명과 종류

반복자( Iterator )란 무엇인가?Iterator는 컨테이너에서 원소의 위치를 표현하는, 포인터와 같은 객체입니다. 여기서, 컨테이너란 다른 객체들을 담는 집합 객체라고 할 수 있습니다. 컨테이너의

codingembers.co.kr

 

list 반복자는 다음과 같이 선언합니다.

list<T>::iterator iter_name;

여기서, T는 list의 데이터 타입을 나타냅니다.

 

list의 반복자 초기화

list의 초기화는 다음의 함수들로 수행할 수 있습니다.

begin

이 함수는 list의 첫 번째 원소를 가리키는 iterator를 반환합니다.

list<int> int_list = { 1, 2, 3, 4, 5 };
list<int>::iterator iter;   // int타입 list의 반복자 선언

iter = int_list.begin();

end

이 함수는 list의 마지막 원소 다음을 가리키는 iterator를 반환합니다.
마지막 원소를 가리키는 iterator는 다음과 같이 구할 수 있습니다.

list<int> int_list = { 1, 2, 3, 4, 5 };
list<int>::iterator iter;   // int타입 list의 반복자 선언

iter = int_list.end();
iter--;

int val = *iter;	// 마지막 원소 5

 

만일, list의 원소가 하나도 없다면 begin과 end가 같은 값을 반환합니다.

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

int main(){

    list<int> int_list;
    if ( int_list.begin() == int_list.end()){
        cout << "list size is zero\n";
    }

    return 0;
}

▼출력

list size is zero

 

list의 모든 원소를 순환하고자 하면 다음과 같이 할 수 있습니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };
    list<int>::iterator iter;

    for(iter = int_list.begin(); iter != int_list.end(); iter++){
        cout << *iter << " ";
    }

    return 0;
}

▼출력

1 2 3 4 5

 

 

list의 기능들

list는 매우 많은 기능을 가진 객체입니다.
이 중에서, 공통적으로 많이 쓰이는 기능을 정리해서 설명하겠습니다.

 

 

원소의 개수 알아내기

size

list가 저장하고 있는 원소의 개수를 반환합니다.

empty

list가 가지고 있는 원소의 개수가 0이면 true, 아니면 false를 반환합니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };

    cout << int_list.size() << endl;

    cout << "is empty: " << int_list.empty();

    return 0;
}

▼출력

5
is empty: 0

 

원소에 접근하기

front

reference front();
const_reference front() const;

list의 첫 번째 원소를 반환합니다.

만약, list가 원소를 갖고 있지 않은 경우, 위 함수는 정의되지 않으므로, 사용 시 주의해야 합니다.

back

reference back();
const_reference back() const;

list의 마지막 원소를 반환합니다.

만약, list가 원소를 갖고 있지 않은 경우, 위 함수는 정의되지 않으므로, 사용 시 주의해야 합니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };

    int& first = int_list.front();	// 첫 번째 원소의 참조 반환
    first = 0;
    cout << "first element: " << first << endl;

    const int& last = int_list.back();	// 마지막 원소의 참조 반환
    cout << "last element: " << last << endl;

    return 0;
}

 

원소 추가하기

push_front 

새로운 원소를 list의 처음에 추가합니다.

push_back

원소를 list의 마지막에 추가합니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };

    int_list.push_front(0);
    int_list.push_back(6);
    
    for( int data : int_list ){
        cout << data << " ";
    }

    return 0;
}

▼출력

0 1 2 3 4 5 6

 

insert 

원소를 하나 또는 여러 개를 Iterator가 가리키는 위치에 삽입합니다.

 

이 함수는 여러 가지 방식으로 데이터를 추가할 수 있습니다.

먼저, 하나의 원소를 원하는 위치에 입력하는 방법입니다.

이 버전은 입력된 원소의 위치를 나타내는 iterator를 반환합니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };
    list<int>::iterator iter = int_list.begin();   // int타입 list의 반복자 선언

    iter = int_list.insert( iter, 0);	// 입력된 원소를 위치를 반환

    iter++;
    int_list.insert( iter, 20);

    for( int data : int_list){
        cout << data << " ";
    }

    return 0;
}

▼출력

0 20 1 2 3 4 5

 

같은 원소를 연속해서 삽입할 수도 있습니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };
    list<int>::iterator iter = int_list.begin();   // int타입 list의 반복자 선언

    int_list.insert( iter, 3, 10);	// 같은 값을 가진 원소를 3개 삽입

    for( int data : int_list){
        cout << data << " ";
    }

    return 0;
}

▼출력

10 10 10 1 2 3 4 5

 

다른 객체의 원소를 가리키는 iterator를 사용해서, 삽입할 수도 있습니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };
    list<int> int_list2 = { 10, 20, 30 };	// 다른 list 객체
    
    list<int>::iterator iter = int_list.begin();   // int타입 list의 반복자 선언

    // 세 번째 인자는 입력하고자 하는 마지막 원소의 다음 원소 위치입니다.
    int_list.insert( iter, int_list2.begin(), int_list2.end());

    for( int data : int_list){
        cout << data << " ";
    }

    return 0;
}

▼출력

10 20 30 1 2 3 4 5

 

원소 삭제하기

pop_front

list의 첫 번째 원소를 삭제합니다.

list에 데이터가 없는 경우, 예외( exception )가 발생합니다.

pop_back

list의 마지막 원소를 삭제합니다.

list에 데이터가 없는 경우, 예외( exception )가 발생합니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };

    int_list.pop_front();
    int_list.pop_back();

    for( int data : int_list){
        cout << data << " ";
    }

    return 0;
}

▼출력

2 3 4

clear

list의 모든 원소를 삭제합니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };
    int_list.clear();

    int size = int_list.size(); // 0

    return 0;
}

 

remove

list에 찾는 값이 있으면 삭제합니다.

int main(){

    list<int> int_list = { 1, 2, 3, 2, 5, 2, 7 };
    
    int_list.remove(2);

    for( int data : int_list){
        cout << data << " ";
    }

    return 0;
}

▼출력

1 3 5 7

erase

list의 iterator가 가리키는 원소를 삭제합니다.

만일, iterator가 가리키는 원소가 없으면 예외(exception)가 발생합니다.

그리고, 원소를 삭제하고 남아있는 첫 번째 위치를 가리키는 iterator를 반환하거나,

남은 원소가 없으면 end()를 반환합니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };
    list<int>::iterator iter = int_list.end();
    iter--;
    iter--;

    iter = int_list.erase(iter);

    cout << "returned iterator: " << *iter << endl;

    for( int data : int_list){
        cout << data << " ";
    }

    return 0;
}

▼출력

returned iterator: 5
1 2 3 5

 

원소의 범위를 지정하여 여러 원소를 삭제할 수도 있습니다.

이때, 마지막 인자는 삭제하고자 하는 원소의 다음을 가리키는 iterator입니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };
    list<int>::iterator iter = int_list.begin();
    iter++;
    
    int_list.erase( iter, int_list.end());
    
    cout << "remained: ";
    for( int data : int_list){
        cout << data << " ";
    }

    return 0;
}

▼출력

remained: 1

 

그 외의 다양한 기능들

reverse

list 안에 있는 원소들의 순서를 반대로 변경합니다.

int main(){

    list<int> int_list = { 1, 2, 3, 4, 5 };
        
    int_list.reverse();
    
    for( int data : int_list){
        cout << data << " ";
    }

    return 0;
}

▼출력

5 4 3 2 1

sort

list 안의 원소를 오름차순(기본값) 또는 사용자 정렬 함수를 통한 정렬을 수행합니다.

참고로, STL의 sort 함수는 임의 접근 반복자( random access iterator )를 지원하는 컨테이너만을 지원하기 때문에, 

list는 sort 함수를 사용할 수 없습니다.

그래서, list는 자체적인 정렬 함수를 사용합니다.

int main(){

    list<int> int_list = { 3, 2, 1, 5, 4 };
        
    int_list.sort();    // 오름차순으로 정렬 (기본값)
    
    cout << "1st sort: ";
    for( int data : int_list){
        cout << data << " ";
    }

    int_list.sort( greater<int>() );    // 내림차순으로 정렬

    cout << endl << "2nd sort: ";
    for( int data : int_list){
        cout << data << " ";
    }

    return 0;
}

▼출력

1st sort: 1 2 3 4 5 
2nd sort: 5 4 3 2 1

unique

이 함수는 연속된 같은 값을 가진 원소를 삭제합니다.

이 함수는 정렬된 된 데이터를 가정하고 있기 때문에, 연속하지 않으면 같은 값을 가졌다 하더라도 삭제되지 않습니다.

또한, 사용자 비교 함수를 사용해서, 연속하면서 서로의 값이 같지 않은 원소를 삭제할 수도 있습니다.

int main(){

    list<int> int_list = { -10, 10, 10, 20, 20, -10 };
    
    not_equal_to<int> bifunc;   // 같지 않으면 true를 리턴하는 함수 객체

    cout << "original: ";
    for( int data : int_list){
        cout << data << " ";
    }
    
    int_list.unique();  // 인접한 같은 원소 모두 제거
            
    cout << endl << "1st unique: ";
    for( int data : int_list){
        cout << data << " ";
    }

    int_list.unique( not_equal_to<int>() );    // 인접한 같지 않은 원소 모두 제거

    cout << endl << "2nd unique: ";
    for( int data : int_list){
        cout << data << " ";
    }

    return 0;
}

▼출력

original: -10 10 10 20 20 -10 
1st unique: -10 10 20 -10
2nd unique: -10 -10

merge

 

병합될 list에서 원소를 제거하여, 대상 list에 병합시킵니다.

이때, 병합될 순서를 오름차순(기본값)으로 하거나, 사용자 비교 함수를 통해서 정렬 순서를 정할 수 있습니다.

주의할 것은, 병합되기 전의 list는 정렬하고자 하는 순서대로 정렬되어 있어야 한다는 것입니다.

int main(){

    list<int> int_list1 = { 1, 3, 2 };
    list<int> int_list2 = { 6, 4, 5 };
    list<int> dest = { 7, 9, 8 };

    // 모두 같은 정렬 순으로 정렬되어 있어야 합니다.
    int_list1.sort( greater<int>());
    int_list2.sort( greater<int>());
    dest.sort( greater<int>());

    dest.merge(int_list1, greater<int>());  // 오름차순으로 병합

    cout << "1st merge: ";
    for( int data : dest){
        cout << data << " ";
    }
    
    dest.merge(int_list2, greater<int>());  // 오름차순으로 병합

    cout << endl << "2nd merge: ";
    for( int data : dest){
        cout << data << " ";
    }

    return 0;
}

▼출력

1st merge: 9 8 7 3 2 1 
2nd merge: 9 8 7 6 5 4 3 2 1

 

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유