챕터8. 실습 문제
2025. 3. 28. 08:58ㆍProgramming Languages/C++
8.6 실습 문제
문제 1: 학생 성적 관리 시스템
STL 컨테이너와 알고리즘을 사용하여 학생 성적을 관리하는 프로그램을 작성하세요:
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <numeric>
#include <iomanip>
// 학생 정보를 담는 구조체
struct Student {
std::string name;
std::string id;
std::vector<int> scores; // 여러 과목 점수
// 평균 점수 계산
double getAverage() const {
if (scores.empty()) return 0.0;
return static_cast<double>(std::accumulate(scores.begin(), scores.end(), 0)) / scores.size();
}
// 총점 계산
int getTotal() const {
return std::accumulate(scores.begin(), scores.end(), 0);
}
};
// 학생 정보 출력 함수
void printStudent(const Student& student) {
std::cout << "이름: " << student.name << ", 학번: " << student.id << std::endl;
std::cout << "점수: ";
for (const auto& score : student.scores) {
std::cout << score << " ";
}
std::cout << std::endl;
std::cout << "평균: " << std::fixed << std::setprecision(2) << student.getAverage() << std::endl;
std::cout << "총점: " << student.getTotal() << std::endl;
std::cout << "-------------------------" << std::endl;
}
class StudentManager {
private:
std::vector<Student> students;
std::map<std::string, size_t> studentMap; // 학번 -> 인덱스 매핑
public:
// 학생 추가
void addStudent(const Student& student) {
// 이미 존재하는 학번인지 확인
if (studentMap.find(student.id) != studentMap.end()) {
std::cout << "오류: 이미 존재하는 학번입니다." << std::endl;
return;
}
studentMap[student.id] = students.size();
students.push_back(student);
std::cout << student.name << " 학생이 추가되었습니다." << std::endl;
}
// 학생 검색 (학번으로)
bool findStudent(const std::string& id, Student& outStudent) const {
auto it = studentMap.find(id);
if (it != studentMap.end()) {
outStudent = students[it->second];
return true;
}
return false;
}
// 학생 정보 갱신
bool updateStudent(const std::string& id, const Student& newInfo) {
auto it = studentMap.find(id);
if (it != studentMap.end()) {
// 학번은 변경하지 않음
students[it->second].name = newInfo.name;
students[it->second].scores = newInfo.scores;
return true;
}
return false;
}
// 학생 삭제
bool removeStudent(const std::string& id) {
auto it = studentMap.find(id);
if (it != studentMap.end()) {
size_t index = it->second;
std::string name = students[index].name;
// 학생 제거 및 맵 갱신
students.erase(students.begin() + index);
studentMap.erase(id);
// 맵의 인덱스 업데이트 (삭제된 이후의 학생들)
for (auto& pair : studentMap) {
if (pair.second > index) {
pair.second--;
}
}
std::cout << name << " 학생이 삭제되었습니다." << std::endl;
return true;
}
return false;
}
// 모든 학생 출력
void printAllStudents() const {
if (students.empty()) {
std::cout << "등록된 학생이 없습니다." << std::endl;
return;
}
std::cout << "학생 목록 (" << students.size() << "명):" << std::endl;
std::cout << "==========================" << std::endl;
for (const auto& student : students) {
printStudent(student);
}
}
// 성적순으로 정렬하여 출력
void printStudentsByGrade() const {
if (students.empty()) {
std::cout << "등록된 학생이 없습니다." << std::endl;
return;
}
// 학생 복사 후 정렬
std::vector<Student> sortedStudents = students;
std::sort(sortedStudents.begin(), sortedStudents.end(),
[](const Student& a, const Student& b) {
return a.getAverage() > b.getAverage(); // 내림차순 정렬
});
std::cout << "성적순 학생 목록 (" << sortedStudents.size() << "명):" << std::endl;
std::cout << "==========================" << std::endl;
for (size_t i = 0; i < sortedStudents.size(); i++) {
std::cout << (i + 1) << "등: ";
printStudent(sortedStudents[i]);
}
}
// 특정 점수 이상인 학생 출력
void printStudentsAboveScore(int minScore) const {
auto isAboveScore = [minScore](const Student& s) {
return s.getAverage() >= minScore;
};
// 조건을 만족하는 학생 수 세기
int count = std::count_if(students.begin(), students.end(), isAboveScore);
if (count == 0) {
std::cout << minScore << "점 이상인 학생이 없습니다." << std::endl;
return;
}
std::cout << minScore << "점 이상인 학생 목록 (" << count << "명):" << std::endl;
std::cout << "==========================" << std::endl;
// 조건을 만족하는 학생 출력
for (const auto& student : students) {
if (isAboveScore(student)) {
printStudent(student);
}
}
}
// 통계 출력
void printStatistics() const {
if (students.empty()) {
std::cout << "등록된 학생이 없습니다." << std::endl;
return;
}
// 모든 학생의 평균 점수 계산
std::vector<double> averages;
for (const auto& student : students) {
averages.push_back(student.getAverage());
}
// 전체 평균
double totalAverage = std::accumulate(averages.begin(), averages.end(), 0.0) / averages.size();
// 최고/최저 평균
auto minmax = std::minmax_element(averages.begin(), averages.end());
double minAverage = *minmax.first;
double maxAverage = *minmax.second;
// 최고/최저 학생 찾기
auto maxStudent = std::max_element(students.begin(), students.end(),
[](const Student& a, const Student& b) {
return a.getAverage() < b.getAverage();
});
auto minStudent = std::min_element(students.begin(), students.end(),
[](const Student& a, const Student& b) {
return a.getAverage() < b.getAverage();
});
// 통계 출력
std::cout << "학생 통계:" << std::endl;
std::cout << "==========================" << std::endl;
std::cout << "전체 학생 수: " << students.size() << "명" << std::endl;
std::cout << "전체 평균: " << std::fixed << std::setprecision(2) << totalAverage << std::endl;
std::cout << "최고 평균: " << maxAverage << " (" << maxStudent->name << ", " << maxStudent->id << ")" << std::endl;
std::cout << "최저 평균: " << minAverage << " (" << minStudent->name << ", " << minStudent->id << ")" << std::endl;
}
};
int main() {
StudentManager manager;
// 샘플 학생 데이터 추가
Student s1 = {"홍길동", "S001", {85, 90, 78, 92, 88}};
Student s2 = {"김철수", "S002", {76, 82, 95, 89, 90}};
Student s3 = {"이영희", "S003", {92, 96, 91, 95, 89}};
Student s4 = {"박민수", "S004", {68, 72, 78, 65, 70}};
Student s5 = {"정지원", "S005", {88, 85, 92, 97, 91}};
manager.addStudent(s1);
manager.addStudent(s2);
manager.addStudent(s3);
manager.addStudent(s4);
manager.addStudent(s5);
int choice;
bool running = true;
while (running) {
std::cout << "\n학생 성적 관리 시스템" << std::endl;
std::cout << "1. 학생 목록 출력" << std::endl;
std::cout << "2. 성적순 학생 목록 출력" << std::endl;
std::cout << "3. 학생 검색" << std::endl;
std::cout << "4. 학생 추가" << std::endl;
std::cout << "5. 학생 정보 수정" << std::endl;
std::cout << "6. 학생 삭제" << std::endl;
std::cout << "7. 특정 점수 이상 학생 출력" << std::endl;
std::cout << "8. 학생 통계 보기" << std::endl;
std::cout << "0. 종료" << std::endl;
std::cout << "선택: ";
std::cin >> choice;
switch (choice) {
case 1:
manager.printAllStudents();
break;
case 2:
manager.printStudentsByGrade();
break;
case 3: {
std::string id;
std::cout << "검색할 학번: ";
std::cin >> id;
Student found;
if (manager.findStudent(id, found)) {
std::cout << "학생 정보:" << std::endl;
std::cout << "==========================" << std::endl;
printStudent(found);
} else {
std::cout << "학번 " << id << "인 학생을 찾을 수 없습니다." << std::endl;
}
break;
}
case 4: {
Student newStudent;
std::cout << "이름: ";
std::cin >> newStudent.name;
std::cout << "학번: ";
std::cin >> newStudent.id;
int numScores;
std::cout << "과목 수: ";
std::cin >> numScores;
newStudent.scores.resize(numScores);
for (int i = 0; i < numScores; i++) {
std::cout << "과목 " << (i + 1) << " 점수: ";
std::cin >> newStudent.scores[i];
}
manager.addStudent(newStudent);
break;
}
case 5: {
std::string id;
std::cout << "수정할 학생의 학번: ";
std::cin >> id;
Student found;
if (manager.findStudent(id, found)) {
std::cout << "현재 정보:" << std::endl;
printStudent(found);
std::cout << "새 이름 (현재: " << found.name << "): ";
std::cin >> found.name;
int numScores;
std::cout << "새 과목 수 (현재: " << found.scores.size() << "): ";
std::cin >> numScores;
found.scores.resize(numScores);
for (int i = 0; i < numScores; i++) {
std::cout << "과목 " << (i + 1) << " 점수: ";
std::cin >> found.scores[i];
}
if (manager.updateStudent(id, found)) {
std::cout << "학생 정보가 업데이트되었습니다." << std::endl;
} else {
std::cout << "업데이트 실패!" << std::endl;
}
} else {
std::cout << "학번 " << id << "인 학생을 찾을 수 없습니다." << std::endl;
}
break;
}
case 6: {
std::string id;
std::cout << "삭제할 학생의 학번: ";
std::cin >> id;
if (!manager.removeStudent(id)) {
std::cout << "학번 " << id << "인 학생을 찾을 수 없습니다." << std::endl;
}
break;
}
case 7: {
int minScore;
std::cout << "최소 점수: ";
std::cin >> minScore;
manager.printStudentsAboveScore(minScore);
break;
}
case 8:
manager.printStatistics();
break;
case 0:
running = false;
std::cout << "프로그램을 종료합니다." << std::endl;
break;
default:
std::cout << "잘못된 선택입니다. 다시 시도하세요." << std::endl;
}
}
return 0;
}
문제 2: 문자열 처리 유틸리티
STL 알고리즘과 컨테이너를 사용한 문자열 처리 유틸리티를 구현하세요:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <iomanip>
class StringUtils {
public:
// 문자열 분할
static std::vector<std::string> split(const std::string& str, char delimiter = ' ') {
std::vector<std::string> tokens;
std::stringstream ss(str);
std::string token;
while (std::getline(ss, token, delimiter)) {
if (!token.empty()) { // 빈 토큰 제외
tokens.push_back(token);
}
}
return tokens;
}
// 문자열 합치기
static std::string join(const std::vector<std::string>& tokens, const std::string& delimiter = " ") {
if (tokens.empty()) return "";
std::string result = tokens[0];
for (size_t i = 1; i < tokens.size(); i++) {
result += delimiter + tokens[i];
}
return result;
}
// 대소문자 변환
static std::string toUpper(const std::string& str) {
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return std::toupper(c); });
return result;
}
static std::string toLower(const std::string& str) {
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return std::tolower(c); });
return result;
}
// 단어 빈도 계산
static std::map<std::string, int> wordFrequency(const std::string& text) {
std::vector<std::string> words = split(text);
std::map<std::string, int> freq;
for (const auto& word : words) {
// 구두점 제거 및 소문자 변환
std::string cleanWord;
std::copy_if(word.begin(), word.end(), std::back_inserter(cleanWord),
[](char c) { return std::isalnum(c); });
if (!cleanWord.empty()) {
cleanWord = toLower(cleanWord);
freq[cleanWord]++;
}
}
return freq;
}
// 문자열 앞뒤 공백 제거
static std::string trim(const std::string& str) {
auto start = std::find_if_not(str.begin(), str.end(),
[](unsigned char c) { return std::isspace(c); });
auto end = std::find_if_not(str.rbegin(), str.rend(),
[](unsigned char c) { return std::isspace(c); }).base();
return (start < end) ? std::string(start, end) : "";
}
// 부분 문자열 교체
static std::string replace(const std::string& str, const std::string& from, const std::string& to) {
std::string result = str;
size_t pos = 0;
while ((pos = result.find(from, pos)) != std::string::npos) {
result.replace(pos, from.length(), to);
pos += to.length();
}
return result;
}
// 회문(palindrome) 검사
static bool isPalindrome(const std::string& str) {
// 알파벳만 추출하고 소문자로 변환
std::string cleaned;
std::copy_if(str.begin(), str.end(), std::back_inserter(cleaned),
[](char c) { return std::isalpha(c); });
cleaned = toLower(cleaned);
if (cleaned.empty()) return false;
// 원본과 뒤집은 문자열 비교
std::string reversed = cleaned;
std::reverse(reversed.begin(), reversed.end());
return cleaned == reversed;
}
// 문자열에서 특정 문자 제거
static std::string removeChars(const std::string& str, const std::string& chars) {
std::string result = str;
for (char c : chars) {
result.erase(std::remove(result.begin(), result.end(), c), result.end());
}
return result;
}
// 문자열에서 고유한 문자 찾기
static std::set<char> uniqueChars(const std::string& str) {
std::set<char> result(str.begin(), str.end());
return result;
}
// 두 문자열의 애너그램(anagram) 여부 확인
static bool areAnagrams(const std::string& str1, const std::string& str2) {
// 대소문자 무시, 공백 및 구두점 제거
auto cleanString = [](const std::string& s) {
std::string result;
std::copy_if(s.begin(), s.end(), std::back_inserter(result),
[](char c) { return std::isalpha(c); });
return toLower(result);
};
std::string s1 = cleanString(str1);
std::string s2 = cleanString(str2);
if (s1.length() != s2.length()) return false;
std::sort(s1.begin(), s1.end());
std::sort(s2.begin(), s2.end());
return s1 == s2;
}
};
int main() {
int choice;
bool running = true;
while (running) {
std::cout << "\n문자열 처리 유틸리티" << std::endl;
std::cout << "1. 문자열 분할" << std::endl;
std::cout << "2. 문자열 합치기" << std::endl;
std::cout << "3. 대문자/소문자 변환" << std::endl;
std::cout << "4. 단어 빈도 계산" << std::endl;
std::cout << "5. 문자열 앞뒤 공백 제거" << std::endl;
std::cout << "6. 부분 문자열 교체" << std::endl;
std::cout << "7. 회문(Palindrome) 검사" << std::endl;
std::cout << "8. 특정 문자 제거" << std::endl;
std::cout << "9. 고유 문자 찾기" << std::endl;
std::cout << "10. 애너그램(Anagram) 검사" << std::endl;
std::cout << "0. 종료" << std::endl;
std::cout << "선택: ";
std::cin >> choice;
std::cin.ignore(); // 입력 버퍼 비우기
std::string input, input2, delimiter;
std::vector<std::string> tokens;
switch (choice) {
case 1: // 문자열 분할
std::cout << "문자열 입력: ";
std::getline(std::cin, input);
std::cout << "구분자 입력 (단일 문자): ";
std::cin >> delimiter;
tokens = StringUtils::split(input, delimiter[0]);
std::cout << "분할 결과 (" << tokens.size() << "개):" << std::endl;
for (size_t i = 0; i < tokens.size(); i++) {
std::cout << i + 1 << ": \"" << tokens[i] << "\"" << std::endl;
}
break;
case 2: // 문자열 합치기
std::cout << "합칠 문자열 개수: ";
int count;
std::cin >> count;
std::cin.ignore();
tokens.clear();
for (int i = 0; i < count; i++) {
std::cout << "문자열 " << i + 1 << ": ";
std::getline(std::cin, input);
tokens.push_back(input);
}
std::cout << "구분자 입력: ";
std::getline(std::cin, delimiter);
std::cout << "합친 결과: \"" << StringUtils::join(tokens, delimiter) << "\"" << std::endl;
break;
case 3: // 대문자/소문자 변환
std::cout << "문자열 입력: ";
std::getline(std::cin, input);
std::cout << "대문자 변환: \"" << StringUtils::toUpper(input) << "\"" << std::endl;
std::cout << "소문자 변환: \"" << StringUtils::toLower(input) << "\"" << std::endl;
break;
case 4: // 단어 빈도 계산
std::cout << "텍스트 입력: ";
std::getline(std::cin, input);
std::map<std::string, int> freq = StringUtils::wordFrequency(input);
std::cout << "단어 빈도 (총 " << freq.size() << "개):" << std::endl;
for (const auto& pair : freq) {
std::cout << std::setw(15) << std::left << pair.first << ": "
<< pair.second << "회" << std::endl;
}
break;
case 5: // 문자열 앞뒤 공백 제거
std::cout << "문자열 입력: ";
std::getline(std::cin, input);
std::cout << "원본: \"" << input << "\"" << std::endl;
std::cout << "공백 제거 후: \"" << StringUtils::trim(input) << "\"" << std::endl;
break;
case 6: // 부분 문자열 교체
std::cout << "원본 문자열: ";
std::getline(std::cin, input);
std::cout << "찾을 문자열: ";
std::getline(std::cin, input2);
std::cout << "바꿀 문자열: ";
std::getline(std::cin, delimiter);
std::cout << "교체 결과: \"" << StringUtils::replace(input, input2, delimiter) << "\"" << std::endl;
break;
case 7: // 회문 검사
std::cout << "검사할 문자열: ";
std::getline(std::cin, input);
if (StringUtils::isPalindrome(input)) {
std::cout << "\"" << input << "\"은(는) 회문입니다." << std::endl;
} else {
std::cout << "\"" << input << "\"은(는) 회문이 아닙니다." << std::endl;
}
break;
case 8: // 특정 문자 제거
std::cout << "원본 문자열: ";
std::getline(std::cin, input);
std::cout << "제거할 문자들: ";
std::getline(std::cin, input2);
std::cout << "제거 결과: \"" << StringUtils::removeChars(input, input2) << "\"" << std::endl;
break;
case 9: // 고유 문자 찾기
std::cout << "문자열 입력: ";
std::getline(std::cin, input);
std::set<char> uniqueChars = StringUtils::uniqueChars(input);
std::cout << "고유 문자 (" << uniqueChars.size() << "개): ";
for (char c : uniqueChars) {
if (c == ' ') {
std::cout << "' ' ";
} else {
std::cout << c << " ";
}
}
std::cout << std::endl;
break;
case 10: // 애너그램 검사
std::cout << "첫 번째 문자열: ";
std::getline(std::cin, input);
std::cout << "두 번째 문자열: ";
std::getline(std::cin, input2);
if (StringUtils::areAnagrams(input, input2)) {
std::cout << "두 문자열은 애너그램입니다." << std::endl;
} else {
std::cout << "두 문자열은 애너그램이 아닙니다." << std::endl;
}
break;
case 0:
running = false;
std::cout << "프로그램을 종료합니다." << std::endl;
break;
default:
std::cout << "잘못된 선택입니다. 다시 시도하세요." << std::endl;
}
}
return 0;
}
'Programming Languages > C++' 카테고리의 다른 글
파일 입출력 (0) | 2025.03.28 |
---|---|
고급 주제 (0) | 2025.03.28 |
함수 객체와 람다 표현식 (0) | 2025.03.28 |
STL 알고리즘 (0) | 2025.03.28 |
STL 반복자 (0) | 2025.03.28 |