반응형

저번 시간은 map 컨테이너에 대해 알아보았다.

map은 key와 value를 함께 관리할 수 있는 연관 컨테이너였다.

단, key가 중복이 허용되지 않았다.

그럼 key를 중복으로 사용하고 싶다면 어떻게 해야할까?

그 해답인 multimap에 대해 알아보자.


1. multimap이란?

multimap은 map과 매우 유사한 연관 컨테이너이다.

균형 이진트리(중위순회)이며, key와 value의 쌍(pair)인 원소들의 집합으로 이루어져 있다.

multimap의 특징은 map과 달리 key값이 중복이 된다는 것이다.

key를 중복하여 사용하고자 할때 해당 컨테이너를 이용하면 프로그램을 유연하게 구현가능하므로 기억해두자.

 

map과 같이 원소 삽입시(insert) 자동 정렬되며, default 기준 오름차순정렬이다.

 

multimap을 사용하기 위해선 <map> 헤더파일을 include 해주어야하며(multimap이 아니다!!),

std::multimap<[key 데이터타입], [value 데이터타입]> [변수이름]; 형식으로 선언해 사용할 수 있다.

(using namespace std;로 std 생략하여 편하게 작성가능)

 

2. multimap - 생성자

multimap 생성자는 다음과 같이 사용 가능하다. 아래부터 key는 int, value는 char형이라 가정하고 작성하겠다.

  • multimap<int, char> mm;
    • 빈 multimap 컨테이너 mm을 생성
  • multimap<int, char, greater<int>> mm;
    • key를 내림차순으로 정렬하는 빈 multimap 컨테이너 mm을 생성
  • multimap<int, char> mm2(mm);
    • mm를 복사한 mm2 컨테이너 생성


3. multimap - 멤버 함수 및 접근 방식

다음은 multimap 멤버 함수와 접근 방식이다. (multimap<int, char> m 선언 기준)

 

- 멤버 함수

  • mm.begin();
    • mm의 맨 처음 원소를 가리키는 반복자 리턴
    • iterator = mm.begin();
  • mm.end();
    • mm의 마지막 원소를 가리키는 반복자 리턴
    • iterator = mm.end();
  • mm.clear();
    • mm의 모든 원소를 제거
  • mm.size(), mm.max_size();
    • mm의 원소 갯수를 반환
    • mm의 최대 사이즈 반환
  • mm.empty();
    • mm이 비어있는지 확인
  • mm.count(k);
    • mm에서 k(key) 원소의 갯수 반환
  • mm.insert(p), m.emplace(p);
    • mm에 p(pair)라는 객체 추가
    • insert 성공시 true 반환, key 이미 존재하여 실패한 경우는 false 반환
    • emplace로도 추가 가능
  • mm.insert(pair<int, char>(k, v)), m.emplace(pair<int, char>(k, v));
    • mm에 k(key), v(value) 값 삽입
    • insert 성공시 true 반환, key 이미 존재하여 실패한 경우는 false 반환
    • emplace로도 추가 가능
  • mm.erase(k);
    • mm에서 k(key) 값 해당 요소를 찾아 제거
  • mm.erase(start, end), mm.erase(iterator);
    • mm에서 start부터 end 범위 원소 모두 제거
    • iterator가 가리키는 key 제거
  • mm.find(k), mm.find(k)->second;
    • mm에서 k(key) 값을 찾아 반복자 형태로 반환
    • mm에서 k(key) 값을 찾아 value 출력
    • 못찾은경우 반복자 end 리턴
  • mm2.swap(mm);
    • mm과 mm2의 데이터를 바꿈
  • mm.upper_bound(k1), mm.lower_bound(k2);
    • k1(key) 값 해당되는 맨 마지막 원소의 다음을 가리키는 반복자 반환(폐구간 ")"로 사용)
    • k2(key) 값 해당하는 맨 첫번째 원소를 가리키는 반복자 반환(개구간 "["로 사용)
  • mm.equal_range(k);
    • k(key)이란 원소가 시작하는 구간과 끝나는 구간 반복자 pair 객체 반환
    • pair의 first는 lower_bound 반환값, second는 upper_bound 반환값
    • [ first, second )
  • mm.key_comp(), m.value_comp();
    • 정렬 기준 조건자 반환(key기준, value 기준 선택)

- 접근 방식

  • iterator를 통한 접근
    • multimap<int, char>::iterator mmit;
    • mmit->first(key), mmit->second(value) 형식으로 접근가능


4. multimap - 연산자

multimap의 연산자이다.

  • ==, != 
    • == : 두 multimap 컨테이너의 모든 원소가 같으면 참, 아니면 거짓
    • != : 두 multimap 컨테이너에서 하나라도 원소가 다르면 참, 아니면 거짓
  • <, >, <=, >=
    • multimap 컨테이너간 크기 비교


5. multimap 구조 및 실습

위에서 설명한 multimap의 구조는 균형 이진트리로 다음 그림과 같다.

계속해서 말하지만 key의 중복이 허용된다.



multimap 컨테이너를 이용하여 실습을 진행해보았다.

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

