Topic 4: 반복문 실전 활용 🚀
🎯 학습 목표
- 복잡한 문제를 반복문으로 해결할 수 있다
- 효율적인 반복문 작성 방법을 익힐 수 있다
- 실제 프로젝트에서 활용 가능한 패턴을 습득할 수 있다
🔢 수학적 계산
팩토리얼 계산
#include <iostream>
using namespace std;
int main() {
int n;
long long factorial = 1;
cout << "팩토리얼을 계산할 숫자를 입력하세요: ";
cin >> n;
if (n < 0) {
cout << "음수는 팩토리얼을 계산할 수 없습니다." << endl;
} else if (n == 0 || n == 1) {
cout << n << "! = 1" << endl;
} else {
cout << n << "! = ";
for (int i = 1; i <= n; i++) {
factorial *= i;
cout << i;
if (i < n) cout << " × ";
}
cout << " = " << factorial << endl;
}
return 0;
}
소수 판별
#include <iostream>
using namespace std;
int main() {
int num;
cout << "소수인지 확인할 숫자: ";
cin >> num;
if (num < 2) {
cout << num << "은(는) 소수가 아닙니다." << endl;
} else {
bool isPrime = true;
for (int i = 2; i < num; i++) {
if (num % i == 0) {
isPrime = false;
break;
}
}
if (isPrime) {
cout << num << "은(는) 소수입니다." << endl;
} else {
cout << num << "은(는) 소수가 아닙니다." << endl;
}
}
return 0;
}
🎨 패턴과 도형
별 피라미드
#include <iostream>
using namespace std;
int main() {
int height;
cout << "피라미드 높이: ";
cin >> height;
// 위쪽 부분
for (int i = 1; i <= height; i++) {
// 공백 출력
for (int j = 1; j <= height - i; j++) {
cout << " ";
}
// 별 출력
for (int j = 1; j <= i; j++) {
cout << "* ";
}
cout << endl;
}
return 0;
}
간단한 숫자 테이블
#include <iostream>
using namespace std;
int main() {
cout << "곱셈 표 (3x3):" << endl;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
cout << (i * j) << "\t"; // \t는 탭 문자
}
cout << endl;
}
cout << "\n덧셈 표 (3x3):" << endl;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
cout << (i + j) << "\t";
}
cout << endl;
}
return 0;
}
🎯 게임 로직
숫자 맞추기 게임
#include <iostream>
using namespace std;
int main() {
int secret = 7; // 정답
int guess;
int attempts = 0;
cout << "=== 숫자 맞추기 게임 ===" << endl;
cout << "1부터 10 사이의 숫자를 맞춰보세요!" << endl;
do {
attempts++;
cout << attempts << "번째 시도: ";
cin >> guess;
if (guess == secret) {
cout << "정답! " << attempts << "번만에 맞추셨네요!" << endl;
} else if (guess < secret) {
cout << "더 큰 숫자입니다." << endl;
} else {
cout << "더 작은 숫자입니다." << endl;
}
} while (guess != secret);
cout << "게임 종료!" << endl;
return 0;
}
📊 데이터 처리
간단한 점수 처리
#include <iostream>
using namespace std;
int main() {
int scores[3];
int sum = 0;
cout << "=== 3명의 점수 입력 ===" << endl;
for (int i = 0; i < 3; i++) {
cout << (i + 1) << "번 학생 점수: ";
cin >> scores[i];
sum += scores[i];
}
double average = (double)sum / 3;
cout << "\n=== 결과 ===" << endl;
cout << "총점: " << sum << "점" << endl;
cout << "평균: " << average << "점" << endl;
// 최고점과 최저점 찾기
int maxScore = scores[0];
int minScore = scores[0];
for (int i = 1; i < 3; i++) {
if (scores[i] > maxScore) {
maxScore = scores[i];
}
if (scores[i] < minScore) {
minScore = scores[i];
}
}
cout << "최고점: " << maxScore << "점" << endl;
cout << "최저점: " << minScore << "점" << endl;
return 0;
}
💡 최적화 팁
1. 불필요한 계산 줄이기
// 비효율적
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (expensive_function(i) > threshold) { // 매번 계산
// ...
}
}
}
// 효율적
for (int i = 0; i < n; i++) {
int value = expensive_function(i); // 한 번만 계산
for (int j = 0; j < n; j++) {
if (value > threshold) {
// ...
}
}
}
2. 조기 종료 활용
// 목표 찾기 - 조기 종료
bool found = false;
for (int i = 0; i < n && !found; i++) {
for (int j = 0; j < m && !found; j++) {
if (arr[i][j] == target) {
found = true;
// 위치 저장 등
}
}
}
🎨 추가 연습 예제
복잡한 도형 패턴
#include <iostream>
using namespace std;
int main() {
int size;
cout << "도형 크기를 입력하세요: ";
cin >> size;
cout << "\n=== 1. 속이 빈 사각형 ===" << endl;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (i == 0 || i == size-1 || j == 0 || j == size-1) {
cout << "* ";
} else {
cout << " ";
}
}
cout << endl;
}
cout << "\n=== 2. X 패턴 ===" << endl;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (i == j || i + j == size - 1) {
cout << "* ";
} else {
cout << " ";
}
}
cout << endl;
}
cout << "\n=== 3. 체스보드 패턴 ===" << endl;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if ((i + j) % 2 == 0) {
cout << "■ ";
} else {
cout << "□ ";
}
}
cout << endl;
}
return 0;
}
📈 알고리즘 컬렉션
정렬 알고리즘 시각화
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
void printArray(int arr[], int size, string title) {
cout << title << ": ";
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
// 버블 정렬
void bubbleSort(int arr[], int size) {
cout << "\n=== 버블 정렬 과정 ===" << endl;
for (int i = 0; i < size - 1; i++) {
cout << "\n" << (i + 1) << "번째 패스:" << endl;
bool swapped = false;
for (int j = 0; j < size - i - 1; j++) {
cout << "비교: " << arr[j] << " vs " << arr[j + 1];
if (arr[j] > arr[j + 1]) {
// 스왑
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
cout << " → 교환!" << endl;
} else {
cout << " → 유지" << endl;
}
}
printArray(arr, size, "현재 상태");
if (!swapped) {
cout << "더 이상 교환할 것이 없습니다. 정렬 완료!" << endl;
break;
}
}
}
// 선택 정렬
void selectionSort(int arr[], int size) {
cout << "\n=== 선택 정렬 과정 ===" << endl;
for (int i = 0; i < size - 1; i++) {
int minIndex = i;
cout << "\n" << (i + 1) << "번째 위치에 들어갈 최소값 찾기:" << endl;
cout << "현재 최소값: " << arr[minIndex] << " (인덱스 " << minIndex << ")" << endl;
for (int j = i + 1; j < size; j++) {
cout << "비교: " << arr[j];
if (arr[j] < arr[minIndex]) {
minIndex = j;
cout << " → 새로운 최소값! (인덱스 " << minIndex << ")" << endl;
} else {
cout << " → 현재 최소값 유지" << endl;
}
}
if (minIndex != i) {
cout << "교환: " << arr[i] << " ↔ " << arr[minIndex] << endl;
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
printArray(arr, size, "현재 상태");
}
}
int main() {
srand(time(0));
const int SIZE = 8;
int arr1[SIZE], arr2[SIZE];
// 랜덤 배열 생성
cout << "정렬할 배열을 랜덤으로 생성합니다." << endl;
for (int i = 0; i < SIZE; i++) {
int num = rand() % 50 + 1; // 1~50 사이 숫자
arr1[i] = num;
arr2[i] = num; // 복사본
}
printArray(arr1, SIZE, "원본 배열");
cout << "\n어떤 정렬을 보시겠습니까?" << endl;
cout << "1. 버블 정렬" << endl;
cout << "2. 선택 정렬" << endl;
cout << "선택: ";
int choice;
cin >> choice;
switch (choice) {
case 1:
bubbleSort(arr1, SIZE);
break;
case 2:
selectionSort(arr2, SIZE);
break;
default:
cout << "잘못된 선택입니다." << endl;
return 1;
}
return 0;
}
🎯 간단한 수학 계산
약수 찾기
#include <iostream>
using namespace std;
int main() {
int num;
cout << "약수를 찾을 숫자: ";
cin >> num;
cout << num << "의 약수: ";
for (int i = 1; i <= num; i++) {
if (num % i == 0) {
cout << i << " ";
}
}
cout << endl;
return 0;
}
💰 실전 프로젝트: 가계부 관리 시스템
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
struct Transaction {
int id;
string type; // "수입" 또는 "지출"
string category; // "식비", "교통비", "급여" 등
int amount;
string description;
};
void displayMenu() {
cout << "\n======= 💰 가계부 관리 시스템 =======" << endl;
cout << "1. 📈 수입 추가" << endl;
cout << "2. 📉 지출 추가" << endl;
cout << "3. 📊 전체 내역 보기" << endl;
cout << "4. 🔍 카테고리별 집계" << endl;
cout << "5. 💳 월말 정산" << endl;
cout << "6. 🗑️ 내역 삭제" << endl;
cout << "0. 🚪 종료" << endl;
cout << "=================================" << endl;
cout << "선택: ";
}
void addIncome(Transaction transactions[], int& count, int& nextId) {
if (count >= 100) {
cout << "❌ 더 이상 추가할 수 없습니다. (최대 100개)" << endl;
return;
}
cout << "\n=== 📈 수입 추가 ===" << endl;
transactions[count].id = nextId++;
transactions[count].type = "수입";
cout << "카테고리 입력 (예: 급여, 용돈, 부업 등): ";
cin >> transactions[count].category;
cout << "금액 입력: ";
cin >> transactions[count].amount;
cout << "설명 입력: ";
cin.ignore();
getline(cin, transactions[count].description);
count++;
cout << "✅ 수입이 추가되었습니다!" << endl;
}
void addExpense(Transaction transactions[], int& count, int& nextId) {
if (count >= 100) {
cout << "❌ 더 이상 추가할 수 없습니다. (최대 100개)" << endl;
return;
}
cout << "\n=== 📉 지출 추가 ===" << endl;
transactions[count].id = nextId++;
transactions[count].type = "지출";
cout << "카테고리 입력 (예: 식비, 교통비, 쇼핑 등): ";
cin >> transactions[count].category;
cout << "금액 입력: ";
cin >> transactions[count].amount;
cout << "설명 입력: ";
cin.ignore();
getline(cin, transactions[count].description);
count++;
cout << "✅ 지출이 추가되었습니다!" << endl;
}
void showAllTransactions(Transaction transactions[], int count) {
if (count == 0) {
cout << "📝 등록된 내역이 없습니다." << endl;
return;
}
cout << "\n=== 📊 전체 거래 내역 ===" << endl;
cout << setw(4) << "ID" << setw(8) << "구분" << setw(12) << "카테고리"
<< setw(10) << "금액" << setw(20) << "설명" << endl;
cout << string(54, '-') << endl;
for (int i = 0; i < count; i++) {
cout << setw(4) << transactions[i].id
<< setw(8) << transactions[i].type
<< setw(12) << transactions[i].category
<< setw(10) << transactions[i].amount
<< setw(20) << transactions[i].description << endl;
}
}
void showCategorySummary(Transaction transactions[], int count) {
if (count == 0) {
cout << "📝 등록된 내역이 없습니다." << endl;
return;
}
cout << "\n=== 🔍 카테고리별 집계 ===" << endl;
// 수입 카테고리별 집계
cout << "\n📈 수입 카테고리:" << endl;
string incomeCategories[50];
int incomeAmounts[50] = {0};
int incomeCount = 0;
for (int i = 0; i < count; i++) {
if (transactions[i].type == "수입") {
bool found = false;
for (int j = 0; j < incomeCount; j++) {
if (incomeCategories[j] == transactions[i].category) {
incomeAmounts[j] += transactions[i].amount;
found = true;
break;
}
}
if (!found) {
incomeCategories[incomeCount] = transactions[i].category;
incomeAmounts[incomeCount] = transactions[i].amount;
incomeCount++;
}
}
}
for (int i = 0; i < incomeCount; i++) {
cout << " " << incomeCategories[i] << ": +" << incomeAmounts[i] << "원" << endl;
}
// 지출 카테고리별 집계
cout << "\n📉 지출 카테고리:" << endl;
string expenseCategories[50];
int expenseAmounts[50] = {0};
int expenseCount = 0;
for (int i = 0; i < count; i++) {
if (transactions[i].type == "지출") {
bool found = false;
for (int j = 0; j < expenseCount; j++) {
if (expenseCategories[j] == transactions[i].category) {
expenseAmounts[j] += transactions[i].amount;
found = true;
break;
}
}
if (!found) {
expenseCategories[expenseCount] = transactions[i].category;
expenseAmounts[expenseCount] = transactions[i].amount;
expenseCount++;
}
}
}
for (int i = 0; i < expenseCount; i++) {
cout << " " << expenseCategories[i] << ": -" << expenseAmounts[i] << "원" << endl;
}
}
void monthlyReport(Transaction transactions[], int count) {
if (count == 0) {
cout << "📝 등록된 내역이 없습니다." << endl;
return;
}
int totalIncome = 0;
int totalExpense = 0;
int incomeTransactions = 0;
int expenseTransactions = 0;
for (int i = 0; i < count; i++) {
if (transactions[i].type == "수입") {
totalIncome += transactions[i].amount;
incomeTransactions++;
} else {
totalExpense += transactions[i].amount;
expenseTransactions++;
}
}
cout << "\n=== 💳 월말 정산 보고서 ===" << endl;
cout << "총 수입: +" << totalIncome << "원 (" << incomeTransactions << "건)" << endl;
cout << "총 지출: -" << totalExpense << "원 (" << expenseTransactions << "건)" << endl;
cout << string(30, '-') << endl;
int balance = totalIncome - totalExpense;
if (balance > 0) {
cout << "순수익: +" << balance << "원 😊" << endl;
cout << "저축률: " << fixed << setprecision(1)
<< (double)balance / totalIncome * 100 << "%" << endl;
} else if (balance < 0) {
cout << "적자: " << balance << "원 😰" << endl;
cout << "⚠️ 지출이 수입을 " << (-balance) << "원 초과했습니다!" << endl;
} else {
cout << "수지균형: 0원 😐" << endl;
}
// 평균 계산
if (incomeTransactions > 0) {
cout << "평균 수입: " << (totalIncome / incomeTransactions) << "원" << endl;
}
if (expenseTransactions > 0) {
cout << "평균 지출: " << (totalExpense / expenseTransactions) << "원" << endl;
}
}
void deleteTransaction(Transaction transactions[], int& count) {
if (count == 0) {
cout << "📝 삭제할 내역이 없습니다." << endl;
return;
}
showAllTransactions(transactions, count);
cout << "\n삭제할 거래의 ID를 입력하세요: ";
int targetId;
cin >> targetId;
int index = -1;
for (int i = 0; i < count; i++) {
if (transactions[i].id == targetId) {
index = i;
break;
}
}
if (index == -1) {
cout << "❌ 해당 ID의 거래를 찾을 수 없습니다." << endl;
return;
}
cout << "삭제할 거래: " << transactions[index].type << " - "
<< transactions[index].category << " - " << transactions[index].amount << "원" << endl;
cout << "정말 삭제하시겠습니까? (y/n): ";
char confirm;
cin >> confirm;
if (confirm == 'y' || confirm == 'Y') {
// 배열에서 해당 원소 제거 (뒤의 원소들을 앞으로 이동)
for (int i = index; i < count - 1; i++) {
transactions[i] = transactions[i + 1];
}
count--;
cout << "✅ 거래가 삭제되었습니다." << endl;
} else {
cout << "❌ 삭제가 취소되었습니다." << endl;
}
}
int main() {
Transaction transactions[100]; // 최대 100개 거래
int transactionCount = 0;
int nextId = 1;
cout << "안녕하세요! 가계부 관리 시스템에 오신 것을 환영합니다! 💰" << endl;
int choice;
do {
displayMenu();
cin >> choice;
switch (choice) {
case 1:
addIncome(transactions, transactionCount, nextId);
break;
case 2:
addExpense(transactions, transactionCount, nextId);
break;
case 3:
showAllTransactions(transactions, transactionCount);
break;
case 4:
showCategorySummary(transactions, transactionCount);
break;
case 5:
monthlyReport(transactions, transactionCount);
break;
case 6:
deleteTransaction(transactions, transactionCount);
break;
case 0:
cout << "가계부 관리 시스템을 종료합니다. 안녕히가세요! 👋" << endl;
break;
default:
cout << "❌ 잘못된 선택입니다. 다시 선택해주세요." << endl;
}
if (choice != 0) {
cout << "\nEnter키를 누르면 메뉴로 돌아갑니다...";
cin.ignore();
cin.get();
}
} while (choice != 0);
return 0;
}
⚙️ 성능 최적화 심화
캐시 친화적 알고리즘
#include <iostream>
#include <ctime>
using namespace std;
// 비효율적인 행렬 곱셈 (캐시 미스 많음)
void matrixMultiply_Slow(int a[][1000], int b[][1000], int c[][1000], int size) {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
c[i][j] = 0;
for (int k = 0; k < size; k++) {
c[i][j] += a[i][k] * b[k][j]; // b[k][j]가 캐시 미스 유발
}
}
}
}
// 효율적인 행렬 곱셈 (캐시 친화적)
void matrixMultiply_Fast(int a[][1000], int b[][1000], int c[][1000], int size) {
// 행렬 b를 전치하여 캐시 효율성 향상
int b_transposed[1000][1000];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
b_transposed[j][i] = b[i][j];
}
}
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
c[i][j] = 0;
for (int k = 0; k < size; k++) {
c[i][j] += a[i][k] * b_transposed[j][k]; // 연속 메모리 접근
}
}
}
}
int main() {
const int SIZE = 500;
static int a[SIZE][SIZE], b[SIZE][SIZE], c1[SIZE][SIZE], c2[SIZE][SIZE];
cout << "=== 행렬 곱셈 성능 비교 ===" << endl;
cout << "행렬 크기: " << SIZE << " x " << SIZE << endl;
// 랜덤 행렬 초기화
srand(time(0));
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
a[i][j] = rand() % 10;
b[i][j] = rand() % 10;
}
}
// 일반적인 방법 측정
cout << "\n1. 일반적인 행렬 곱셈 실행 중..." << endl;
clock_t start = clock();
matrixMultiply_Slow(a, b, c1, SIZE);
clock_t end = clock();
double time1 = (double)(end - start) / CLOCKS_PER_SEC;
cout << "실행 시간: " << time1 << "초" << endl;
// 최적화된 방법 측정
cout << "\n2. 캐시 친화적 행렬 곱셈 실행 중..." << endl;
start = clock();
matrixMultiply_Fast(a, b, c2, SIZE);
end = clock();
double time2 = (double)(end - start) / CLOCKS_PER_SEC;
cout << "실행 시간: " << time2 << "초" << endl;
// 성능 비교
cout << "\n=== 성능 분석 ===" << endl;
if (time1 > time2) {
cout << "최적화된 방법이 " << (time1 / time2) << "배 빠름!" << endl;
cout << "성능 향상: " << ((time1 - time2) / time1 * 100) << "%" << endl;
} else {
cout << "일반 방법이 더 빠르거나 비슷함" << endl;
}
// 결과 검증 (일부만)
bool same = true;
for (int i = 0; i < min(10, SIZE) && same; i++) {
for (int j = 0; j < min(10, SIZE) && same; j++) {
if (c1[i][j] != c2[i][j]) {
same = false;
}
}
}
cout << "결과 검증: " << (same ? "통과 ✅" : "실패 ❌") << endl;
return 0;
}
🎯 반복문 마스터리 완성
핵심 개념 총정리
이 토픽을 통해 다음과 같은 고급 반복문 활용 능력을 키웠습니다:
🔢 수학적 알고리즘
- 소수 판별: 효율적인 sqrt() 활용법
- 유클리드 호제법: 최대공약수/최소공배수 계산
- 정렬 알고리즘: 버블정렬, 선택정렬 시각화
🎨 패턴과 도형
- 복잡한 기하학적 패턴: 속이 빈 도형, X패턴, 체스보드
- 나선형 알고리즘: 2차원 배열의 창의적 활용
- 동적 패턴 생성: 사용자 입력 기반 맞춤형 도형
🎮 게임 개발
- 상태 관리: 플레이어와 몬스터의 복합 상태 처리
- 확률 시스템: 랜덤 이벤트와 전투 메커니즘
- 사용자 인터페이스: 메뉴 시스템과 입력 검증
💰 실무 프로젝트
- 데이터 구조 설계: struct를 활용한 트랜잭션 관리
- CRUD 연산: 생성, 조회, 수정, 삭제의 완전한 구현
- 비즈니스 로직: 카테고리별 집계와 재무 분석
⚡ 성능 최적화
- 알고리즘 복잡도: 에라토스테네스의 체와 같은 효율적 알고리즘
- 캐시 최적화: 메모리 접근 패턴 개선
- 벤치마킹: 성능 측정과 비교 분석
실전 활용 가이드
문제 해결 접근법
- 문제 분석: 요구사항을 명확히 파악
- 알고리즘 설계: 효율적인 반복 구조 계획
- 구현: 단계별 코딩과 테스트
- 최적화: 성능 개선과 코드 정리
코드 품질 기준
- 가독성: 의미 있는 변수명과 적절한 주석
- 효율성: 불필요한 연산 최소화
- 안정성: 예외 상황 처리와 입력 검증
- 유지보수성: 모듈화와 재사용 가능한 구조
다음 학습 방향
이제 여러분은 반복문을 자유자재로 활용할 수 있는 수준에 도달했습니다! 다음 단계에서는:
- 함수와 모듈화: 반복되는 코드를 함수로 추상화
- 배열과 포인터: 더 복잡한 데이터 구조 다루기
- 객체지향 프로그래밍: 클래스와 객체를 통한 체계적인 설계
- 고급 알고리즘: 더 복잡하고 실용적인 문제 해결
여러분의 프로그래밍 여정이 더욱 흥미진진해질 것입니다! 💪
Last updated on