
인프런 워밍업 클럽 3기 CS - 2주차 미션
2주차 학습 내용 - 미션
자료구조 & 알고리즘
1. 재귀함수에서 기저조건을 만들지 않거나 잘못 설정했을 때 어떤 문제가 발생할 수 있나요?
기저조건을 만들지 않으면 함수가 계속 실행되서 콜스택이 메모리에 쌓이게 되고, 각자의 메모리 용량에 따라 다르겠지만 메모리끝에 다다르게 되면 실행이 종료된다. 그것을 스택 오버플로우 오류라고 한다.
2. 0부터 입력 n까지 홀수의 합을 더하는 재귀 함수를 만들어보세요.
function sumOdd(n) {
if (n % 2 !== 0) { // 홀수가 되는 경우
return n + sumOdd(n - 1);
} else if (n === 0) { // 종료가 되는 경우
return 0;
} else { // 짝수가 되는 경우
return sumOdd(n - 1);
}
}
console.log(sumOdd(10)); // 25
이 방법이 100점짜리 정답인지는 모르겠지만 우선 sumOdd 값에 다른 수를 넣어도 홀수의 합만 뽑아서 더하고 있다.
로직은 3가지의 조건으로 나뉘고 있다.
n이 홀수인경우 n을 더하고 n-1한 sumOdd 함수를 재호출
n이 0인경우 0을 리턴하며 종료
n이 짝수인 경우 n을 더하지는 않고 n-1한 sumOdd 함수를 재호출
이로써
sumOdd(10)
을 할 경우 25(1+3+5+7+9)라는 값이 나오게 됨.
3. 다음 코드는 매개변수로 주어진 파일 경로(.는 현재 디렉토리)에 있는 하위 모든 파일과 디렉토리를 출력하는 코드입니다. 다음 코드를 재귀 함수를 이용하는 코드로 변경해보세요.
const fs = require("fs"); // 파일을 이용하는 모듈
const path = require("path"); // 폴더와 파일의 경로를 지정해주는 모듈
function traverseDirectoryRecursive(directory) {
const files = readdirSync(directory); // 현재 디렉토리의 파일 및 폴더 가져오기
for (const file of files) {
const filePath = join(directory, file);
const fileStatus = statSync(filePath);
if (fileStatus.isDirectory()) {
console.log("디렉토리:", filePath);
traverseDirectoryRecursive(filePath); // 🔥 폴더라면 재귀 호출 (스택 역할)
} else {
console.log("파일:", filePath);
}
}
}
traverseDirectoryRecursive(".")
이 문제의 경우 솔직히 너무 힘들었음..... (나한텐 어려워😐)
gpt.. 의 힘을 빌려 성공하긴 했지만 이 코드를 봐도 이해하기 힘들어서 재귀가 눈에 익게 자주 문제를 풀어보고 생각해야할 것 같다.
✅ 재귀 함수 정의
function traverseDirectoryRecursive(directory) {
const files = readdirSync(directory); // 현재 디렉토리의 파일 및 폴더 목록 가져오기
traverseDirectoryRecursive(directory)
:directory
를 입력받아 해당 폴더 내의 파일과 폴더를 탐색하는 함수
readdirSync(directory)
:해당 디렉토리 안에 있는 파일/폴더 목록을 배열로 반환
✅ for문을 사용하여 모든 파일 및 폴더를 탐색
for (const file of files) {
const filePath = join(directory, file); // 전체 경로 생성
const fileStatus = statSync(filePath); // 파일 정보 가져오기
for (const file of files)
:files
배열 안의 파일 또는 폴더를 하나씩 순회
join(directory, file)
:현재 디렉토리 경로 + 파일 이름을 합쳐서 파일의 전체 경로 생성
statSync(filePath)
:해당 경로가 파일인지 폴더인지 확인할 수 있는 정보 가져오기
✅ 폴더인 경우 재귀 호출
if (fileStatus.isDirectory()) {
console.log("디렉토리:", filePath);
traverseDirectoryRecursive(filePath); // 🔁 재귀 호출하여 하위 폴더 탐색
} else {
console.log("파일:", filePath);
}
}
✔ 폴더인 경우 (fileStatus.isDirectory()
)
"디렉토리: [폴더 경로]"
를 출력재귀적으로(
traverseDirectoryRecursive(filePath)
) 다시 탐색 → DFS(깊이 우선 탐색) 방식
✔ 파일인 경우
"파일: [파일 경로]"
를 출력하고 다음 파일로 넘어감
✅ 함수 실행 (탐색 시작)
traverseDirectoryRecursive("."); // 현재 디렉토리부터 탐색 시작
"."
는 현재 실행 중인 디렉토리를 의미현재 디렉토리부터 재귀적으로 모든 파일과 폴더를 탐색
운영체제
1. FIFO 스케줄링의 장단점이 뭔가요?
FIFO 스케줄링의 로직은 큐에 들어온 순서대로 CPU를 할당받는 방식이다.
장점으로는 단순하고 직관적이라는 점
단점으로는 한 프로세스가 완전히 끝나야 다음 프로세스를 실행하기 때문에 앞의 프로세스에서 시간이 지연될수록 뒤에 있는 프로세스는 너무 지연되기 때문에 효율성을 따지면 문제가 생김.
2. SJF를 사용하기 여러운 이유가 뭔가요?
SJF는 Burst Time이 짧은 순서대로 실행하는 로직이다.
이론적으로 생각하면 짧은 순서대로 치기때문에 크게 지연되서 생길 문제도 줄어들긴 하지만,
2가지 문제점이 발생하게 된다.
첫째는 어떤 프로세스가 얼마나 실행될지 알 수 없다는 점.
둘째는 Burst Time이 긴 프로세스는 오랜시간동안 실행되지 않을 수 있다는 점.
결과적으로 이런 문제때문에 SFJ 알고리즘은 사용되지 않는다.
3. RR 스케줄링에서 타임 슬라이스가 아주 작으면 어떤 문제가 발생할까요?
RR 스케줄링은 모든 프로세스에게 공평하게 CPU 시간을 할당해주는 방식으로 돌아가는 로직이다.
RR프로세스의 단점중 타임 슬라이스를 너무 짧게 부여하게 되면, 다른 프로세스로 전환하는 과정인 컨텍스트 스위칭이 자주 일어나게 되어 불필요한 처리가 늘어난다는 것이다. 그래서 너무 길지도 짧지도 않은 적정선을 찾아서 지정해줘야 한다.
4. 운영체제가 MLFQ에서 CPU Bound Process와 I/O Bound Process를 어떻게 구분할까요?
현대 운영체제에서 가장 일반적으로 쓰이는 방식.
CPU Bound Process 와 I/O Bound Process에게 자신에게 맞는 타임 슬라이스를 부여해야하기 때문에 구분을 해야한다.
구분하는 방법은 CPU를 사용하는 프로세스가 실행하다가 스스로 CPU를 반납하면 CPU 사용이 적은 것이기 때문 에 I/O 바운드라고 예상할 수 있고, 프로세스가 타임 슬라이스 크기를 오버해서 CPU에게 강제로 뺏기면 CPU 바운드라고 예상 할 수 있다.
5. 공유자원이란무엇인가요?
공유자원이란 프로세스 간의 통신을 위해 공동으로 사용하는 변수나 파일, 장치 등을 의미한다.
6. 교착상태에 빠질 수 있는 조건은 어떤 것들을 충족해야할까요?
교착상태란 여러 프로세스가 서로 다른 프로세스의 작업이 끝나기를 기다리다가 아무도 작업을 진행하지 못하는 상태이다.
교착상태가 발생되는 원인으로는 공유자원을 사용하기 때문이다.
교착상태가 발생하기 위해서는 4가지중 하나라도 해당된다면 발생한다.
1. 상호배제: A프로세스가 A리소스를 차지한다면, 다른 프로세스에게 공유되면 안된다.
2. 비선점: A프로세스가 A리소스를 차지하고 있을때, 프로세스B가 A리소스를 빼앗을 수 없다야 한다.
3. 점유와 대기: A프로세스가 리소스A를 차지한 상태에서 리소스B를 원하는 상태여야 한다.
4. 원형 대기: 서로가 서로의 리소스를 원하는 경우가 해당
하지만 이 4가지 규칙을 지켜도 예방하기란 쉽지 않았고, 결국 교착상태에 빠졌을 경우 해결하는 방법에 대해 연구하게 된다.
댓글을 작성해보세요.