int main(void) {
	multimap<int, char> mm;
	multimap<int, char>::iterator mmit;
	mm.insert(pair<int, char>(1, 'a')); //insert key 1, value 'a'
	mm.insert(pair<int, char>(2, 'b')); //insert key 2, value 'b'
	mm.insert(pair<int, char>(3, 'c')); //insert key 3, value 'c'
	mm.insert(pair<int, char>(4, 'd')); //insert key 4, value 'd'
	mm.insert(pair<int, char>(3, 'e')); //insert key 3, value 'e' > Allow!

	for (mmit = mm.begin(); mmit != mm.end(); mmit++) {
		cout << "key값 : " << mmit->first; //iterator->first는 key
		cout << ", value값 : "<< mmit->second << endl; //iterator->second는 value
	}

	cout << "mm.erase(1) 수행" << endl;
	mm.erase(1); //key가 1인값 제거

	for (mmit = mm.begin(); mmit != mm.end(); mmit++) {
		cout << "key값 : " << mmit->first; //iterator->first는 key
		cout << ", value값 : " << mmit->second << endl; //iterator->second는 value
	}

	cout << "mm.size : " << mm.size() << endl; //크기
	cout << "mm.max_size : " << mm.max_size() << endl; //최대 사이즈
	cout << "mm.count(3) : " << mm.count(3) << "개" << endl; //key가 3인 원소 갯수
	cout << "mm.find(2)->second : " << mm.find(2)->second << endl; //key가 2인 원소 value
	cout << "mm.lower_bound(3) : "<< mm.lower_bound(3)->first << ", " << mm.lower_bound(3)->second << endl;
	cout << "mm.upper_bound(3) : " << mm.upper_bound(3)->first << ", " << mm.upper_bound(3)->second << endl;

	return 0;
}

실행결과는 다음과 같다.

 


여기까지 multimap과 동시에 stl 파트를 마친다. 다음시간엔 클래스에 대해 알아볼 예정이다.

반응형

'Programming > Language' 카테고리의 다른 글

[Assembly] 문자열 입력과 출력  (0) 2020.06.05
[Assembly] 1부터 10까지의 합 계산  (0) 2020.06.04
[C++] STL - map 공부  (0) 2020.05.14
[C++] STL - set 공부  (0) 2020.05.14
[C++] STL - stack 공부  (0) 2020.05.11
반응형

Canon 100D + EF-S 18-55mm


 

Canon 100D, EF-S 18-55mm F3.5-5.6 IS STM WHITE, 프라하 까를교
Canon 100D, EF-S 18-55mm F3.5-5.6 IS STM WHITE, 잘츠부르크 할슈타트
Canon 100D, EF-S 18-55mm F3.5-5.6 IS STM WHITE, 잘츠부르크 호엔잘츠부르크성
Canon 100D, EF-S 18-55mm F3.5-5.6 IS STM WHITE, 체스키 크롬로프
Canon 100D, EF-S 18-55mm F3.5-5.6 IS STM WHITE, 프라하 강변
Canon 100D, EF-S 18-55mm F3.5-5.6 IS STM WHITE, 체스키 크롬로프 크리스마스 공연
Canon 100D, EF-S 18-55mm F3.5-5.6 IS STM WHITE, 체코 지하철역

 

반응형

'Interesting > Pictures' 카테고리의 다른 글

Canon 100D + EF-S 18-55mm - 2  (0) 2020.05.24
반응형

저번 시간은 set 컨테이너에 대해 알아보았다.

set은 key만을 관리하는데 key와 value를 함께 관리할 수 있는 연관 컨테이너가 있다.

바로 map 컨테이너이다. 오늘은 map 컨테이너에 대해 알아보자.


1. map이란?

map은 set과 같은 연관 컨테이너로 노드 기반 컨테이너이다.

map 역시 균형 이진트리(중위순회)로 이루어져 있으며, key와 value의 쌍(pair)인 원소들의 집합으로 이루어져 있다.

여기서 key는 중복이 허용되지 않으며 중복을 허용하기 위해선 multimap을 사용하여야 한다.

 

원소 삽입시(insert) 자동 정렬되며, default 기준 오름차순정렬이다.

 

map을 사용하기 위해선 <map> 헤더파일을 include 해주어야하며,

std::map<[key 데이터타입], [value 데이터타입], [정렬 기준 조건자]> [변수이름]; 형식으로 선언해 사용할 수 있다.

정렬 기준 조건자는 greater<key 데이터타입> 형태로 선언하여 내림차순으로 변경가능하며, 생략 역시 가능하다.

(using namespace std;로 std 생략하여 편하게 작성가능)

 

 

2. map - 생성자

map 생성자는 다음과 같이 사용 가능하다. 아래부터 key는 int, value는 char형이라 가정하고 작성하겠다.

  • map<int, char> m;
    • 빈 map 컨테이너 m을 생성
  • map<int, char, greater<int>> m;
    • key를 내림차순으로 정렬하는 빈 map 컨테이너 m을 생성
  • map<int, char> m2(m);
    • m를 복사한 m2 컨테이너 생성


3. map - 멤버 함수 및 접근 방식

다음은 map 멤버 함수와 접근 방식이다. (map<int, char> m 선언 기준)

 

- 멤버 함수

  • m.begin();
    • m의 맨 처음 원소를 가리키는 반복자 리턴
    • iterator = m.begin();
  • m.end();
    • m의 마지막 원소를 가리키는 반복자 리턴
    • iterator = m.end();
  • m.clear();
    • m의 모든 원소를 제거
  • m.size(), m.max_size();
    • m의 원소 갯수를 반환
    • m의 최대 사이즈 반환
  • m.empty();
    • m이 비어있는지 확인
  • m.count(k);
    • m에서 k(key) 원소의 갯수 반환(중복안되므로 0 or 1)
  • m[k] = v;
    • m에 k(key)에 v(value)값 삽입
    • key 값 존재하는 경우 value 값 갱신, key 없는 경우엔 추가
  • m.insert(p), m.emplace(p);
    • m에 p(pair)라는 객체 추가
    • insert 성공시 true 반환, key 이미 존재하여 실패한 경우는 false 반환
    • emplace로도 추가 가능
  • m.insert(pair(k, v)), m.emplace(pair(k, v));
    • m에 k(key), v(value) 값 삽입
    • insert 성공시 true 반환, key 이미 존재하여 실패한 경우는 false 반환
    • emplace로도 추가 가능
  • m.insert(iterator, k);
    • m에서 iterator가 가리키는 위치부터 k(key)를 삽입할 위치 탐색하여 삽입(균형 이진트리)
  • m.erase(k);
    • m에서 k(key) 값 해당 요소를 찾아 제거
  • m.erase(start, end);
    • m에서 start부터 end 범위 원소 모두 제거
  • m.find(k);
    • m에서 k(key) 값을 찾아 반복자 형태로 반환
    • 못찾은경우 반복자 end 리턴
  • m2.swap(m);
    • m과 m2의 데이터를 바꿈
  • m.upper_bound(k1), m.lower_bound(k2);
    • k1(key)란 원소가 끝나는 구간 반복자
    • k2(key)란 원소가 시작하는 구간 반복자
  • m.equal_range(k);
    • k(key)이란 원소가 시작하는 구간과 끝나느 구간 반복자 pair 객체 반환
  • m.key_comp(), m.value_comp();
    • 정렬 기준 조건자 반환(key기준, value 기준 선택)

