front/back/size 불변식을 코드로 안전하게 유지할 수 있다.template<typename T>
void Print(const T& value)
{
std::cout << value << '\n';
}
T는 “나중에 결정되는 타입 매개변수”입니다.Print(10), Print(3.14f), Print(std::string("hi"))처럼 호출 타입에 맞춰 인스턴스화됩니다.template<typename T>
class RandomBox
{
public:
void Add(const T& value) { _data.push_back(value); }
const T& Get(int index) const { return _data[index]; }
private:
std::vector<T> _data;
};
RandomBox<int>와 RandomBox<float>는 서로 다른 타입입니다.Vector<T>, List<T>)를 모든 도메인 타입에 재사용할 수 있습니다.template<>
void Print<int>(const int& value)
{
std::cout << "[int] " << value << '\n';
}
| 구조 | 규칙 | 대표 예시 |
|---|---|---|
| 스택(Stack) | LIFO | Undo, 함수 호출 스택, 팝업 닫기 |
| 큐(Queue) | FIFO | 작업 대기열, 서버 요청 처리 |
핵심은 “자료구조 자체”보다 “사용 가능한 연산을 제한한 인터페이스”입니다.
push, pop, top, empty, sizepush, pop, front, back, empty, sizetop/front로 확인하고 pop은 제거만 담당하는 패턴을 권장합니다.vector 기반이 가장 단순하고 빠릅니다(push_back/pop_back O(1)).vector로 만들고 앞에서 제거하면 O(N) 이동 비용이 발생합니다.list 기반 혹은 인덱스 기반 원형 큐가 자연스럽습니다.template<typename T>
class Stack
{
public:
void push(const T& value) { _container.push_back(value); }
void pop() { _container.pop_back(); }
T& top() { return _container.back(); }
const T& top() const { return _container.back(); }
bool empty() const { return _container.empty(); }
int size() const { return static_cast<int>(_container.size()); }
private:
std::vector<T> _container;
};
capacity = 8
front = 읽을 위치
back = 쓸 위치(다음 삽입 위치)
size = 현재 원소 개수
다음 인덱스 = (index + 1) % capacity
front와 back은 배열 끝에 도달하면 0으로 순환합니다.size == 0size == capacitytemplate<typename T>
class CircularQueue
{
public:
explicit CircularQueue(int capacity = 8)
: _data(capacity), _front(0), _back(0), _size(0) {}
void push(const T& value)
{
if (_size == static_cast<int>(_data.size()))
Grow();
_data[_back] = value;
_back = (_back + 1) % static_cast<int>(_data.size());
++_size;
}
void pop()
{
if (empty())
return;
_front = (_front + 1) % static_cast<int>(_data.size());
--_size;
}
T& front() { return _data[_front]; }
const T& front() const { return _data[_front]; }
bool empty() const { return _size == 0; }
int size() const { return _size; }
private:
void Grow()
{
std::vector<T> next(_data.size() * 2);
for (int i = 0; i < _size; ++i)
next[i] = _data[(_front + i) % static_cast<int>(_data.size())];
_data.swap(next);
_front = 0;
_back = _size;
}
private:
std::vector<T> _data;
int _front;
int _back;
int _size;
};
front()/pop() 전에 empty() 확인을 누락하기 쉽습니다..cpp로 분리하면 왜 링크 에러가 자주 발생할까?pop_front가 비효율적인 이유는?front/back/size 중 하나가 틀리면 어떤 버그가 나는가?