[Sprint 성취도 평가] 알고리즘과 자료구조 이론평가
문제1. File I/O의 주요 클래스들과 그 특징을 설명하고, 자료구조와 결합하여 사용하는 방법에 대해 설명하시오.
[SB] [알고리즘과 자료 구조]
문제1-1. 답변
FileInputStream: 파일의 데이터를 바이트 단위로 읽어옴FileOutputStream:: 파일에 바이트 단위로 데이터를 저장ObjectInputStream: 객체 직렬화 입력에 사용ObjectOutputStream: 객체 직렬화 출력에 사용BufferInputStream: 입력 버퍼 처리BufferOutputStream: 출력 버퍼 처리
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("파일경로")) {
Object fileData = ois.readData();
}
문제 1-2. 정리
File I/O의 주요 클래스로는 FileReader, BufferedReader, FileWriter, BufferedWriter가 있습니다. FileReader와 FileWriter는 문자 단위로 파일을 읽고 쓰는 기본적인 스트림 클래스이며, BufferedReader와 BufferedWriter는 이들을 감싸서 버퍼링 기능을 제공하는 보조 스트림 클래스입니다.
BufferedReader와 BufferedWriter는 내부적으로 버퍼를 사용하여 I/O 성능을 향상시킵니다. BufferedReader는 readLine() 메서드로 한 줄씩 읽을 수 있고, BufferedWriter는 버퍼링을 통해 출력 성능을 개선합니다.
자료구조와 File I/O를 결합할 때는, 예를 들어 ArrayList에 저장된 데이터를 파일에 저장할 때 BufferedWriter를 사용하여 각 요소를 순차적으로 파일에 쓸 수 있습니다. 반대로 파일에서 데이터를 읽어올 때는 BufferedReader로 한 줄씩 읽어 자료구조에 저장할 수 있습니다. 이를 통해 프로그램 종료 후에도 데이터를 영구적으로 보존하고, 다음 실행 시 복원할 수 있습니다.
문제 1-3. 채점 코멘트
| ✔️ File I/O 주요 클래스(FileReader, BufferedReader, FileWriter, BufferedWriter) 설명 | 1/3점 |
| ✔️ 각 클래스의 특징과 용도 설명 | 2/3점 |
| ✔️ 자료구조와 File I/O를 결합한 데이터 영구 저장 방법 설명 | 1/4점 |
✅ 잘한 부분
- FileInputStream과 FileOutputStream이 바이트 단위로 데이터를 처리한다는 점을 정확히 설명하고 있어요.
- ObjectInputStream과 ObjectOutputStream을 통해 객체 직렬화 입출력이 가능하다는 점을 잘 알고 있어요.
- 버퍼를 활용한 입출력(Buffer 계열)이 성능 개선을 위한 목적이라는 점을 인지하고 있는걸로 확인됩니다.
- try-with-resources 문법을 사용해 자원을 안전하게 처리하는 방식을 사용하고 있어요.
❗ 아쉬운 부분
- 문제에서 요구한 파일을 다루는 대표적인 클래스인 FileReader, BufferedReader, FileWriter, BufferedWriter에 대한 설명이 포함되어 있지 않아요.
- BufferInputStream, BufferOutputStream으로 작성되어 있는데, 정확한 클래스명은 BufferedInputStream, BufferedOutputStream이에요.
- 문자 기반 File I/O와 버퍼 문자 스트림의 특징(readLine 등)이 설명되지 않았어요.
- 자료구조(List, ArrayList, Map 등)와 File I/O를 결합해 데이터를 저장하고 복원하는 흐름이 구체적으로 드러나지 않아요.
- 예제 코드가 객체 직렬화 자체에만 집중되어 있어 문제 해설에서 요구한 텍스트 기반 영구 저장 방식과는 방향이 달라요.
📚 더 공부하면 좋은 내용
- FileReader, FileWriter와 BufferedReader, BufferedWriter를 중심으로 문자 기반 File I/O 흐름을 다시 정리해 보면 좋아요.
- BufferedReader로 파일을 한 줄씩 읽어 ArrayList에 저장하고, BufferedWriter로 다시 파일에 저장하는 기본 예제를 작성해 보면 좋아요.
- 객체 직렬화 방식과 텍스트 파일 기반 저장 방식의 차이와 각각의 사용 목적을 비교해 보면 도움이 될 거에요. Buffered 계열 클래스의 정확한 명칭과 역할을 정리해 두면 실수 없이 사용할 수 있어요.
문제2. 제네릭의 개념과 컬렉션 프레임워크에서의 활용에 대해 설명하시오.
[SB] [알고리즘과 자료 구조]
문제 2-1. 답변
- 제네릭 :
<>으로 사용하고, 타입을 유동성 있게 하는 것
문제 2-2. 정리
제네릭은 클래스나 메서드가 다양한 데이터 타입에 대해 동작할 수 있도록 일반화하는 기능입니다. 컴파일 시점에 타입을 체크하여 타입 안정성을 보장하고, 불필요한 타입 캐스팅을 줄여 코드의 재사용성을 높입니다. 제네릭은 컴파일 시점에서 타입을 체크함으로써 런타임 에러를 방지합니다. 예를 들어, List으로 선언된 리스트에 정수를 추가하려고 하면 컴파일 오류가 발생하여 잠재적인 오류를 사전에 방지할 수 있습니다. 컬렉션 프레임워크에서는 List, Set, Map<K,V>와 같이 제네릭을 활용합니다. 예를 들어, List는 정수만을 저장할 수 있는 리스트를 생성하고, Map<String, Student>는 문자열 키와 Student 객체 값을 가지는 맵을 생성합니다. 이를 통해 컬렉션에 저장되는 데이터의 타입을 명확히 하고, 타입 관련 오류를 컴파일 단계에서 잡아낼 수 있습니다.
문제 2-3. 채점 코멘트
| ✔️ 제네릭의 기본 개념과 필요성 설명 | 1/3점 |
| ✔️ 제네릭이 제공하는 타입 안정성 설명 | ****- |
| ✔️ 컬렉션 프레임워크에서 제네릭 활용 예시 제시 | 1/4점 |
✅ 잘한 부분
- 제네릭이 <> 문법을 사용한다는 점을 정확하게 언급하고 있어요.
- 타입을 고정하지 않고 유연하게 사용할 수 있다는 핵심 방향성은 잘 짚고 있어요.
❗ 아쉬운 부분
- 제네릭이 왜 필요한지에 대한 설명이 부족해요. 타입 안정성이나 코드 재사용성과의 연결이 나타나지 않아요.
- 컴파일 시점에서 타입 오류를 방지한다는 제네릭의 중요한 역할이 설명되지 않았어요.
- 컬렉션 프레임워크와의 관계가 전혀 드러나지 않아요. List, Set, Map 등의 실제 활용 예시가 필요해요.
📚 더 공부하면 좋은 내용
- 제네릭을 사용하지 않은 List와 List을 비교해서 어떤 차이가 생기는지 코드로 정리해보세요.
- 잘못된 타입을 컬렉션에 넣으려고 할 때 컴파일 에러가 발생하는 예제를 직접 작성해보세요.
- List, Set, Map<K, V>에서 각각 제네릭이 어떤 역할을 하는지 하나씩 정리해보세요.
- 제네릭이 없던 시절 Object 기반 컬렉션에서 왜 형 변환 문제가 자주 발생했는지도 함께 살펴보면 좋아요.
- 제네릭 클래스와 제네릭 메서드의 차이를 간단한 예제로 구분해보는 연습도 도움이 돼요.
문제3. Big O 표기법의 개념과 필요성에 대해 설명하고, 일상생활의 예시를 들어 O(1), O(n), O(log n), O(n^2)을 비교하여 설명하세요.
[SB] [알고리즘과 자료 구조]
문제 3-1. 답변
Big O 표기법은 입력값에 대한 최악의 경우를 표현하는 방법으로, 최악의 경우를 상정하여 대비할 수 있게 한다.
예시
- O(1) : 아파트 우편함에서 본인 집 우편물 가져가는 것처럼 입력 값 상관없이 바로 찾을 수 있음
- O(n) : 입력값에 비례, 반복문
- O(log n) : 입력값을 절반으로 나눠서 탐색
- O(n^2) : 입력값 하나하나에 대해서 입력 값의 개수 만큼 탐색 반복, 중첩 반복문
문제 3-2. 정리
Big O 표기법은 알고리즘의 성능을 나타내는 방법으로, 알고리즘이 얼마나 빠르고 효율적인지를 수치화한 것입니다. 입력 크기가 커질 때 알고리즘의 실행 시간이 어떻게 증가하는지 예측할 수 있게 해주므로, 효율적인 프로그램 설계에 필수적입니다.
O(1)은 상수 시간으로, 입력 크기와 상관없이 항상 동일한 시간이 소요됩니다. 예를 들어, 도서관에서 도서 위치 시스템을 통해 특정 책의 위치를 즉시 찾는 경우입니다. 책이 몇 권이 있든 상관없이 동일한 시간이 걸립니다.
O(n)은 선형 시간으로, 입력 크기에 비례하여 시간이 증가합니다. 예를 들어, 정리되지 않은 책장에서 특정 책을 찾기 위해 한 권씩 순차적으로 확인해야 하는 경우입니다. 책이 많아질수록 찾는 시간이 비례하여 증가합니다.
O(log n)은 로그 시간으로, 입력이 커질수록 시간이 천천히 증가합니다. 예를 들어, 도서관에서 분류번호순으로 정렬된 책장에서 책을 찾을 때, 중간 지점부터 시작해서 찾고자 하는 책이 앞쪽에 있는지 뒤쪽에 있는지 판단하며 범위를 반씩 좁혀가는 경우입니다.
O(n^2)은 이차 시간으로, 입력 크기의 제곱만큼 시간이 증가합니다. 예를 들어, 도서관의 모든 책과 다른 도서관의 모든 책을 한 권씩 비교하여 중복 도서를 찾는 경우입니다. 각 도서관의 책 수가 n권이라면, 총 n x n번의 비교가 필요하므로 책의 수가 증가할수록 비교 시간이 제곱으로 증가합니다.
문제 3-3. 채점 코멘트
| ✔️ Big O 표기법의 개념과 필요성을 정확히 설명 | 2.5/3점 |
| ✔️ O(1), O(n), O(log n), O(n^2)의 특징을 정확히 설명 | 3/4점 |
| ✔️ 각각의 시간 복잡도를 일상생활의 적절한 예시와 연관지어 설명 | 2.5/3점 |
✅ 잘한 부분
- Big O 표기법을 최악의 경우 기준으로 성능을 판단하는 개념으로 정확하게 짚고 있어요.
- O(1), O(n), O(log n), O(n^2)를 모두 빠짐없이 언급하고 있고, 각각의 증가 방식도 잘 구분하고 있어요.
- O(1)에 대해 아파트 우편함 예시를 들어 입력 크기와 무관하다는 점을 잘 표현하고 있어요.
❗ 아쉬운 부분
- Big O 표기법이 왜 필요한지에 대한 설명이 한 문장으로 다소 짧게 정리되어 있어요.
- O(n), O(log n), O(n^2)는 반복문 구조 중심으로 설명되어 있어 일상생활 예시가 상대적으로 부족해요.
- O(log n)의 특징에서 왜 절반씩 줄어드는지가 한 번 더 풀어 설명되었으면 좋았을 것 같아요.
📚 더 공부하면 좋은 내용
- 반복문 구조를 실제 생활 상황으로 바꾸어 설명하는 연습을 해보면 좋아요.
- O(n)과 O(n^2)가 데이터가 커질수록 얼마나 큰 차이를 만드는지 수치 예시로 비교해보는 것도 도움이 돼요.
- 같은 문제를 서로 다른 시간 복잡도로 해결하는 사례를 찾아보면 개념이 더 명확해질 거에요.
문제4. 시간 복잡도와 공간 복잡도의 차이를 설명하고, O(n^2)의 특징과 실제 알고리즘에서의 예시를 들어 설명하시오. 또한 이를 개선할 수 있는 방법에 대해 서술하세요.
[SB] [알고리즘과 자료 구조]
문제 4-1. 답변
시간 복잡도는 일을 처리하는데 걸리는 시간, 공간 복잡도는 일을 처리하는데 사용되는 메모리(잠깐동안 존재하는 데이터도 포함)
O(n^2)는 입력값 하나하나에 대해서 입력 값의 개수 만큼 탐색 반복하므로, 입력값이 커지면 처리 시간이 증가
- 예시: 중첩 반복문
- 개선 방법: 코드 리팩토링
문제 4-2. 정리
시간 복잡도는 알고리즘이 실행되는 데 걸리는 시간을 나타내며, 입력이 많아질 때 처리 시간이 어떻게 증가하는지를 분석합니다. 반면 공간 복잡도는 알고리즘이 실행되면서 사용하는 메모리 양을 의미하며, 얼마나 많은 추가 메모리가 필요한지를 나타냅니다.
O(n^2)는 이차 시간 복잡도로, 입력 크기의 제곱만큼 시간이 소요됩니다. 대표적인 예시로 중첩된 반복문이 있습니다. 예를 들어, 학생들이 서로 인사를 하는 상황처럼, 각 학생이 다른 모든 학생과 인사를 해야 하는 경우 학생 수가 늘어날수록 인사 횟수가 제곱으로 증가합니다.
O(n^2) 알고리즘의 개선 방법으로는 다음과 같은 것들이 있습니다:
- 불필요한 반복 제거 (예: 이미 처리한 데이터는 다시 처리하지 않기)
- 효율적인 자료구조 활용 (예: HashMap을 사용하여 검색 시간 단축)
- 분할 정복 방식 적용 (예: O(n log n)의 병합 정렬 활용)
문제 4-3. 채점 코멘트
| ✔️ 시간 복잡도와 공간 복잡도의 차이점 설명 | 2/3점 |
| ✔️ O(n^2)의 특징과 실제 알고리즘 예시 설명 | 1/3점 |
| ✔️ O(n^2) 알고리즘의 개선 방법 제시 | 1/4점 |
✅ 잘한 부분
- 시간 복잡도와 공간 복잡도를 각각 실행 시간과 메모리 사용량의 관점으로 구분하고 있어요.
- 공간 복잡도 설명에서 일시적으로 사용되는 메모리까지 포함한다는 점을 언급한 것은 개념적으로 정확해요.
- O(n^2)가 입력값 하나당 전체 입력을 반복 탐색한다는 핵심 특징을 잘 짚고 있어요.
❗ 아쉬운 부분
- O(n^2)의 실제 알고리즘 예시가 구체적으로 제시되지 않았어요. 버블 정렬이나 선택 정렬 같은 대표적인 알고리즘이 함께 언급되었으면 더 좋았을 것 같아요.
- 개선 방법에서 코드 리팩토링이라는 표현이 다소 추상적이에요. 어떤 방식으로 반복을 줄이거나 구조를 바꾸는지에 대한 설명이 필요해요.
- 시간 복잡도와 공간 복잡도의 차이에 대한 설명이 간결한 대신, 입력 크기 증가에 따른 변화 관점이 조금 더 보완되면 좋겠어요.
📚 더 공부하면 좋은 내용
- 이중 반복문이 왜 O(n^2)가 되는지 간단한 코드 예제를 통해 다시 정리해보면 좋아요.
- 버블 정렬, 선택 정렬 같은 O(n^2) 정렬 알고리즘의 동작 과정을 직접 비교해보세요.
- 코드 리팩토링 관점에서 불필요한 반복 제거, 자료구조 변경(HashMap, Set 활용) 같은 구체적인 개선 사례를 함께 학습하면 이해가 더 깊어질 거에요.
문제5. ArrayList와 LinkedList의 데이터 삽입/삭제/검색 작업에서의 시간 복잡도 차이가 발생하는 이유를 설명하세요.
[SB] [알고리즘과 자료 구조]
문제 5-1. 답변
ArrayList에 있는 데이터는 순서가 존재하여, 해당 인덱스를 통해 원하는 위치로 바로 이동할 수 있지만, LinkedList는 순서가 없어, 처음부터 순회해서 찾아야 하기 때문에 시간 복잡도의 차이가 발생한다.
문제 5-2. 정리
ArrayList는 연속된 메모리 공간에 데이터를 저장하는 자료구조로, 특정 위치의 데이터를 찾는 것은 O(1)이지만, 중간에 데이터를 삽입하거나 삭제할 때는 O(n)이 소요됩니다. 이는 데이터 삽입/삭제 시 다른 모든 요소들을 이동시켜야 하기 때문입니다.
LinkedList는 각 노드가 다음 노드를 참조하는 구조로, 중간에 데이터를 삽입하거나 삭제하는 것은 O(1)이지만, 특정 데이터를 찾는 것은 O(n)이 소요됩니다. 이는 원하는 위치까지 순차적으로 이동해야 하기 때문입니다.
문제 5-3. 채점 코멘트
| ✔️ ArrayList와 LinkedList의 시간 복잡도 비교 설명 | 2/5점 |
| ✔️ 각 자료 구조의 삽입/삭제/검색 시간 복잡도 차이의 원인 설명 | 2/5점 |
✅ 잘한 부분
- ArrayList는 인덱스를 통해 원하는 위치로 바로 접근할 수 있고, LinkedList는 순차적으로 탐색해야 한다는 점을 정확히 이해하고 있어요.
- 두 자료 구조의 검색 방식 차이로 인해 시간 복잡도가 달라진다는 핵심 원인을 간단하게 잘 짚고 있어요.
❗ 아쉬운 부분
- 삽입과 삭제 연산에 대한 설명이 전혀 포함되지 않은점이 아주 아쉬웠어요.
- ArrayList와 LinkedList의 시간 복잡도를 O(1), O(n)과 같이 구체적인 수치로 비교하지 않아 설명이 다소 추상적으로 느껴져요.
- LinkedList를 “순서가 없다”고 표현했는데, 실제로는 순서가 없기보다는 인덱스 기반 접근이 불가능하다는 점에서 차이가 있어요.
📚 더 공부하면 좋은 내용
- ArrayList에서 중간 삽입/삭제 시 왜 요소 이동이 발생하는지 예시를 통해 다시 정리해보면 좋아요.
- LinkedList의 삽입/삭제가 빠른 이유와, 위치 탐색이 선행될 경우 시간 복잡도가 어떻게 달라지는지도 함께 학습해보세요.
- 삽입, 삭제, 검색 각각의 연산을 표 형태로 정리해 비교해보면 개념이 더 명확해질 거에요.
Leave a comment