- 접근 방식

  • iterator를 통한 접근
    • map<int, char>::iterator mit;
    • mit->first(key), mit->second(value) 형식으로 접근가능
  • index 요소를 통한 접근
    • m[k](value) 형식 접근가능


4. map - 연산자

map의 연산자이다.

  • ==, != 
    • == : 두 map 컨테이너의 모든 원소가 같으면 참, 아니면 거짓
    • != : 두 map 컨테이너에서 하나라도 원소가 다르면 참, 아니면 거짓
  • <, >, <=, >=
    • map 컨테이너간 크기 비교


5. map 구조 및 실습

위에서 설명한 map의 구조는 균형 이진트리로 다음 그림과 같다.



map 컨테이너를 이용하여 실습을 진행해보았다.

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

int main(void) {
	map<int, char> m;
	map<int, char>::iterator mit;
	m.insert(make_pair(3,'k')); //m에 3이란 key와, 'k'란 value 삽입
	m.insert(make_pair(1,'c')); //m에 1이란 key와, 'c'란 value 삽입
	m.insert(make_pair(2,'y')); //m에 2이란 key와, 'y'란 value 삽입

	cout << m[1] << endl; //첫번째 접근 방법

	mit = m.begin();
	cout << mit->first << ":" << mit->second << "\n" << endl; //두번째 접근 방법

	for (mit = m.begin(); mit != m.end(); mit++) {
		cout << mit->first << ":" << mit->second << endl; //모든 원소 key, value 출력
	}

	mit = m.find(3); //3이란 key 탐색
	if (mit != m.end()) { //m.end()가 아니면 출력 (find해서 없으면 m.end()반환하므로)
		cout << "\n 3이란 key를 찾았습니다. value 값은 " << mit->second << "입니다." << endl;
	}
	else {
		cout << "\n 3이란 key를 찾지 못했습니다." << endl;
	}
	return 0;
}

실행결과는 다음과 같다.


여기까지 map 공부를 마친다. 계속해서 stl에 대해 알아가볼 예정이다.

반응형

'Programming > Language' 카테고리의 다른 글

[Assembly] 1부터 10까지의 합 계산  (0) 2020.06.04
[C++] STL - multimap 공부  (0) 2020.05.24
[C++] STL - set 공부  (0) 2020.05.14
[C++] STL - stack 공부  (0) 2020.05.11
[C++] STL - list 공부  (0) 2020.05.07
반응형

이번 시간부터는 연관 컨테이너에 대해 알아보겠다.

연관 컨테이너는 일정 규칙에 따라 조직화하여 자료를 정렬하고 처리하는 컨테이너이다.

여기서 오늘 set 컨테이너에 대해 다뤄보려고 한다.


1. set이란?

set은 연관 컨테이너로 노드 기반 컨테이너이다.

균형 이진트리(중위순회)로 이루어져 있으며, key라고 하는 원소들의 집합으로 이루어져 있다.

여기서 key는 중복이 허용되지 않으며 중복이되는 key는 multiset으로 추후 설명할 예정이다.

 

원소 삽입시(insert) 자동 정렬되며, default 기준 오름차순정렬이다.

 

set을 사용하기 위해선 <set> 헤더파일을 include 해주어야하며,

std::set<[데이터타입]> [변수이름]; 형식으로 선언해 사용할 수 있다.

(using namespace std;로 std 생략하여 편하게 작성가능)

 

2. set - 생성자

set 생성자는 다음과 같이 사용 가능하다. 아래부터 데이터타입이 int라고 가정하고 작성하겠다.

  • set<int> s;
    • 빈 set 컨테이너 s 생성
  • set<int> s(predicate);
    • predicate 정렬 기준으로 빈 s 컨테이너 생성
  • set<int> s2(s);
    • s를 복사한 s2 컨테이너 생성

3. set - 멤버 함수

다음은 set 멤버 함수이다. (set<int> s 선언 기준)

 

