vector | List | |
크기 변경 가능 | O | O |
중간 삽입, 삭제 용이 | X | O |
순차 접근 가능 | O | O |
랜덤 접근 가능 | O | X |
중간 삽입 삭제가 있다면 무조건 list를 사용해야 할까요? list와 vector의 차이점을 보면 중간 삽입, 삭제가 자주 일어나는 자료구조는 list 사용이 정답입니다.
그렇다고 list 사용이 항상 정답은 아닙니다. 만약 저장하는 데이터의 개수가 적고 랜덤 접근을 하고 싶은 경우에는 vector를 사용해도 좋습니다.
제가 하는 일을 예를 들면 대부분의 온라인 캐주얼 게임은 방을 만들어서 방에 들어온 유저끼리 게임을 합니다. 방은 유저가 들어 오기도 하고 나가기도 합니 다. 중간 삽입, 삭제가 자주 일어나지만 방의 유저 수는 대부분 적습니다. 이런 경우 중간 삽입, 삭제로 데이터를 이동해도 전체적인 성능 측면에서는 문제가 되지 않습니다. 방에 있는 유저를 저장한 위치를 알고 있다면 유저 데이터에 접근할 때 list는 반복문으로 해당 위치까지 순차적으로 접근해야 하지만 vector는 바로 랜덤 접근이 가능하고 성능면에서도 더 좋습니다. 또한, 방에 있는 모든 유저 데이터에 접근할 때 list는 반복자(Iterator)로 접근하지만, vector는 일반 배열 처럼 접근하므로 훨씬 간단하게 유저 데이터에 접근할 수 있습니다. 저장하는 데이터 개수가 적은 경우는 대부분 list 보다는 vector를 사용하는 편이 더 좋습니다. vector와 list의 차이점만으로 둘 중 어느 것을 사용할지 선택하기 보다는 전체적인 장, 단점을 파악하고나서 선택하는 것이 좋습니다. |
#includevector 형식은 아래와 같습니다.
vector< 자료 type > 변수 이름vector를 int 형에 대해 선언했습니다.
vector< int > vector1;선언 후 vector를 사용합니다. vector도 list처럼 동적 할당이 가능합니다.
vector < 자료 type >* 변수 이름 = new vector< 자료 type >; vector< int >* vector1 = new vector< int>;
멤버 | 설명 |
---|---|
assign | 특정 원소로 채운다 |
at | 특정 위치의 원소의 참조를 반환 |
back | 마지막 원소의 참조를 반환 |
begin | 첫 번째 원소의 랜던 접근 반복자를 반환 |
clear | 모든 원소를 삭제 |
empty | 아무것도 없으면 true 반환 |
End | 마지막 원소 다음의(미 사용 영역) 반복자를 반환 |
erase | 특정 위치의 원소나 지정 범위의 원소를 삭제 |
front | 첫 번째 원소의 참조를 반환 |
insert | 특정 위치에 원소 삽입 |
pop_back | 마지막 원소를 삭제 |
push_back | 마지막에 원소를 추가 |
rbegin | 역방향으로 첫 번째 원소의 반복자를 반환 |
rend | 역방향으로 마지막 원소 다음의 반복자를 반환 |
reserve | 지정된 크기의 저장 공간을 확보 |
size | 원소의 개소를 반환 |
swap | 두 개의 vector의 원소를 서로 맞바꾼다 |
멤버 | 원형 | 설명 |
---|---|---|
at | reference at( size_type _Pos );
const_reference at( size_type _Pos ) const; |
특정 위치의 원소의 참조를 반환 |
back | reference back( );
const_reference back( ) const; |
마지막 원소의 참조를 반환 |
begin | const_iterator begin() const;
iterator begin(); |
첫 번째 원소의 랜덤 접근 반복자를 반환 |
clear | void clear(); | 모든 원소를 삭제 |
empty | bool empty() const; | 아무것도 없으면 true 반환 |
end | iterator end( );
const_iterator end( ) const; |
마지막 원소 다음의(미 사용 영역) 반복자를 반환 |
front | reference front( );
const_reference front( ) const; |
첫 번째 원소의 참조를 반환 |
pop_back | void pop_back(); | 마지막 원소를 삭제 |
push_back | void push_back( const Type& _Val ); | 마지막에 원소를 추가 |
rbegin | reverse_iterator rbegin( );
const_reverse_iterator rbegin( ) const; |
역방향으로 첫 번째 원소의 반복자를 반환 |
rend | const_reverse_iterator rend( ) const;
reverse_iterator rend( ); |
역방향으로 마지막 원소 다음의 반복자를 반환 |
size | size_type size() const; | 원소의 개수를 반환 |
vector< int > vector1; vector1.push_back( 1 );삭제
vector1.pop_back();접근
vector< int >::iterator IterBegin = vector1.begin(); cout << *IterBegin << endl; int& FirstValue = vector1.front(); const int& refFirstValue = vector1.front();마지막 다음의 영역(미 사용 영역)을 가리키는 반복자를 반환할 때는 end()를 사용합니다. 마지막 원소의 참조를 반환할 때는 back()을 사용합니다.
; vector< int >::iterator IterEnd = vector1.end(); for(vector< int >::iterator IterPos = vector1.begin; IterPos != vector1.end(); ++IterPos ) { …….. } int& LastValue = vector1.back(); const int& refLastValue = vector1.back();rbegin()과 rend()는 방향이 역방향이라는 점만 다를 뿐, 나머지는 begin()과 end()와 같습니다. 특정 위치에 있는 원소를 접근할 때는 at()을 사용하면 됩니다.
int& Value1 = vector1.at(0); // 첫 번째 위치 const int Value2 = vector1.at(1); // 두 번째 위치배열 식 접근도 가능합니다. vector를 사용할 때 보통 이 방식으로 자주 사용합니다.
int Value = vector1[0]; // 첫 번째 위치모두 삭제
vector1.clear();데이터 저장 여부
bool bEmpty = vector1.empty();vector에 저장된 원소 개수 알기
vector< int >::size_type Count = vector1.size();위에 설명한 멤버들을 사용하는 아래의 예제 코드를 보면서 vector의 기본 사용 방법을 정확하게 숙지해 주세요
#include결과#include using namespace std; // 방의 유저 정보 struct RoomUser { int CharCd; // 캐릭터 코드 int Level; // 레벨 }; void main() { // 유저1 RoomUser RoomUser1; RoomUser1.CharCd = 1; RoomUser1.Level = 10; // 유저2 RoomUser RoomUser2; RoomUser2.CharCd = 2; RoomUser2.Level = 5; // 유저3 RoomUser RoomUser3; RoomUser3.CharCd = 3; RoomUser3.Level = 12; // 방의 유저들을 저장할 vector vector< RoomUser > RoomUsers; // 추가 RoomUsers.push_back( RoomUser1 ); RoomUsers.push_back( RoomUser2 ); RoomUsers.push_back( RoomUser3 ); // 방에 있는 유저 수 int UserCount = RoomUsers.size(); // 방에 있는 유저 정보 출력 // 반복자로 접근 - 순방향 for( vector< RoomUser >::iterator IterPos = RoomUsers.begin(); IterPos != RoomUsers.end(); ++IterPos ) { cout << "유저코드 : " << IterPos->CharCd << endl; cout << "유저레벨 : " << IterPos->Level << endl; } cout << endl; // 반복자로 접근- 역방향 for( vector< RoomUser >::reverse_iterator IterPos = RoomUsers.rbegin(); IterPos != RoomUsers.rend(); ++IterPos ) { cout << "유저코드: " << IterPos->CharCd << endl; cout << "유저레벨: " << IterPos->Level << endl; } cout << endl; // 배열 방식으로 접근 for( int i = 0; i < UserCount; ++i ) { cout << "유저 코드 : " << RoomUsers[i].CharCd << endl; cout << "유저 레벨 : " << RoomUsers[i].Level << endl; } cout << endl; // 첫 번째 유저 데이터 접근 RoomUser& FirstRoomUser = RoomUsers.front(); cout << "첫 번째 유저의 레벨 : " << FirstRoomUser.Level << endl << endl; RoomUser& LastRoomUser = RoomUsers.back(); cout << "마지막 번째 유저의 레벨: " << LastRoomUser.Level << endl << endl; // at을 사용하여 두 번째 유저의 레벨을 출력 RoomUser& RoomUserAt = RoomUsers.at(1); cout << "두 번째 유저의 레벨: " << RoomUserAt.Level << endl << endl; // 삭제 RoomUsers.pop_back(); UserCount = RoomUsers.size(); cout << "현재 방에 있는 유저 수: " << UserCount << endl << endl; // 아직 방에 유저가 있다면 모두 삭제한다. if( false == RoomUsers.empty() ) { RoomUsers.clear(); } UserCount = RoomUsers.size(); cout << "현재 방에 있는 유저 수: " << UserCount << endl; }
원형 : iterator insert( iterator _Where, const Type& _Val ); void insert( iterator _Where, size_type _Count, const Type& _Val ); templatevoid insert( iterator _Where, InputIterator _First, InputIterator _Last );
vector< int >::iterator iterInsertPos = vector1.begin(); vector1.insert( iterInsertPos, 100 );이 코드는 100을 첫 번째 위치에 삽입합니다. 두 번째 insert는 지정한 위치에 데이터를 횟수만큼 삽입합니다.
iterInsertPos = vector1.begin(); ++iterInsertPos; vector1.insert( iterInsertPos, 2, 200 );두 번째 위치에 200을 두 번 추가합니다. 세 번째 insert는 지정한 위치에 복사 할 vector의 (복사하기를 원하는 영역의)시작과 끝 반복자가 가리키는 영역의 모 든 요소를 삽입합니다.
vector< int > vector2; list2.push_back( 500 ); list2.push_back( 600 ); list2.push_back( 700 ); iterInsertPos = vector1.begin(); vector1.insert( ++iterInsertPos, vector2.begin(), vector2.end() );vector1의 두 번째 위치에 vector2의 모든 요소를 삽입합니다. 위에서 설명한 insert의 세 가지 방법을 사용한 전체 코드입니다. 참고로 이 예제는 이전 회의 list 의 insert에서 소개했던 코드와 같습니다. 오직 list 대신 vector를 사용했다는 것만 다릅니다.
void main() { vector< int > vector1; vector1.push_back(20); vector1.push_back(30); cout << "삽입 테스트 1" << endl; // 첫 번째 위치에 삽입한다. vector< int >::iterator iterInsertPos = vector1.begin(); vector1.insert( iterInsertPos, 100 ); // 100, 20, 30 순으로 출력한다. vector< int >::iterator iterEnd = vector1.end(); for(vector< int >::iterator iterPos = vector1.begin(); iterPos != iterEnd; ++iterPos ) { cout << "vector1 : " << *iterPos << endl; } cout << endl << "삽입 테스트 2" << endl; // 두 번째 위치에 200을 2개 삽입한다. iterInsertPos = vector1.begin(); ++iterInsertPos; vector1.insert( iterInsertPos, 2, 200 ); // 100, 200, 200, 20, 30 순으로 출력한다. iterEnd = vector1.end(); for(vector< int >::iterator iterPos = vector1.begin(); iterPos != iterEnd; ++iterPos ) { cout << "vector1 : " << *iterPos << endl; } cout << endl << "삽입 테스트 3" << endl; vector< int > vector2; vector2.push_back( 1000 ); vector2.push_back( 2000 ); vector2.push_back( 3000 ); // 두 번째 위치에 vecter2의 모든 데이터를 삽입한다. iterInsertPos = vector1.begin(); vector1.insert( ++iterInsertPos, vector2.begin(), vector2.end() ); // 100, 1000, 2000, 3000, 200, 200, 20, 30 순으로 출력한다. iterEnd = vector1.end(); for(vector< int >::iterator iterPos = vector1.begin(); iterPos != iterEnd; ++iterPos ) { cout << "vector1 : " << *iterPos << endl; } }결과
원형 : iterator erase( iterator _Where ); iterator erase( iterator _First, iterator _Last );
vector1.erase( vector1.begin() );두 번째 erase는 지정한 반복자 요소만큼 삭제합니다. 다음 코드는 vector1의 첫 번째 요소에서 마지막까지 모두 삭제합니다.
vector1.erase( vector1.begin(), vector1.end() );다음은 erase 사용을 보여주는 예제입니다.
void main() { vector< int > vector1; vector1.push_back(10); vector1.push_back(20); vector1.push_back(30); vector1.push_back(40); vector1.push_back(50); int Count = vector1.size(); for( int i = 0; i < Count; ++i ) { cout << "vector 1 : " << vector1[i] << endl; } cout << endl; cout << "erase 테스트 1" << endl; // 첫 번째 데이터 삭제 vector1.erase( vector1.begin() ); // 20, 30, 40, 50 출력 Count = vector1.size(); for( int i = 0; i < Count; ++i ) { cout << "vector 1 : " << vector1[i] << endl; } cout << endl << "erase 테스트" << endl; // 첫 번째 데이터에서 마지막까지 삭제한다. vector< int >::iterator iterPos = vector1.begin(); vector1.erase( iterPos, vector1.end() ); if( vector1.empty() ) { cout << "vector1에 아무 것도 없습니다" << endl; } }결과
원형 : void assign( size_type _Count, const Type& _Val ); templatevoid assign( InputIterator _First, InputIterator _Last );
vector1.assign( 7, 4 );두 번째 assign은 다른 vector의 반복자로 지정한 영역으로 채워줍니다.
vector1.erase( vector1.begin(), vector1.end() );다음은 assign을 사용법을 보여주는 예제입니다.
void main() { vector< int > vector1; // 4를 7개 채운다. vector1.assign( 7, 4 ); int Count = vector1.size(); for( int i = 0; i < Count; ++i ) { cout << "vector 1 : " << vector1[i] << endl; } cout << endl; vector< int > vector2; vector2.push_back(10); vector2.push_back(20); vector2.push_back(30); // vector2의 요소로 채운다 vector1.assign( vector2.begin(), vector2.end() ); Count = vector1.size(); for( int i = 0; i < Count; ++i ) { cout << "vector 1 : " << vector1[i] << endl; } cout << endl; }결과
원형 : void reserve( size_type _Count );
vector1.reserve( 10 );4.5.1.6 swap
원형 : void swap( vector& _Right ); friend void swap( vector & _Left, vector & _Right );
vector1.swap( vector2 );swap을 사용하는 예제입니다.
void main() { vector< int > vector1; vector1.push_back(1); vector1.push_back(2); vector1.push_back(3); vector< int > vector2; vector2.push_back(10); vector2.push_back(20); vector2.push_back(30); vector2.push_back(40); vector2.push_back(50); int Count = vector1.size(); for( int i = 0; i < Count; ++i ) { cout << "vector 1 : " << vector1[i] << endl; } cout << endl; Count = vector2.size(); for( int i = 0; i < Count; ++i ) { cout << "vector 2 : " << vector2[i] << endl; } cout << endl; cout << endl; cout << "vector1과vector2를swap" << endl; vector1.swap(vector2); Count = vector1.size(); for( int i = 0; i < Count; ++i ) { cout << "vector 1 : " << vector1[i] << endl; } cout << endl; Count = vector2.size(); for( int i = 0; i < Count; ++i ) { cout << "vector 2 : " << vector2[i] << endl; } }결과
// 유저 정보 struct UserInfo { char acUserName[21]; // 이름 int Level; // 레벨 int Exp; // 경험치 }; // 게임 방의 유저를 관리하는 클래스 // 방에는 최대 6명까지 들어 갈 수 있다. // 방에 들어 오는 순서 중 가장 먼저 들어 온 사람이 방장이 된다. class GameRoomUser { public: GameRoomUser(); ~GameRoomUser(); // 방에 유저 추가 bool AddUser( UserInfo& tUserInfo ); // 방에서 유저 삭제. // 만약 방장이 나가면 acMasterUserName에 새로운 방장의 이름을 설정 해야 된다. bool DelUser( char* pcUserName ); // 방에 유저가 없는 지조사. 없으면 true 반환 bool IsEmpty(); // 방에 유저가 꽉 찼는지 조사. 꽉 찼다면 true 반환 bool IsFull(); // 특정 유저의 정보 UserInfo& GetUserOfName( char* pcName ); // 방장의 유저 정보 UserInfo& GetMasterUser(); // 가장 마지막에 방에 들어 온 유저의 정보 UserInfo& GetUserOfLastOrder(); // 특정 순서에 들어 온 유저를 쫒아낸다. bool BanUser( int OrderNum ); // 모든 유저를 삭제한다. void Clear(); private: vector< UserInfo > Users; char acMasterUserName[21]; // 방장의 이름 };
이전 글 : 소프트웨어 개발에서 force multiplier는 무엇인가?
다음 글 : 컴포넌트 함께 사용하기
최신 콘텐츠