함수들의 정리
- 수학 <math> 사용
함수 기능 예시 (3.4 기준)
| ceil(x) | 올림 (천장) | ceil(3.4) → 4.0 |
| floor(x) | 내림 (바닥) | floor(3.4) → 3.0 |
| round(x) | 반올림 | round(3.4) → 3.0 |
| abs(x) | 절댓값 | abs(-5) → 5 |
| pow(base, exp) | 거듭제곱 ($base^{exp}$) | pow(2, 3) → 8.0 |
| sqrt(x) | 제곱근 ($\sqrt{x}$) | sqrt(16) → 4.0 |
- 알고리즘 함수
함수 기능 사용 예시
| sort(start, end) | 정렬 (오름차순) | sort(v.begin(), v.end()) |
| reverse(start, end) | 거꾸로 뒤집기 | reverse(v.begin(), v.end()) |
| max(a, b) / min(a, b) | 둘 중 큰 값 / 작은 값 | max(10, 20) → 20 |
| max_element(s, e) | 범위 내 최대값의 위치 | *max_element(v.begin(), v.end()) |
| min_element(s, e) | 범위 내 최소값의 위치 | *min_element(v.begin(), v.end()) |
| find(s, e, val) | 특정 값의 위치 찾기 | find(v.begin(), v.end(), 5) |
- 문자열 함수
함수 기능 사용법 및 예시
| length() / size() | 문자열 길이 반환 | s.length() |
| substr(pos, len) | 부분 문자열 추출 | s.substr(0, 3) (0번부터 3글자) |
| find(str) | 특정 문자열 위치 찾기 | s.find("abc") (못 찾으면 string::npos) |
| stoi(str) | 문자열 → 정수 변환 | stoi("123") → 123 |
| to_string(val) | 숫자 → 문자열 변환 | to_string(10) → "10" |
| push_back(char) | 맨 뒤에 문자 하나 추가 | s.push_back('A') |
- Vector
함수 설명
| push_back(val) | 벡터의 맨 뒤에 요소 추가 |
| pop_back() | 벡터의 맨 뒤 요소 삭제 |
| insert(pos, val) | 특정 위치(pos)에 요소 삽입 |
| erase(pos) | 특정 위치(pos)의 요소 삭제 |
| clear() | 모든 요소 삭제 (크기를 0으로 만듦) |
| emplace_back(args) | 요소를 생성하여 맨 뒤에 삽입 (성능상 push_back보다 유리할 때가 있음) |
함수 설명
| at(index) | 해당 인덱스의 요소 접근 (범위 검사를 수행하여 안전함) |
| operator[] | 해당 인덱스의 요소 접근 (범위 검사 없음, 빠름) |
| front()/begin() | 첫 번째 요소 참조 |
| back()/end() | 마지막 요소 참조 |
함수 설명
| size() | 현재 담긴 요소의 개수 반환 |
| empty() | 벡터가 비어있는지 확인 (true/false) |
| capacity() | 할당된 메모리 공간의 크기 반환 |
| reserve(n) | $n$개의 요소를 담을 메모리를 미리 예약 (성능 최적화) |
| resize(n) | 벡터의 크기를 $n$으로 변경 |
STL 기초
- Standard Template Library는 c++ 표준 라이브러리의 일부로, 컨테이너, 알고리즘, 반복자 등의 템플릿 기반 구성요소를 포함함
- 컨테이너
데이터를 담는 자료구조
모든 컨테이너는 템플릿으로 구현 다양한 데이터를 저장할 수 있음
모든 컨테이너는 메모리 관리를 내부적으로 하고 사용시 메모리 해제를 직접 고려하지 않아도 된다.
대부분 컨테이너는 반복자를 제공한다. 따라서 내부 구현을 몰라도 동일한 방식으로 컨테이너를 순회할 수 있다.
- 벡터 - 배열과 매우 유사한 컨테이너
- 템플릿 클래스로 구현되어 특정 타입에 종속되지 않음
- 삽입되는 원소 개수에 따라 내부 배열의 크기가 자동으로 조정
- 임의 접근이 가능 (인덱스를 통해)
- 삽입 / 삭제는 맨 뒤에 하는 게 좋다
#include <vector>
using namespace std;
// 1. 기본 생성 및 초기화 없이 선언
vector<int> vec1;
// 2. 특정 크기와 초기값으로 벡터 선언
vector<int> vec2(5, 10); // 크기 5, 모든 원소가 10으로 초기화
// 3. 리스트 초기화로 벡터 선어
vector<int> vec3 = {1, 2, 3, 4, 5};
//4. 기존 벡터 복사
vector<int> vec4(vec3);
//5. 2차원 배열 벡터
vector<int> vec2D(3, vector<int>(4,7);
vec1.push_back(10);
vec1.push_back(20);
vec1.push_back(30);
// 10 20 30
cout << vec1.size(); //3
vec1.pop_back(); //10 20
cout << vec1.size(); //2
vec1.pop_back(); // 10
cout << vec1.size(); //1
vec1.pop_back(); //
//메인 함수 생략
- 맵 - 특정 키를 활용해서 값을 찾는 기능
- 키-값 쌍은 map<const Key, Value>map1; 형태로 저장
- 키값을 기준으로 내부 데이터가 자동으로 정렬
- 중복된 키값을 허용하지 않음
#include <iostream>
#include <map>
using namespace std;
// 정수 키와 문자열 값을 저장하는 map 예제
int main() {
map<int, string> studentMap;
// 요소 추가
studentMap[101] = "Alice";
studentMap[102] = "Bob";
studentMap[103] = "Charlie";
//요소 추가 방식2
studentMap.insert({104, "Mark"});
//요소 추가 방식 3
studentMap.insert(make_pair(100, "Park"));
//요소 추가 방식 4
studentMap[106] = "Kim";
// 요소 출력
for (const auto& pair : studentMap) {
cout << "ID: " << pair.first << ", Name: " << pair.second << endl;
}
int key=100;
auto it = studentMap.find(key);
if(it != studentMap.end()) {
cout << "Key : " << it -> first << "Value: " << it->second;
} else {
cout << "Key not found";
return 0;
}
객체지향적 설계는 단순 문법이 아니라 클래스를 어떻게 효과적으로 설계하는지가 핵심이다.
이에 대한 기준은 응집도와 결합도에 있다.
- 응집도
- 응집도는 클래스 또는 모듈 내부의 구성 요소들이 얼마나 밀접하게 관련되어 있는지를 나타낸다.
- 결합도
- 결합도는 각 모듈들의 서로 얼마나 의존하는 지 나타낸다.
- 즉 결합도는 낮은 게 좋은 코드다. 이는 인터페이스를 사용에 결합도를 감소시킬 수 있다.
SOLID 원칙
- SRP 단일 책임 원칙 - 역할과 책임을 분리해 수정을 최소화 한다.
- OCP 개방 폐쇄 원칙 - 확장에는 열려 있고 수정에는 닫혀 있어야 함, 따라서 기존 코드를 변경하지 않고 새로운 기능을 추가할 수 있도록 하는 것.
- LSP 리스 코프 치환 원칙 - 자식 클래스는 부모 클래스에서 기대되는 행동을 보장해야 함
- ISP 인터페이스 분리 원칙 - 각 클래스에는 불필요한 메서드를 구현하지 말아야 함
- DIP 의존 역전 원칙 - 인터페이스나 추상 클래스를 사용해 결합도를 낮추는 것
실습 과제 2:
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
struct Movie {
string title;
double rating;
};
// TODO: MovieProcessor 추상 클래스 정의
// 순수 가상 함수 process를 선언해야 합니다.
// process는 vector<Movie>&를 인자로 받아야 합니다.
class MovieProcessor
{
public:
virtual void process(vector<Movie>& movies) = 0; // 순수 가상 함수
virtual ~MovieProcessor() {} // 가상 소멸자
};
// 기본 영화 관리자
class MovieManager {
private:
vector<Movie> movies;
map<string, double> movieMap;
public:
MovieManager() {
// 초기 데이터 설정
movies = {
{"Inception", 9.0},
{"Interstellar", 8.6},
{"The Dark Knight", 9.1},
{"Memento", 8.4}
};
for (const auto& movie : movies) {
movieMap[movie.title] = movie.rating;
}
}
void printMovies() {
cout << "영화 목록:\n";
for (const auto& movie : movies) {
cout << "제목: " << movie.title << ", 평점: " << movie.rating << "\n";
}
}
void findMovie(const string& title) {
auto it = movieMap.find(title);
if (it != movieMap.end()) {
cout << "영화 제목: " << it->first << ", 평점: " << it->second << "\n";
}
else {
cout << "해당 영화는 목록에 없습니다.\n";
}
}
// MovieProcessor를 사용하여 기능 확장
void processMovies(MovieProcessor& processor) {
processor.process(movies);
}
};
// TODO: compareMovies 함수 정의
// Movies 객체의 대소를 비교하는 함수 입니다.
// STL에서 제공하는 sort 함수를 활용해서 vector<Movie>를 멤버변수 rating 기준 내림차순으로 정렬 할 수 있도록 해야 합니다.
void compareMovies(vector<Movie>& movies) {
sort(movies.begin(), movies.end(), [](const Movie& a, const Movie& b) {
return a.rating > b.rating; // 내림차순 정렬
});
}
// TODO: RatingSorter 클래스 정의
// MovieProcessor를 상속받아 구현합니다.
// process 는 vector<Movie>&를 인자로 받으며 영화목록이 저장되어 있습니다.
// process는 인자로 받은 벡터는 내림차순으로 정렬하고, 정렬된 영화목록을 출력합니다.
class RatingSorter : public MovieProcessor {
public:
void process(vector<Movie>& movies) override {
compareMovies(movies); // 영화 목록을 평점 기준으로 내림차순 정렬
cout << "평점 기준 내림차순으로 정렬된 영화 목록:\n";
for (const auto& movie : movies) {
cout << "제목: " << movie.title << ", 평점: " << movie.rating << "\n";
}
}
};
// 구체 클래스: 특정 평점 이상의 영화 필터링
class RatingFilter : public MovieProcessor {
private:
double minRating;
public:
explicit RatingFilter(double minRating) : minRating(minRating) {}
void process(vector<Movie>& movies) {
cout << "평점 " << minRating << " 이상인 영화 목록:\n";
for (const auto& movie : movies) {
if (movie.rating >= minRating) {
cout << "제목: " << movie.title << ", 평점: " << movie.rating << "\n";
}
}
}
};
int main() {
MovieManager manager;
cout << "1. 영화 목록 출력\n";
manager.printMovies();
cout << "\n2. 영화 검색 (예: Interstellar)\n";
manager.findMovie("Interstellar");
cout << "\n3. 평점 기준 정렬 및 출력\n";
RatingSorter sorter;
manager.processMovies(sorter);
cout << "\n4. 평점 8.5 이상인 영화 필터링 및 출력\n";
RatingFilter filter(8.5);
manager.processMovies(filter);
return 0;
}
디자인 패턴

- 생성 패턴
- 새로운 것을 만들어내는 방법과 관련된 패턴
- 구조 패턴
- 여러 부품을 어떻게 조립하고 연결하는 방법에 대한 패턴
- 행동 패턴
- 부품이 서로 어떻게 상호작용 할지에 대한 패턴
생성 패턴: 싱글톤
클래스에 인스턴스가 하나만 있도록 하면서 해당 인스턴스에 전역 접근 지점을 제공한다. 따라서 새로운 객체를 생성했다고 해도 이미 만든 객체를 받게 된다.
싱글톤 패턴 예시 코드:
#include <iostream>
using namespace std;
class Airplane {
private:
static Airplane* instance; // 유일한 비행기 객체를 가리킬 정적 포인터
int positionX; // 비행기의 X 위치
int positionY; // 비행기의 Y 위치
// private 생성자: 외부에서 객체 생성 금지
Airplane() : positionX(0), positionY(0) {
cout << "Airplane Created at (" << positionX << ", " << positionY << ")" << endl;
}
public:
// 복사 생성자와 대입 연산자를 삭제하여 복사 방지
Airplane(const Airplane&) = delete;
Airplane& operator=(const Airplane&) = delete;
// 정적 메서드: 유일한 비행기 인스턴스를 반환
static Airplane* getInstance() {
if (instance == nullptr) {
instance = new Airplane();
}
return instance;
}
// 비행기 위치 이동
void move(int deltaX, int deltaY) {
positionX += deltaX;
positionY += deltaY;
cout << "Airplane moved to (" << positionX << ", " << positionY << ")" << endl;
}
// 현재 위치 출력
void getPosition() const {
cout << "Airplane Position: (" << positionX << ", " << positionY << ")" << endl;
}
};
// 정적 멤버 초기화
Airplane* Airplane::instance = nullptr;
// 메인 함수 (사용 예시)
int main() {
// 유일한 비행기 인스턴스를 가져옴
Airplane* airplane = Airplane::getInstance();
airplane->move(10, 20); // 비행기 이동
airplane->getPosition();
// 또 다른 요청도 같은 인스턴스를 반환
Airplane* sameAirplane = Airplane::getInstance();
sameAirplane->move(-5, 10); // 비행기 이동
sameAirplane->getPosition();
return 0;
}
구조 패턴: 데코레이터 패턴
데코레이터는 객체들을 새로운 행동들을 포함한 특수 래퍼 객체들 내에 넣어서 위 행동들을 해당 객체들에 연결시키는 구조적 디자인 패턴이다.
데코레이터 패턴 예시 코드:
#include <iostream>
#include <string>
using namespace std;
// **추상 컴포넌트 (Component): Pizza**
// - 피자 객체의 기본 구조를 정의하는 인터페이스입니다.
// - 모든 피자는 이름(`getName`)과 가격(`getPrice`)을 가져야 합니다.
class Pizza {
public:
virtual ~Pizza() {}
virtual string getName() const = 0; // 피자의 이름 반환
virtual double getPrice() const = 0; // 피자의 가격 반환
};
// **구체 컴포넌트 (Concrete Component): BasicPizza**
// - 기본 피자 클래스입니다.
// - 피자의 기본 베이스(이름과 가격)를 구현합니다.
class BasicPizza : public Pizza {
public:
string getName() const {
return "Basic Pizza"; // 기본 피자의 이름
}
double getPrice() const {
return 5.0; // 기본 피자의 가격
}
};
// **데코레이터 추상 클래스 (Decorator): PizzaDecorator**
// - 기존 피자의 기능을 확장하기 위한 데코레이터의 기본 구조를 정의합니다.
// - 내부적으로 `Pizza` 객체를 감싸며, 이름과 가격에 추가적인 기능을 제공합니다.
class PizzaDecorator : public Pizza {
protected:
Pizza* pizza; // 기존의 피자 객체를 참조합니다.
public:
// 데코레이터는 피자 객체를 받아서 감쌉니다.
PizzaDecorator(Pizza* p) : pizza(p) {}
// 소멸자에서 내부 피자 객체를 삭제합니다.
virtual ~PizzaDecorator() {
delete pizza;
}
};
// **구체 데코레이터 (Concrete Decorators): Cheese, Pepperoni, Olive**
// - 각각의 토핑 데코레이터는 `PizzaDecorator`를 상속받아 이름과 가격을 확장합니다.
// 치즈 토핑 데코레이터
class CheeseDecorator : public PizzaDecorator {
public:
CheeseDecorator(Pizza* p) : PizzaDecorator(p) {}
string getName() const {
// 기존 피자의 이름에 " + Cheese"를 추가
return pizza->getName() + " + Cheese";
}
double getPrice() const {
// 기존 피자의 가격에 치즈 추가 비용 1.5를 더함
return pizza->getPrice() + 1.5;
}
};
// 페퍼로니 토핑 데코레이터
class PepperoniDecorator : public PizzaDecorator {
public:
PepperoniDecorator(Pizza* p) : PizzaDecorator(p) {}
string getName() const {
// 기존 피자의 이름에 " + Pepperoni"를 추가
return pizza->getName() + " + Pepperoni";
}
double getPrice() const {
// 기존 피자의 가격에 페퍼로니 추가 비용 2.0을 더함
return pizza->getPrice() + 2.0;
}
};
// 올리브 토핑 데코레이터
class OliveDecorator : public PizzaDecorator {
public:
OliveDecorator(Pizza* p) : PizzaDecorator(p) {}
string getName() const {
// 기존 피자의 이름에 " + Olive"를 추가
return pizza->getName() + " + Olive";
}
double getPrice() const {
// 기존 피자의 가격에 올리브 추가 비용 0.7을 더함
return pizza->getPrice() + 0.7;
}
};
// **클라이언트 코드**
// - 피자와 데코레이터를 조합하여 최종 피자를 생성하고, 정보를 출력합니다.
int main() {
// 1. 기본 피자를 생성합니다.
Pizza* pizza = new BasicPizza();
// 2. 치즈 토핑을 추가합니다.
pizza = new CheeseDecorator(pizza);
// 3. 페퍼로니 토핑을 추가합니다.
pizza = new PepperoniDecorator(pizza);
// 4. 올리브 토핑을 추가합니다.
pizza = new OliveDecorator(pizza);
// 5. 최종 피자 정보 출력
cout << "Pizza: " << pizza->getName() << endl; // 피자의 이름 출력
cout << "Price: $" << pizza->getPrice() << endl; // 피자의 가격 출력
// 6. 메모리 해제
delete pizza;
return 0;
}
행동 패턴: 옵서버 패턴
옵저버 패턴은 당신이 여러 객체에 자신이 관찰 중인 객체에 발생하는 모든 이벤트에 대하여 알리는 구독 메커니즘을 정의할 수 있도록 하는 행동 디자인 패턴이다.
옵저버 패턴 예시 코드:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// Observer 인터페이스
// - Observer 패턴에서 상태 변화를 알림받는 객체들의 공통 인터페이스
// - Observer들은 이 인터페이스를 구현하여 `update` 메서드를 통해 데이터를 전달받음
class Observer {
public:
virtual ~Observer() = default; // 가상 소멸자
virtual void update(int data) = 0; // 데이터 업데이트 메서드 (순수 가상 함수)
};
// Subject 클래스 (엑셀 시트 역할)
// - 데이터의 상태 변화를 관리하며, 모든 등록된 Observer들에게 변경 사항을 알림
class ExcelSheet {
private:
vector<Observer*> observers; // Observer들을 저장하는 리스트
int data; // 현재 데이터 상태
public:
ExcelSheet() : data(0) {} // 생성자: 초기 데이터 값은 0
// Observer 등록 메서드
// - 새로운 Observer를 등록하여 변경 사항 알림을 받을 수 있도록 추가
void attach(Observer* observer) {
observers.push_back(observer);
}
// 데이터 변경 알림 메서드
// - 등록된 모든 Observer들의 `update` 메서드를 호출하여 데이터 변경 사항을 알림
void notify() {
for (Observer* observer : observers) {
observer->update(data); // 각 Observer에게 데이터를 전달
}
}
// 데이터 설정 메서드
// - 데이터를 변경하고 변경 사항을 모든 Observer에게 알림
void setData(int newData) {
data = newData; // 새로운 데이터로 갱신
cout << "ExcelSheet: Data updated to " << data << endl;
notify(); // Observer들에게 알림
}
};
// 구체적인 Observer 클래스: BarChart (막대 차트)
// - 데이터를 막대 그래프로 표현
class BarChart : public Observer {
public:
void update(int data) { // 데이터 업데이트 시 호출됨
cout << "BarChart: Displaying data as vertical bars: ";
for (int i = 0; i < data; ++i) {
cout << "|"; // 데이터 값만큼 막대 출력
}
cout << " (" << data << ")" << endl;
}
};
// 구체적인 Observer 클래스: LineChart (라인 차트)
// - 데이터를 선형 그래프로 표현
class LineChart : public Observer {
public:
void update(int data) { // 데이터 업데이트 시 호출됨
cout << "LineChart: Plotting data as a line: ";
for (int i = 0; i < data; ++i) {
cout << "-"; // 데이터 값만큼 선 출력
}
cout << " (" << data << ")" << endl;
}
};
// 구체적인 Observer 클래스: PieChart (파이 차트)
// - 데이터를 파이 그래프로 표현
class PieChart : public Observer {
public:
void update(int data) { // 데이터 업데이트 시 호출됨
cout << "PieChart: Displaying data as a pie chart slice: ";
cout << "Pie [" << data << "%]" << endl; // 데이터 값 출력 (가정: % 비율로 표현)
}
};
// 메인 함수
int main() {
// Subject 생성
ExcelSheet excelSheet; // 데이터를 관리하는 엑셀 시트 객체 생성
// Observer 객체 생성 (각 차트 객체)
BarChart* barChart = new BarChart(); // 막대 차트 생성
LineChart* lineChart = new LineChart(); // 라인 차트 생성
PieChart* pieChart = new PieChart(); // 파이 차트 생성
// Observer 등록
// - 각 차트(Observer)를 엑셀 시트(Subject)에 등록
excelSheet.attach(barChart);
excelSheet.attach(lineChart);
excelSheet.attach(pieChart);
// 데이터 변경 테스트
// - 데이터를 변경하면 등록된 모든 Observer들이 알림을 받고 화면에 갱신
excelSheet.setData(5); // 데이터 변경: 5
excelSheet.setData(10); // 데이터 변경: 10
// 메모리 해제
// - 동적 할당된 Observer(차트) 객체 삭제
delete barChart;
delete lineChart;
delete pieChart;
return 0;
}
디자인 패턴 실습 과제 코드:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 고객 인터페이스 (Observer 역할)
class Customer {
public:
virtual void update(const string& status) = 0; // 순수 가상 함수
};
// 일반 고객 클래스
class RegularCustomer : public Customer {
private:
string name;
public:
RegularCustomer(const string& name) : name(name) {}
void update(const string& status) {
cout << "Regular customer " << name << " received update: " << status << endl;
}
};
// TODO: VIP 고객 클래스 (Customer를 상속받아 구현)
// 요구 사항:
// - 고객 이름을 저장하는 멤버 변수 `name`을 추가하세요.
// - 생성자에서 이름을 초기화하세요.
// - `update` 메서드를 구현하여 "VIP customer [이름] received VIP update: [배송 상태]" 형식으로 출력되도록 하세요.
class VIPCustomer : public Customer {
private:
string name;
public:
VIPCustomer(const string& name) : name(name) {}
void update(const string& status) {
cout << "VIP customer " << name << " received VIP update: " << status << endl;
}
};
class BusinessCustomer : public Customer {
private:
string name;
public:
BusinessCustomer(const string& name) : name(name) {}
void update(const string& status) {
cout << "Business customer " << name << " received business update: " << status << endl;
}
};
// TODO: 배송 회사 클래스 (DeliveryService)
// 요구 사항:
// - `customers`라는 고객 리스트를 저장하는 멤버 변수를 추가하세요.
// - `currentStatus`라는 현재 배송 상태를 저장하는 멤버 변수를 추가하세요.
// - 고객을 추가하는 `addCustomer` 메서드를 구현하세요.
// - 고객을 제거하는 `removeCustomer` 메서드를 구현하세요.
// - 배송 상태를 업데이트하고 모든 고객에게 알리는 `updateStatus` 메서드를 구현하세요.
// - 등록된 모든 고객에게 상태를 전달하는 `notifyCustomers` 메서드를 구현하세요.
class DeliveryService {
private:
vector<Customer*> customers; // 고객 리스트
string currentStatus; // 현재 배송 상태
public:
void addCustomer(Customer* customer) {
customers.push_back(customer);
}
void removeCustomer(Customer* customer) {
customers.erase(remove(customers.begin(), customers.end(), customer), customers.end());
}
void updateStatus(const string& status) {
currentStatus = status;
notifyCustomers();
}
void notifyCustomers() {
for (Customer* customer : customers) {
customer->update(currentStatus);
}
}
};
// Main 함수
int main() {
DeliveryService service;
// 고객 객체 생성
RegularCustomer* customer1 = new RegularCustomer("Alice");
VIPCustomer* customer2 = new VIPCustomer("Bob");
BusinessCustomer* customer3 = new BusinessCustomer("CompanyX");
// 고객 등록
service.addCustomer(customer1);
service.addCustomer(customer2);
service.addCustomer(customer3);
// 배송 상태 업데이트 및 알림
cout << "Updating status: 배송 준비 중" << endl;
service.updateStatus("배송 준비 중");
cout << "\nUpdating status: 배송 완료" << endl;
service.updateStatus("배송 완료");
// 메모리 해제
delete customer1;
delete customer2;
delete customer3;
return 0;
}'c++ > 알고리즘' 카테고리의 다른 글
| C++ 알고리즘) 스택 및 큐 (0) | 2026.03.12 |
|---|---|
| C++ 알고리즘) 시뮬레이션 및 행렬 연산 (0) | 2026.03.11 |
| C++ 알고리즘) 정렬 (0) | 2026.03.10 |
| C++ 알고리즘) 벡터, 덱, 및 재귀 함수 (0) | 2026.03.09 |
| C++ 알고리즘) 스마트 포인터 및 언리얼 가비지 컬렉션 (0) | 2026.03.05 |