- 멤버 함수

  • s.begin();
    • s의 맨 처음 원소를 가리키는 반복자 리턴
    • iterator = s.begin();
  • s.end();
    • s의 마지막 원소를 가리키는 반복자 리턴
    • iterator = s.end();
  • s.clear();
    • s의 모든 원소를 제거
  • s.size(), s.max_size();
    • s의 원소 갯수를 반환
    • s의 최대 사이즈 반환
  • s.empty();
    • s가 비어있는지 확인
  • s.count(3);
    • s에서 3이란 원소의 갯수 반환(중복안되므로 0 or 1)
  • s.insert(6);
    • s에 6이란 원소 삽입(자동 정렬)
    • 삽입 성공시 리턴값 pair<iterator, bool>에 pair.second 값으로 true, 삽입 실패시 false가 나옴(pair.first는 삽입한 원소 가리키는 반복자)
  • s.insert(iterator, 5);
    • s에서 iterator가 가리키는 위치부터 5를 삽입할 위치 탐색하여 삽입(균형 이진트리)
  • s.erase(iterator);
    • s에서 iterator가 가리키는 원소를 제거하고 다음 원소 가리키는 반복자 리턴
  • s.erase(start, end);
    • s에서 start부터 end 범위 원소 모두 제거
  • s.find(3);
    • s에서 3이란 원소 찾아 가리키는 반복자 반환, 없으면 s.end() 반환
  • s2.swap(s);
    • s와 s2 서로 데이터를 바꾼다.
  • s.upper_bound(4), s.lower_bound(5);
    • 4란 원소가 끝나는 구간 반복자
    • 5란 원소가 시작하는 구간 반복자
  • s.equal_range(3);
    • 3이란 원소가 시작하는 구간과 끝나느 구간 반복자 pair 객체 반환
  • s.key_comp(), s.value_comp();
    • 정렬 기준 조건자 반환(set에선 둘이 같음)

4. set - 연산자

set의 연산자이다.

  • ==, != 
    • == : 두 set 컨테이너의 모든 원소가 같으면 참, 아니면 거짓
    • != : 두 set 컨테이너에서 하나라도 원소가 다르면 참, 아니면 거짓
  • <, >, <=, >=
    • set 컨테이너간 크기 비교


5. set 구조 및 실습

위에서 설명한 set의 구조는 균형 이진트리로 다음 그림과 같다.



set 컨테이너를 이용하여 실습을 진행해보았다.

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

int main(void) {
	set<int> s;
	set<int>::iterator sit;
	s.insert(3); cout << "3 원소 추가!" << endl;
	s.insert(7); cout << "7 원소 추가!" << endl;
	s.insert(2); cout << "2 원소 추가!" << endl;
	
	sit = s.begin();
	s.insert(sit, 6);
	cout << "s.begin()부터 탐색하여 6 원소 추가! \n" << endl;
	
	cout << "==========원소출력==========" << endl;
	for (sit = s.begin(); sit != s.end(); sit++) {
		cout << *sit << endl;
	}
	cout << "============================\n" << endl;

	s.erase(7); cout << "7 원소 삭제!" << endl;
	//s.erase(s.begin(), s.end()); // 모든 원소 삭제

	sit = s.upper_bound(3); cout << "3 원소 끝나는 구간에 반복자 지정" << endl;
	cout << "반복자가 가리키는 원소 : " << *sit << "\n" << endl;

	sit = s.find(6); cout << "6이라는 원소 찾기" << endl;
	if (sit != s.end()) {
		cout << *sit << " 원소가 존재 합니다." << endl;
	}
	else {
		cout << "해당 원소를 찾지 못했습니다." << endl;
	}
	
	return 0;
}

실행결과는 다음과 같다.


여기까지 set 공부를 마친다. 다음 시간엔 map에 대하여 알아보는 시간을 갖겠다.

반응형

'Programming > Language' 카테고리의 다른 글

[C++] STL - multimap 공부  (0) 2020.05.24
[C++] STL - map 공부  (0) 2020.05.14
[C++] STL - stack 공부  (0) 2020.05.11
[C++] STL - list 공부  (0) 2020.05.07
[C++] STL - vector 공부  (0) 2020.05.06
반응형

지난 시간에 STL의 시퀸스 컨테이너중 하나인 list에 대해 알아보았다.

연관 컨테이너로 넘어가기 전에 어댑터 컨테이너에 있는 몇몇 컨테이너들을 짚고 넘어가려고 한다.

이번 시간은 stack 컨테이너를 공부해볼 예정이다.


1. stack이란?

stack은 어댑터 컨테이너 중 하나로 vector, deque, list 구조와 같은 시퀸스 컨테이너를 변형한 것이다.

LIFO(Last In First Out) 방식이며 default로 deque 컨테이너를 기반으로 작동한다.

 

이를 사용하기 위해서 C언어에선 PUSH, POP과 같은 함수를 직접 만들어줘야하지만 C++에선 STL이 해결해준다.

<stack> 헤더파일을 include 해주어야하며,

std::stack<[데이터타입]> [변수이름]; 형식으로 선언해 사용할 수 있다.

(using namespace std;로 std 생략하여 편하게 작성가능)

 

*내부 컨테이너를 바꾸고 싶으면 std::stack<[데이터타입], [컨테이너타입]> [변수이름]; 형태로 선언하여 사용 가능하다.



2. stack - 생성자

stack 생성자는 다음과 같이 사용 가능하다. 아래부터 데이터타입이 int라고 가정하고 작성하겠다.

  • stack<int> stk;
    • 빈 stack 컨테이너 stk 생성(내부컨테이너 deque)
  • stack<int, vector<int>> stk;
    • 빈 stack 컨테이너 stk 생성(내부컨테이너 vector(int))


3. stack - 멤버 함수

다음은 stack 멤버 함수이다.

 

- 멤버 함수

  • stk.push(3);
    • stk에 3이란 데이터 삽입
  • stk.pop();
    • stk의 top이 가리키는 원소를 삭제
  • stk.top();
    • 맨위에 있는 데이터를 반환
  • stk.empty();
    • stk이 비어있는지 확인
  • stk.size();
    • stk의 사이즈 반환
  • stk.emplace(args);
    • C++11부터 지원
    • 특정 클래스의 stack이면 해당 인자를 해당 클래스 생성자로 넘겨 해당 클래스 객체 생성하여 Stack에 Push
  • stk.swap(stk2);
    • C++11부터 지원 
    • stk과 stk2의 데이터를 서로 바꿈


  •  

