주의사항
- size와 capacity 개념이 중요하다
size는 실제 사용되는 데이터의 개수를 의미하고
capacity는 사용되는 데이터보다 조금 더(ex. 1.5배, 2배) 큰 크기로
미리 용량을 확보해 놓은 공간의 개수를 의미한다
이렇게 사용하는 이유는 배열의 크기가 변하는 경우 발생하는
복사를 최소화를 하기 위해서다
- 동적배열 선언하고 reserve를 먼저 사용하는 습관
실제 동적 배열을 사용하는 경우에는
효율을 위해 reserve를 가장 먼저 호출해서 사용하는 것이 좋다
그 이유는 데이터가 늘어나는 경우에
특히, 초반에는 배열의 크기가 자주 변경되기에
미리 데이터의 개수를 알고 있다면, reserve로 capacity를 지정해 주는 것이 좋다
- clear의 진실
clear시 capacity는 그대로 유지된다
- resize의 진실
reserve는 size는 유지한 채로 capacity만 바꿔주지만
resize는
일반적으로는 size만 바꿔주는데
만약, 기존 size보다 커지는 경우에
기존 capacity보다 size가 큰 경우에는 size와 capacity 모두 바꿔준다
- resize와 reserve의 충돌
둘이 충돌되는 경우에서의 핵심은 아래 두 가지이다
1) reserve는 이미 늘어난 capacity를 줄여주지 않는다
2) 기존 사이즈보다 작게 resize로 사이즈 줄이면, 그 뒤의 데이터는 다 날아간다
- resize와 reserve의 충돌 예시
vector<int> v0;
v0.resize(10);// 기존값
v0.resize(50);
v0.reserve(100);
cout << v0.size() << " " << v0.capacity() << endl;// 50 100
vector<int> v1;
v1.resize(500);// 기존값
v1.resize(50);// (주의) 사이즈가 줄면서, 그 이후의 값들은 다 날라감
v1.reserve(100);// (주의) 의미 없음
cout << v1.size() << " " << v1.capacity() << endl;// 50 500
vector<int> v2;
v2.resize(10);// 기존값
v2.resize(100);
v2.reserve(50);// (주의) 의미 없음
cout << v2.size() << " " << v2.capacity() << endl;// 100 100
vector<int> v3;
v3.resize(500);// 기존값
v3.resize(100);// (주의) 사이즈가 줄면서, 그 이후의 값들은 다 날라감
v3.reserve(50);// (주의) 의미 없음
cout << v3.size() << " " << v3.capacity() << endl;// 100 500
동적배열 구현
#pragma once
#include <stdexcept>
template<typename T>
class MyVector
{
public:
MyVector()
{
}
~MyVector()
{
if (_data)
delete[] _data;
}
void push_back(const T& value)
{
if (_size == _capacity)// 맨처음 or 배열이 꽉찬 경우
{
// 증설 작업
int newCapacity = static_cast<int>(_capacity * 1.5);
if (newCapacity == _capacity)
newCapacity++;
reserve(newCapacity);
}
// 데이터 저장
_data[_size] = value;
// 데이터 개수 증가
_size++;
}
void resize(int size, const T& value = T())
{
if (_size == size)
return;
if (_size > size)// size가 작아진 경우
{
// []연산자로 접근이 막히기에 size만 줄여줌
_size = size;
// capacity는 유지
}
else// size가 커진 경우
{
if(size > _capacity)// capacity보다 큰 경우에만 capacity 확장(재할당)
reserve(size);
// 늘어난 부분 초기값 설정
for (int i = _size; i < size; i++)
_data[i] = value;
_size = size;
}
}
void reserve(int capacity)
{
if (_capacity >= capacity)
return;
_capacity = capacity;
// 새로운 데이터 동적할당
T* newData = new T[_capacity];
// 데이터 복사
for (int i = 0; i < _size; i++)
newData[i] = _data[i];
// 기존 데이터 삭제
if (_data)
delete[] _data;
// 교체
_data = newData;
}
void clear()
{
// 기존 capacity는 유지하고 재할당하는 방식
// 만약, 기존 공간 재활용하는 방식을 하려면
// _size만 0으로 하면 됨
if (_data)
{
delete[] _data;
_data = new T[_capacity];
}
_size = 0;// size는 0으로
}
T& operator[](const int pos)
{
if (pos < 0 || pos >= _size)
throw std::out_of_range("Index out of range");
return _data[pos];
}
int size() { return _size; }
int capacity() { return _capacity; }
private:
T* _data = nullptr;// 배열의 시작 주소
int _size = 0;// size
int _capacity = 0;// capacity
};
#include <iostream>
#include <vector>
#include "MyVector.h"
using namespace std;
int main()
{
//vector<int> v;
MyVector<int> v;
v.reserve(100);
cout << v.size() << " " << v.capacity() << endl;
for (int i = 0; i < 100; i++)
{
v.push_back(i);
cout << v.size() << " " << v.capacity() << endl;
}
v.resize(10);
cout << v.size() << " " << v.capacity() << endl;
v.clear();
cout << v.size() << " " << v.capacity() << endl;
}
'자료구조 & 알고리즘 > [루키스] C++ 자료구조 & 알고리즘' 카테고리의 다른 글
[C++ 자/알 Note] 스택 구현 (0) | 2025.01.08 |
---|---|
[C++ 자/알 Note] 연결리스트 구현 (0) | 2025.01.08 |
[C++ 자/알 Note] 배열, 동적배열, 연결리스트 (0) | 2025.01.04 |
[C++ 자/알 Note] 오른손 법칙 (미로 탐색) (0) | 2025.01.04 |
[C++ 자/알 Note] Big-O 표기법 (0) | 2025.01.04 |