4. stack - 연산자

stack의 연산자이다.

  • ==, != 
    • == : 두 stack 컨테이너의 모든 원소가 같으면 참, 아니면 거짓
    • != : 두 stack 컨테이너에서 하나라도 원소가 다르면 참, 아니면 거짓
  • <, >, <=, >=
    • stack 컨테이너간 크기 비교


5. stack 구조 및 실습

위에서 설명한 stack의 구조는 다음 그림과 같다.



실습을 진행해보았다. stack 컨테이너를 이용해 원소를 추가, 삭제해보며 실습해보았다.

 

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

int main(void) {
	stack<int> stk;
	stk.push(10); cout << "stk 10 push" << endl;
	stk.push(20); cout << "stk 20 push" << endl;
	stk.push(30); cout << "stk 30 push" << endl;
	
	cout << "stk의 맨위 데이터 : " << stk.top() << endl;
	cout << "stk의 사이즈 : " << stk.size() << endl;
	cout << "stk이 비어있는가 : " << stk.empty() << endl;

	stk.pop(); cout << "stk pop > 30 out" << endl;
	stk.pop(); cout << "stk pop > 20 out" << endl;
	
	cout << "stk의 맨위 데이터 : " << stk.top() << endl;

	stk.pop(); cout << "stk pop > 10 out" << endl;

	cout << "stk의 사이즈 : " << stk.size() << endl;
	cout << "stk이 비어있는가 : " << stk.empty() << endl;
	return 0;
}

 

실행결과는 다음과 같다.

 


여기까지 stack 공부를 마친다. 슬슬 연관 컨테이너에 대해 공부해볼 계획이다.

반응형

'Programming > Language' 카테고리의 다른 글

[C++] STL - map 공부  (0) 2020.05.14
[C++] STL - set 공부  (0) 2020.05.14
[C++] STL - list 공부  (0) 2020.05.07
[C++] STL - vector 공부  (0) 2020.05.06
[C++] STL(Standard Template Library) 시작  (0) 2020.05.05
반응형

지난 시간에 STL의 vector에 대해 알아보았다.

이번시간은 STL 시퀸스 컨테이너 중 이중연결리스트구조인 list에 대해 공부해보려한다.


1. list란?

list는 시퀸스 컨테이너 중 하나로 노드 기반 컨테이너이다.

구조는 doubly linked list 구조로 말그대로 이중 연결 리스트이다.

 

list는 vector, deque와 달리 노드 기반으로 서로 연결이 되어있어서 원소를 삽입하거나 삭제하고자할 때 모든 원소를 밀어내지 않기때문에 상수 시간복잡도를 갖아 속도가 빠르다.

또, 삽입과 삭제시 반복자가 가리키고있는 원소 자체를 삭제해야 원소가 사라지며, 동작자체에서 반복자를 무효화시키지 않는다.

 

이외에도 sort(), splice(), merge() 함수 등 list 정렬, 결합 혹은 사용시 유용한 멤버 함수들을 많이 제공한다.

 

list를 사용하기 위해선 <list> 헤더파일을 include 해주어야하며,

std::list<[데이터타입]> [변수이름] 형식으로 선언해 사용할 수 있다.

(using namespace std;로 std 생략하여 편하게 작성가능)



2. list - 생성자

list 생성자는 다음과 같이 사용 가능하다. 아래부터 데이터타입이 int라고 가정하고 작성하겠다.

  • list<int>lst;
    • 빈 list 컨테이너 lst을 생성
  • list<int>lst(3);
    • 3개의 원소를 갖는 lst을 생성(기본값 초기화)
  • list<int> lst(3, 4);
    • 4로 초기화된 3개의 원소를 갖는 lst을 생성
  • list<int> lst2(lst);
    • lst 컨테이너를 복사한 lst2를 생성


3. list - 멤버 함수, 멤버 형식

다음은 lst 멤버 함수와 멤버 형식이다. 이번 역시 대표적인 몇몇개를 정리해보았다.

 

- 멤버 함수

  • lst.assign(2, 3);
    • lst에서 3이란 값으로 2개의 원소를 할당
  • lst.front();
    • lst의 첫번째 원소를 참조
  • lst.back();
    • lst의 마지막 원소를 참조
  • lst.clear();
    • lst의 모든 원소를 제거하며 메모리는 그대로 내비둠
  • lst.push_front(3);
    • lst 앞에 3 원소를 push
  • lst.push_back(5);
    • lst 끝에 5란 원소를 push
  • lst.pop_front();
    • lst 첫번째 원소를 pop
  • lst.pop_back();
    • lst 마지막 원소를 pop
  • lst.insert(iterator, 4); lst.insert(iterator, 4, 2);
    • lst의 iterator이 가리키는 위치에 4란 값 삽입
    • lst의 iterator이 가리키는 위치에 4개의 2란 값 삽입
  • lst.erase(iterator)
    • iterator가 가리키고 있는 원소를 제거, 다음 원소 가리킴(반환)
  • lst.clear();
    • lst의 모든 원소를 제거
  • lst.begin();
    • lst의 첫번째 원소를 가리킴
    • iterator와 같이 사용
  • lst.end();
    • lst의 끝을 가리킴
    • iterator와 같이 사용
  • lst.size();
    • lst의 원소 갯수 참조
  • lst.empty();
    • lst의 size가 0이면 참, 0보다 크면 거짓
  • lst.swap(lst2);
    • lst1와 lst2의 원소와 할당된 메모리를 맞바꿈
  • lst.merge(lst2), lst.merge(lst2,predicate);
    • lst2를 lst로 합병하여 정렬
    • lst2를 조건자를 통해 lst로 합병하여 정렬
  • lst.remove(3), lst.remove_if(predicate);
    • 3 원소를 모두 제거
    • 단항 조건자가 참인 모든 원소를 제거
  • lst.sort(), lst.sort(predicate);
    • lst의 모든 원소를 오름차순 정렬
    • lst의 모든 원소를 조건자 기준으로 정렬
  • lst.splice(iterator, lst2);
    • iterator가 가르키는 곳에 lst2 모든 원소를 잘라 넣는다.
  • lst.unique(), lst.unique(pred);
    • 입접한 원소의 값이 같다면 유일한 원소 순차열로 만듦
    • 인접한 원소가 이항 조건자 기준에 맞으면 유일한 원소 순차열로 만듦

 

- 멤버 형식

  • allocator_type
    • 메모리 관리자
  • iterator
    • 반복자
  • pointer
    • value_type *
  • refernce
    • value_type &
  • reverse_iterator
    • 역 반복자
  • size_type
    • 인덱스, 원소 갯수 등
  • value_type
    • 원소 형식


4. list - 연산자

list의 연산자이다.

  • ==, != 
    • == : 두 list 컨테이너의 모든 원소가 같으면 참, 아니면 거짓
    • != : 두 list 컨테이너에서 하나라도 원소가 다르면 참, 아니면 거짓
  • <, >, <=, >=
    • list 컨테이너간 크기 비교


5. list 구조 및 실습

위에서 설명한 list의 구조는 다음 그림과 같다.



실습을 진행해보았다. list 컨테이너를 이용해 원소를 추가, 삭제해보고 다양한 멤버 함수를 사용해보았다.

 

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

int main(void) {
	list<int> lst; //빈 list 컨테이너 lst 생성
	list<int>::iterator lstit; //연산자 선언
	lst.push_back(30); //lst 뒤에 30 push > 30
	lst.push_back(20); //lst 뒤에 20 push > 30, 20
	lst.push_back(40); //lst 뒤에 40 push > 30, 20, 40
	lst.push_front(10); //lst 앞에 10 push > 10, 30, 20, 40
	cout << "lst > push_front, push_back" << endl;
	for (lstit = lst.begin(); lstit != lst.end(); lstit++) { //lst begin부터 end까지 출력
		cout << *lstit << endl; 
	}
	cout << "lst > pop_front, pop_back" << endl;
	lst.pop_back(); //lst 맨뒤 원소 pop
	lst.pop_front(); //lst 첫번째 원소 pop
	for (lstit = lst.begin(); lstit != lst.end(); lstit++) {
		cout << *lstit << endl;
	}
	cout << "lst2 > lst복사하여 컨테이너 생성" << endl;
	list<int> lst2(lst); //lst복사하여 lst2 컨테이너 생성
	for (lstit = lst2.begin(); lstit != lst2.end(); lstit++) {
		cout << *lstit << endl;
	}
	cout << "lst2 > sort 정렬" << endl;
	lst2.sort(); //lst2 오름차순 정렬
	for (lstit = lst2.begin(); lstit != lst2.end(); lstit++) {
		cout << *lstit << endl;
	}
	cout << "lst2 > iterator가 가리키고있는 위치에 lst 값 잘라붙여넣기" << endl;
	lst2.splice(lstit, lst); //lterator 가리키는 위치에 lst 값 잘라붙여넣기
	for (lstit = lst2.begin(); lstit != lst2.end(); lstit++) {
		cout << *lstit << endl;
	}
	return 0;
}

실행결과는 다음과 같다.


여기까지 list 공부를 마친다. 이와같이 시퀸스 컨테이너 포스팅을 계속하여 진행하겠다.

반응형

'Programming > Language' 카테고리의 다른 글

[C++] STL - set 공부  (0) 2020.05.14
[C++] STL - stack 공부  (0) 2020.05.11
[C++] STL - vector 공부  (0) 2020.05.06
[C++] STL(Standard Template Library) 시작  (0) 2020.05.05
[C++] 템플릿(Template) 공부  (0) 2020.05.04
반응형

지난 시간에 STL에 대해 알아보았다.

이번시간은 STL 시퀸스 컨테이너 중 많이 활용되는 vector에 대해 공부해보려한다.

긴말필요없이 시작해보자. :)


1. vector란?

vector란 시퀸스 컨테이너 중 하나로 '메모리가 동적으로 할당되는 배열'이다.

이를 이용하여 C++에서 동적 배열을 쉽게 구현할 수 있다.

 

vector는 원소를 저장할 때 메모리에 연속적으로 저장되며, 이로인한 장점과 단점이 존재한다.

순차적이라 임의 접근시 속도는 빠른편이나, 원소를 삽입하거나 제거할때 모든 원소를 옮기는 과정을 거치다보니 속도가 느릴수있다.

 

vector를 사용하기 위해선 <vector> 헤더파일을 include 해주어야하며,

std::vector<[데이터타입]> [변수이름] 형식으로 선언해 사용할 수 있다.

(using namespace std;로 std 생략하여 편하게 작성가능)

 

2. vector - 생성자

vector 생성자는 다음과 같이 사용 가능하다.

  • vector<int> vec
    • 빈 vector 컨테이너 vec을 생성
  • vector<int> vec(3);
    • 3개의 원소를 갖는 vec을 생성(기본값 초기화)
  • vector<int> vec(3, 4);
    • 4로 초기화된 3개의 원소를 갖는 vec을 생성
  • vector<int> vec2(vec);
    • vec 컨테이너를 복사한 vec2를 생성


3. vector - 멤버 함수, 멤버 형식

다음은 vector 멤버 함수와 멤버 형식이다.

대표적인 몇몇개를 정리해보았으며 데이터타입이 int라고 가정하고 작성하겠다.

 

- 멤버 함수

  • vec.assign(2, 3);
    • vec에서 3이란 값으로 2개의 원소를 할당
  • vec.at(3);
    • vec의 3번 인덱스를 참조(범위 점검 > 안전함)
  • vec[3];
    • vec의 3번 인덱스를 참조(범위 점검 X > 속도빠름)
  • vec.front();
    • vec의 첫번째 원소를 참조
  • vec.back();
    • vec의 마지막 원소를 참조
  • vec.clear();
    • vec의 모든 원소를 제거하며 메모리는 그대로 내비둠
  • vec.push_back(5);
    • vec에 5란 원소를 push(추가)
  • vec.pop_push();
    • vec에 마지막 원소를 pop(제거)
  • vec.insert(3, 4); vec.insert(3, 4, 2);
    • vec의 3번 인덱스에 4란 값 삽입
    • vec의 3번 인덱스부터 4개의 2란 값 삽입(밀림)
  • vec.erase(iterator)
    • iterator가 가리키고 있는 원소를 제거
    • size는 줄지만 할당된 메모리는 그대로
  • vec.clear();
    • vec의 모든 원소를 제거
    • size는 0이되며 할당된 메모리는 그대로
  • vec.begin();
    • vec의 첫번째 원소를 가리킴
    • iterator와 같이 사용
  • vec.end();
    • vec의 마지막 다음 주소를 가리킴
    • iterator와 같이 사용
  • vec.size();
    • vec의 원소 갯수 참조
  • vec.capacity();
    • vec이 할당된 공간 크기 리턴
    • 기존 메모리의 2배씩 증가하게 되며, 미리 정해둔 만큼 한번에 동적할당을 해두어 효율을 높이는 것이 목적
    • 원소갯수 = 1 -> capacity = 1, 2 -> 2, 3 -> 4, 4 -> 4, 5 -> 8...
  • vec.empty();
    • vec의 size가 0이면 참, 0보다 크면 거짓
  • vec.swap(vec2);
    • vec1와 vec2의 원소와 할당된 메모리를 맞바꿈
    • vector<int>().swap(vec); 형태로 할당된 메모리가 0인 임시 객체를 만들어 vec capacity 없앨때 사용 가능

- 멤버 형식

  • allocator_type
    • 메모리 관리자
  • iterator
    • 반복자
  • pointer
    • value_type *
  • refernce
    • value_type &
  • reverse_iterator
    • 역 반복자
  • size_type
    • 인덱스, 원소 갯수 등
  • value_type
    • 원소 형식


4. vector - 연산자

마지막은 vector의 연산자이다.

  • ==, != 
    • == : 두 vector 컨테이너의 모든 원소가 같으면 참, 아니면 거짓
    • != : 두 vector 컨테이너에서 하나라도 원소가 다르면 참, 아니면 거짓
  • <, >, <=, >=
    • vector 컨테이너간 크기 비교



5. vector 구조 및 실습

위에서 설명한 vector의 구조는 다음 그림과 같다.



실습은 지난 vector 실습 소스를 수정하여 진행할 예정이다.

 

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

int main(void) {
	vector<int> vec; //빈 컨테이너 vec 생성
	vector<int>::iterator vecit;
	vec.assign(1, 10); //비어있는 vec에 10이란 값을 1개 원소 부여
	cout << "vec.at(0) : " << vec.at(0) << endl; //vec의 0번 인덱스 참조(범위점검O)
	cout << "vec[0] : " << vec[0] << endl; //vec의 0번 인덱스 참조(범위점검X)
	vec.push_back(20); //vec에 20 push
	vec.push_back(30); //vec에 30 push
	vec.push_back(40); //vec에 40 push
	cout << "vec의 첫번째 원소 " << vec.front() << endl;
	cout << "vec의 마지막 원소 " << vec.back() << endl;
	cout << "vec의 사이즈 " << vec.size() << endl;
	cout << "vec의 할당된 메모리 " << vec.capacity() << endl;
	
	for (vecit = vec.begin(); vecit != vec.end(); vecit++) { //연산자로 vec의 begin부터 end까지 출력
		cout << *vecit << endl; //참조하는 값 출력
	}
	
	vector<int> vec2(vec); //vec를 복사한 vec2 생성
	cout << "vec2.at(0) : " << vec2.at(0) << endl; //vec2의 0번 인덱스 참조(범위점검O)
	cout << "vec2[0] : " << vec2[0] << endl; //vec2의 0번 인덱스 참조(범위점검X)
	for (vecit = vec2.begin(); vecit != vec2.end(); vecit++) { //연산자로 vec2의 begin부터 end까지 출력
		cout << *vecit << endl; //참조하는 값 출력
	}
	cout << "vec2이 비어있는가? "<< vec2.empty() << endl; //vec2는 안비어있으므로 0
	cout << "vec2.clear 수행" << endl;
	vec2.clear(); //모든 원소 지움
	cout << "vec2이 비어있는가? " << vec2.empty() << endl; //vec2 원소는 모두 비어있으므로 1
	cout << "vec2의 사이즈 " << vec2.size() << endl; //모두 비어있기때문에 0
	cout << "vec2의 할당된 메모리 " << vec2.capacity() << endl; //clear해도 할당된 크기는 그대로
	cout << "vector<int>().swap(vec2) 수행" << endl;
	vector<int>().swap(vec2); //임시객체를 만들어 swap하며 vec2의 메모리 초기화
	cout << "vec2의 할당된 메모리 " << vec2.capacity() << endl; //clear해도 할당된 크기는 그대로
	return 0;
}

실행결과는 다음과 같다.


여기까지 vector 공부를 마친다. 이와같이 당분간 시퀸스 컨테이너 포스팅을 진행할 예정이다.

반응형
반응형

C++언어에서 빼놓을 수 없는 부분이있다. 바로 STL(Standard Template Library)이다.

매우 다양한 부분에서 STL을 이용할 수 있으며 이는 개발 능률과 바로 연결되므로 매우 유용하다고 볼 수 있다.

오늘부터 몇일간 STL에 있는 컨테이너에 대해 하나하나 공부할 계획이다.


1. STL(Standard Template Library)?

STL이란 '표준 C++ 라이브러리'이다. 프로그램에 필요한 자료구조 및 알고리즘을 템플릿으로 제공한다.

 

STL의 구성요소는 여러가지가 있다.

  • 컨테이너(Container)
  • 반복자(Iterator)
  • 알고리즘(Algorithm)
  • 함수 오브젝트(Function Object) 등

자료들은 컨테이너에 있고 알고리즘은 하나의 수단이다. 이에 접근하기 위해선 반복자를 사용한다고 보면 된다.

이 구성요소를 크게 두개로 나누자면 컨테이너와 알고리즘으로 나눌 수도 있다.

그만큼 STL에서 중요한 요소인데 하나하나 살펴보도록하자.

 

 

2. STL - 컨테이너

STL 컨테이너는 객체(기본자료형과 사용자 정의 자료형)를 저장하는 자료구조이다.

클래스 템플릿으로 되어있으며 일반적으로 다음과 같이 나뉜다.

아래 컨테이너들의 자세한 내용에 대해선 추후 포스팅 해나갈 예정이다.

 

- 시퀀스 컨테이너(Sequence Container) : 일반적인 자료구조와 동일하며, 순차적으로 저장

  • array : 배열
  • vector : 동적 배열
  • deque : 양방향 큐
  • forward_list : 단방향 리스트
  • list : 양방향 리스트

 

- 연관 컨테이너(Associative Container) : 일정규칙에 따라 조직화하여 자료를 정렬, 처리

  • set : 중복아닌 key 집합
  • map : 중복아닌 key, value 집합
  • multiset : 중복되는 key 집합
  • multimap : 중복되는 key, value의 집합

 

- 어댑터 컨테이너(Adepter Container) : 시퀀스 컨테이너를 변형하여 다음과 같이 저장

  • stack : 스택
  • queue : 큐
  • priority_queue : 우선순위 큐


3. STL - 알고리즘

STL 알고리즘은 정렬과 같은 개발시 사용되는 기능을 함수 템플릿으로 만들어둔 것이다.

종류가 매우 다양하며 함수 몇몇개를 정리해보았다.

 

  • sort() 알고리즘 : 지정된 정렬 기준에 따라 구간 요소들을 정렬
  • find() 알고리즘 : 주어진 값에 일치하는 첫번째 요소 반환
  • binary_search() 알고리즘 : 정렬된 컨테이너에 대한 이진 탐색 수행
  • max() 알고리즘 : 두 객체 비교하여 큰 값 반환
  • min() 알고리즘 : 두 객체 비교하여 작은 값 반환
  • replace() 알고리즘 : 지정된 범위 내에 특정 값을 갖는 원소를 찾아 값을 변경


4. STL 반복자

STL 반복자를 사용하여 컨테이너에 저장되어있는 원소들을 접근할 수 있다.

컨테이너와 알고리즘이 함께 동작하도록 만들어주는 역할을 한다. 몇몇가지 연산들을 살펴보겠다.

 

  • begin() 연산자 : 컨테이너에서 첫번째 요소를 반환
  • end() 연산자 : 컨테이너의 끝을 표시하는 원소를 반환(마지막의 다음 주소를 가진다.)
  • ++, -- 연산자 : ++는 컨테이너에서 다음 요소를 가리킴, --는 이전 요소를 가리킴
  • !=, == 연산자 : !=, ==는 두개의 반복자가 같은 요소 가리키는지 확인
  • * 연산자 : 반복자가 가리키는 요소의 값을 보여주는(역참조) 연산자


5. 실습

위 시퀸스 컨테이너중 하나인 vector와 연산자를 이용하여 실습을 진행한다.

 

vector는 뒷 포스팅에서 설명하겠지만 가변적인 배열을 사용하기 위해 사용한다.

순차적이기때문에 읽는 것은 빠르지만 배열 길이가 길어질수록 데이터 처리 속도가 느려진다는 단점이있다.

 

이제 vector를 이용하여 원소를 push, pop하고 연산자를 이용하여 출력하는 것을 실습해보자(주석 참고).

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

int main(void) {
	vector<int> vec; //동적 배열 vector
	vec.push_back(1); //vector에 1 push
	vec.push_back(2); //vector에 2 push
	vec.push_back(3); //vector에 3 push
	vector<int>::iterator vecit = vec.begin(); //연산자 선언과 동시에 vec의 첫번째 값 0을 가리킴
	cout << vec[0] << endl; //vec의 첫번째 값 1 출력
	vecit++; //연산자가 다음 요소 가리킴(0 -> 1)
	cout << *vecit << endl; //참조 값 출력
	vecit++; //연산자가 다음 요소 가리킴(1 -> 2)
	cout << *vecit << endl; //참조 값 출력
	//vec.pop_back(); //마지막 값 pop(3 out)

	for (vecit = vec.begin(); vecit != vec.end(); ++vecit) { //vec의 첫요소부터 끝까지 순환, 연산자 1씩 증가
		cout << *vecit << endl; //연산자가 참조하는 값 출력(1, 2, 3)
	}
	return 0;
}

여기까지 STL 공부를 마친다. 뒤부턴 vector부터 하나하나 STL에 대한 포스팅을 진행할 예정이다.

반응형

+ Recent posts