블로그
전체 9#카테고리
- 알고리즘 · 자료구조
- 풀스택
#태그
- 자료구조
- 알고리즘
- 운영체제
- 미션
- 인프런워밍업클럽
- CS
- 풀스택
- supabase
- next.js
2025. 03. 22.
0
인프런 워밍업 클럽 3기 CS - 3주차 미션
3주차 학습 내용 - 미션자료구조 & 알고리즘 1. 지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.1 ) 버블정렬특징: 인접한 두 요소를 비교해서 큰 값을 뒤로 보내는 방식시간복잡도: 최선: O(n) / 평균,최악: O(n²)장점: 구현이 아주 간단하고 직관적임단점: 성능이 너무 안 좋음, 실전에서 거의 사용 X 2 ) 선택정렬특징: 가장 작은 값을 찾아서 앞으로 하나씩 정렬해가는 방식시간복잡도: 최선,평균,최악: O(n²)장점: 구현 쉬움, 자리 바꿈(Swap) 횟수가 적음단점: 효율성 낮음, 데이터 크기 커지면 성능 ↓ 3) 삽입정렬특징: 정렬된 부분에 새 값을 '삽입'하는 방식시간복잡도: 최선: O(n) / 평균,최악: O(n²)장점: 거의 정렬된 상태일 땐 빠름, 구현 쉽고 안정 정렬단점: 역순 정렬일 경우 성능 급감 4 ) 병합정렬특징: 분할 → 정렬 → 병합하는 재귀 방식 (Divide & Conquer)**시간복잡도: 항상 O(n log n)장점: 성능 안정적, 정렬 정확도 높음, 안정 정렬단점: 추가 메모리 공간 필요, 구현 복잡 5) 퀵정렬특징: 피벗 기준으로 좌우 나눠 정렬하는 분할 정복 방식시간복잡도: 평균: Θ(n log n) / 최악: O(n²)장점: 평균적으로 가장 빠름, 메모리 추가 거의 없음단점: 피벗 선택이 안 좋으면 성능 O(n²), 구현 어렵고 불안정 2. 메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요. 나는 무조건 타뷸레이션을 사용할 것 같다.메모리가 부족한 상황이라면 어차피 타뷸레이션이나 메모이제이션이나 메모리를 아껴 써야 하는 조건은 비슷하다고 생각한다.그렇다면 굳이 어려운 재귀를 써야 하는 메모이제이션보다는, 반복문 기반으로 더 직관적인 타뷸레이션이 훨씬 낫다.솔직히 말해서 아직 재귀가 너무 어렵다… 그래서 재귀 없이 풀 수 있는 타뷸레이션 쪽을 더 선호하게 되는 것 같다. 😅 운영체제 1. 메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요. 1 ) 레지스터CPU 내부에 존재하는 가장 빠른 기억장소연산 중인 데이터나 주소 등을 저장CPU가 직접 접근 → 속도 가장 빠름용량은 매우 작고 휘발성2 ) 캐시CPU와 RAM 사이에 위치하는 고속 메모리CPU가 자주 접근하는 데이터를 미리 저장해서 → 메인 메모리 접근을 줄이고 속도 향상캐시가 없으면 RAM까지 가야 하니까 느려짐휘발성3) 메인메모리(RAM)운영체제(OS)와 실행 중인 프로그램이 올라가는 공간휘발성 메모리 → 전원이 꺼지면 데이터 사라짐가격이 비싸기 때문에, 파일 저장용이 아닌 ‘작업 공간’으로 사용됨HDD/SSD보다 훨씬 빠르지만, 레지스터나 캐시보다는 느림4) 보조저장장치데이터를 영구적으로 저장하기 위한 장치비휘발성 메모리 → 전원을 꺼도 데이터가 유지됨가격이 저렴하고 용량이 큼, 대신 RAM보다 느림HDD자기 디스크를 회전시켜 읽고 쓰는 방식물리적인 회전이 필요해서 느림, 하지만 저렴하고 수명은 길다충격에 약하고, 소음 있음 SSD플래시 메모리 기반의 저장장치회전 없이 빠르게 데이터 처리 가능HDD보다 훨씬 빠름, 충격에 강함, 소음 없음단점은 HDD보다 비싸고 수명(쓰기 횟수 제한)이 있음 2. 사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?✅ 정답: 경계 레지스터 (Boundary Register)경계 레지스터는 사용자 프로세스가 운영체제의 메모리 영역을 침범하지 못하도록 막아주는 역할을 한다.CPU 내부에 존재하며, 메모리 관리자가 경계 값을 기준으로 프로세스가 허용된 영역을 벗어나는지 실시간으로 검사한다.만약 프로세스가 지정된 경계를 넘어서려고 하면, 바로 프로세스를 강제 종료시켜서 시스템 보호를 수행한다. 3. 메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?✅ 가변 분할 방식프로세스 크기에 맞춰서 메모리를 유동적으로 나누는 방식필요한 만큼만 메모리를 나눠 쓸 수 있어서 공간 활용은 유리함하지만 계속 할당과 해제를 반복하다 보면 여기저기 쪼개진 빈 공간들이 생기며, 이걸 외부 단편화라고 하고, 빈 공간이 충분해 보여도 실제로는 새로운 프로세스를 넣기 힘든 상황이 생길 수 있음 ✅ 고정 분할 방식미리 정해진 크기로 메모리를 쪼개놓고, 거기에 프로세스를 할당하는 방식구조가 단순해서 구현이 쉽고 오버헤드도 적음근데 프로세스 크기랑 딱 안 맞는 경우가 많아서, 작은 프로세스가 큰 메모리 블록을 차지해 공간이 낭비되는 내부 단편화 발생 4. CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?✅ 정답: 스레싱멀티프로그래밍 수준을 높여서 CPU 사용률을 끌어올리려 했는데, 오히려 프로세스들이 메모리를 서로 차지하려고 계속 페이지 교체(스왑)만 일어나게 된다.결국 CPU는 계속 대기만 하게 되고 실제 작업은 거의 하지 못하는 상태가 된다.이런 상황을 스레싱(thrashing)이라고 부른다. 5. HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요?이유를 함께 적어주세요.조명처럼 켜두거나 그냥 전시용 벽돌로 둘 거라면 없어도 상관없다.하지만 컴퓨터를 제대로 사용하려면 반드시 필요하다.운영체제(OS), 프로그램, 각종 파일들이 저장되는 공간이 바로 HDD나 SSD이기 때문이다.이 저장장치가 없다면 운영체제를 로딩할 수 없고, 프로그램도 실행할 수 없다.결국 컴퓨터는 켜질 수는 있지만 아무것도 하지 못하는 상태가 된다. 6. 파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?파일을 삭제해도 실제 데이터는 바로 없어지지 않기 때문파일 시스템은 빈 저장 공간을 관리하기 위해 free block list를 사용한다. 이 리스트는 사용 가능한 블록들을 모아놓은 일종의 기록표다.파일을 삭제하면 파일 시스템은 파일의 데이터 전체를 지우지 않고, 파일의 헤더 정보(위치 정보)만 지운다. 그리고 그 파일이 있던 위치를 free block list에 추가한다.결과적으로 사용자 입장에서는 파일이 사라진 것처럼 보이지만, 실제로는 하드디스크 어딘가에 데이터가 남아 있는 상태다.
알고리즘 · 자료구조
・
자료구조
・
알고리즘
・
운영체제
・
미션
・
인프런워밍업클럽
・
CS
2025. 03. 20.
0
인프런 워밍업 클럽 3기 풀스택 - 3주차 발자국
3주차 학습 내용Part 1. Git Repository 생성 및 초기 설정 진행이전과 동일하게 npx create-next-app@14 inflearn-supabase-netflix-clone 해주고, 2주차의 코드를 가져왔다.테이블의 column을 지정해주고, 강사님께서 가져오신 영화 데이터를 받아 DB를 구성했다. Part 2. UI 작업이번에는 다이나믹 라우트를 사용해서 포스터를 클릭하면 해당 포스터의 id를 들고 상세페이지로 이동한다. 사용법은 간단하게 대괄호를 열고 닫은 폴더명을 사용하면 됨.그거 말고는 전체적으로 예제와 같게 UI작업을 했고, 이전 드롭박스때 처럼 grid로 간단하게 반응형을 구현해줌. Part 3. 영화 검색 기능 & 영화 개별 상세페이지 구현🌀 Recoil 사용 방법✅ 1. 설치먼저 Recoil을 설치한다: npm install recoil✅ 2. 서버 컴포넌트(layout.tsx)에 직접 쓰면 ❌Recoil은 클라이언트 사이드 전용 라이브러리이기 때문에layout.tsx에서 바로 사용하면 에러가 발생한다.✅ 3. RecoilProvider 따로 만들어 감싸기config/RecoilProvider.tsx 파일을 만들고, 아래와 같이 구성한다// config/RecoilProvider.tsx "use client"; import { RecoilRoot } from "recoil"; export default function RecoilProvider({ children }: React.PropsWithChildren) { return {children}; } ✅ 4. 전역 상태 정의 (atoms.ts)utils/recoil/atoms.ts에 전역 상태를 선언한다:// utils/recoil/atoms.ts import { atom } from "recoil"; export const searchState = atom({ key: "searchState", default: "", }); ✅ 5. 컴포넌트에서 사용하기import { useRecoilState } from "recoil"; import { searchState } from "utils/recoil/atoms"; const [search, setSearch] = useRecoilState(searchState); Part 4. 무한 스크롤 기능 구현하기 & 더 나은 검색을 위한 SEO 작업하기 핵심 포인트react-query의 useInfiniteQuery 사용react-intersection-observer로 마지막 요소 감지해서 추가 데이터 불러오기🔧 구현 흐름useInfiniteQuery에서 pageParam으로 현재 페이지 관리searchMovies()를 호출해서 검색어와 페이지 정보를 넘김getNextPageParam으로 다음 페이지 조건 처리마지막 아이템에 ref 붙여서 화면에 보이면 자동 로딩 "use client"; import { useInfiniteQuery } from "@tanstack/react-query"; import MovieCard from "./movie-card"; import { searchMovies } from "actions/movieActions"; import { Spinner } from "@material-tailwind/react"; import { useRecoilValue } from "recoil"; import { searchState } from "utils/recoil/atoms"; import { useInView } from "react-intersection-observer"; import { useEffect } from "react"; export default function MovieCardList() { const search = useRecoilValue(searchState); const { data, isFetching, isFetchingNextPage, fetchNextPage, hasNextPage } = useInfiniteQuery({ initialPageParam: 1, queryKey: ["movie", search], queryFn: ({ pageParam }) => searchMovies({ search, page: pageParam, pageSize: 12 }), getNextPageParam: (lastPage) => lastPage.page ? lastPage.page + 1 : null, }); const { ref, inView } = useInView({ threshold: 0, }); useEffect(() => { if (inView && hasNextPage && !isFetching && !isFetchingNextPage) { fetchNextPage(); } }, [inView, hasNextPage]); useEffect(() => { console.log(inView); }, [inView]); return ( {isFetching || (isFetchingNextPage && )} {data?.pages ?.map((page) => page.data) ?.flat() ?.map((movie) => ( ))} ); } 🔧 구현 흐름Next.js의 generateMetadata()를 사용해서페이지별로 동적으로 메타 태그 생성. 💡 포인트페이지 타이틀에 영화 제목 자동 반영설명은 영화 overview에서 가져옴OG 이미지도 함께 등록해서 링크 공유 시 썸네일 출력됨export async function generateMetadata({ params, searchParams }) { const movie = await getMovie(params.id); return { title: movie.title, description: movie.overview, openGraph: { images: [movie.image_url], }, }; } 미션: 북마크 기능 만들기미션: 찜하기 기능을 만들어서, 찜한 영화를 영화 리스트 화면의 최상단에 보여주기원래는 영화 리스트 화면에서 북마크한 영화를 최상단에 보여주는 미션이었지만,실제 사용자 입장에서 불편할 것 같아서 헤더에 "bookmark" 메뉴를 따로 만들고해당 페이지에서 북마크한 영화만 모아보는 방식으로 약간 변형해서 구현했습니다. 1. Supabase 테이블에 bookmark 추가해주기Supabase의 movie 테이블에 bookmark라는 boolean 컬럼을 추가하고,기본값을 false로 설정하기 위해 SQL Editer에서 UPDATE movie SET bookmark = false WHERE bookmark IS NULL;를 입력해줌 2. 북마크 토글 함수 생성// actions/movieActions.ts export async function toggleBookmark(id: number, current: boolean) { const supabase = await createServerSupabaseClient(); const { error } = await supabase .from("movie") .update({ bookmark: !current }) // 현재 값 반대로 토글 .eq("id", id); // 해당 ID만 업데이트 handleError(error); } movieActions에서 북마크 토글을 지원하는 함수를 만들어줌. 3. 상세 페이지에서 북마크 버튼 만들기// app/movies/[id]/ui.tsx "use client"; import { toggleBookmark } from "actions/movieActions"; import { useState, useTransition } from "react"; import { BookmarkIcon } from "@heroicons/react/24/outline"; import { BookmarkIcon as BookmarkSolidIcon } from "@heroicons/react/24/solid"; export default function MovieDetail({ movie }) { const [bookmarked, setBookmarked] = useState(movie.bookmark); const [isPending, startTransition] = useTransition(); const handleClick = () => { setBookmarked((prev) => !prev); // UI 먼저 변경 startTransition(async () => { await toggleBookmark(movie.id, bookmarked); // 서버에 실제 반영 }); }; return ( {movie.title} {bookmarked ? ( ) : ( )} ); } npm install @heroicons/react을 설치해서 토글 아이콘을 생성함.2번에서 만든 함수를 연결해서 북마크를 키고 끄면 DB에도 연동되게 만들었음. 4. 북마크한 영화만 보여주는 페이지 만들기// actions/movieActions.ts export async function getBookmarkedMovies() { const supabase = await createServerSupabaseClient(); const { data, error } = await supabase .from("movie") .select("*") .eq("bookmark", true) // bookmark가 true인 영화만 가져옴 .order("id", { ascending: true }); // id 순으로 정렬 handleError(error); return data; }movieActions에서 북마크한 영화만 보여주는 함수를 만들어줌. // app/movies/bookmark/page.tsx import MovieCard from "@/components/movie-card"; import { getBookmarkedMovies } from "actions/movieActions"; export default async function BookmarkPage() { const movies = await getBookmarkedMovies(); return ( {movies.map((movie) => ( ))} ); }header에서 북마크를 클릭하면 북마크 페이지로 이동하게 만들었고위에서 만든 북마크 영화 함수를 사용해서 북마크한 영화만 보여주도록 만들었음. 아쉬운 부분무한스크롤이 아직 조금 어려워서 북마크 페이지에서는 아직 구현해지 못했다.추후에 좀 더 공부해보고 넣어주면 좋을 것 같다!회고이번 주차 수업 중에서는 무한 스크롤이 가장 어려웠지만,과제는 이전 주차처럼 단순히 '딸깍하면 되는 문제'가 아니어서"어떻게 구현할까?" 부터 고민하는 재미가 있었다.Supabase에서 테이블을 직접 작성하고,서버 액션에서 원하는 기능을 하는 함수를 만들고,그 함수를 페이지에 붙여서내가 의도한 대로 동작하는 걸 확인했을 때 정말 재밌었다.뭔가 시간이 지나면서 점점 supabase와 친해지는 느낌을 받았다.엄청 어렵지는 않지만,약간만 생각하면 풀리는 적당한 난이도라서 더 좋았던 과제였다.
풀스택
・
풀스택
・
미션
・
인프런워밍업클럽
・
supabase
・
next.js
2025. 03. 17.
0
인프런 워밍업 클럽 3기 CS - 3주차 발자국
3주차 학습 내용 - 발자국자료구조 & 알고리즘 삽입정렬function InsertionSort(arr) { for (let i = 1; i = 0; j--) { if (arr[j] > cnt) { arr[j + 1] = arr[j]; } else { break; } } arr[j + 1] = cnt; } return arr; } console.log(InsertionSort([4, 1, 5, 3, 6, 2])); 시간복잡도: O(N²)이해와 구현이 간단하고 직관적,하지만 성능은 좋지 않아서 작은 데이터나 거의 정렬된 데이터에 적합병합정렬function MergeSort(arr, leftIndex, rightIndex) { if (leftIndex 시간복잡도: O(n log n)재귀 기반 정렬이라 이해와 구현은 조금 어렵지만, 성능은 안정적이고 좋다. 퀵정렬function quickSort(arr, left, right) { if (left = left + 1 && arr[rightStartIndex] >= pivot) { rightStartIndex--; } if (leftStartIndex 시간복잡도: 평균적으로 Θ(n log n)재귀 기반 정렬이라 이해와 구현은 어렵게 느껴질 수 있지만, 실제로는 굉장히 빠르고 효율적인 정렬 알고리즘이다. 메모이제이션function fibonacci2(n, memo) { if (n == 0 || n == 1) return n; // ✅ 기본 조건(Base Case) if (memo[n] == null) { // ✅ 이전에 계산된 값이 없으면 계산 memo[n] = fibonacci2(n - 2, memo) + fibonacci2(n - 1, memo); } return memo[n]; // ✅ 저장된 값이 있으면 재사용 } console.log(fibonacci2(5, {})); // ✅ 초기 memo 객체를 전달한 번 계산한 값을 저장해두고, 같은 계산이 필요할 때는 다시 계산하지 않고 저장된 값을 재사용하는 기법중복 계산을 줄여 알고리즘 속도를 최적화 함.예제에서는 피보니치를 재귀로 구현하고 있음, 하지만 일반 재귀로는 불필요한 중복계산이 많아 효율이 좋지 않음.그래서 n의 값에 따라 그 값을 기억하는 memo를 만들어서 n이 실행될때 이전에 저장한게 있으면 바로 값 대입함. 타뷸레이션function fibonacci3(n) { if (n 타뷸레이션은 하향식인 재귀 방식이 아니라, 상향식으로 배열을 채워나가는 방식이다.아무래도 재귀보다 코드가 직관적이고, 이해하기 쉽다. 타뷸레이션은 재귀 없이도 효율적인 풀이가 가능한 방식이라, 초보자에게 훨씬 부담이 적고 실전에서도 유용하다고 느꼈다. 운영체제 가상 메모리운영체제가 물리적 메모리(RAM)가 부족할 때, 하드디스크(또는 SSD)를 이용하여 추가적인 메모리를 제공하는 기술RAM이 부족하면 일부 데이터를 디스크(하드디스크, SSD)에 저장했다가 필요할 때 다시 불러오는 방식페이지 폴트: 프로그램이 필요한 데이터를 RAM에서 찾지 못할 때 발생하는 현상 -> 운영체제가 디스크에서 해당 데이터를 RAM으로 불러오는 작업을 수행스왑 영역: 물리 RAM이 부족할 때, 디스크의 일부를 메모리처럼 사용하는 영역 세그멘테이션프로그램을 논리적인 단위(세그먼트)로 나누어 메모리를 할당하는 방식동작 방식프로그램이 메모리를 요청하면 운영체제는 세그먼트 번호를 할당함.세그먼트 테이블을 참고하여, 해당 세그먼트의 시작 주소를 찾음.세그먼트 시작 주소 + 오프셋(offset)을 더하여 실제 메모리 주소를 계산함.장점: 내부 단편화 X, 메모리를 논리적 단위로 관리 가능단점: 외부 단편화O페이징메모리를 "고정된 크기(페이지 단위)"로 나누어 관리하는 메모리 할당 기법프로세스를 작은 단위(페이지)로 나누어 메모리에 배치동작 방식프로그램이 실행되면, 프로세스를 동일한 크기의 페이지로 나눔.메모리도 같은 크기의 프레임으로 나누고, 각 페이지를 빈 프레임에 적재.CPU가 메모리에 접근할 때, 페이지 테이블을 이용하여 페이지 번호 → 프레임 번호로 변환.장점: 외부 단편화 없음, 메모리를 효율적으로 사용 가능단점: 내부 단편화 발생, 페이지 테이블을 계속 참조해야 해서 오버헤드 존재 세그멘테이션 vs 페이징둘 중에 뭐가 더 좋다, 이렇게 단정 짓긴 어려움. 결국 사용 목적과 상황에 따라 선택하면 됨.세그멘테이션프로그램이 서로 다른 크기의 논리적 블록(세그먼트)으로 나뉘어 있을 때 유리함함수, 배열, 변수 등 논리 단위로 나뉘는 구조에 적합유연하게 메모리를 할당하고 싶을 때 사용하기 좋음페이징메모리를 고정된 크기(페이지 단위)로 균등하게 나눔운영체제에서 일괄적으로 메모리를 관리하고 싶을 때 적합외부 단편화가 더 신경 쓰이는 경우 페이징이 더 효과적임ㅍ페이지 세그멘테이션세그멘테이션 + 페이징의 장점을 섞은 방식세그먼트마다 다시 페이지 단위로 쪼갬논리적으로는 세그먼트로 구분하고, 물리적으로는 페이지처럼 관리함단점도 줄이고, 장점도 살리는 구조 디맨드 페이징실제로 필요한 페이지만 메모리에 올리는 방식프로그램 실행 시, 전체를 메모리에 올리지 않고 조만간 필요할 것 같은 페이지만 로딩나머지 페이지는 스왑 영역(보조 기억장치)에 남겨둠실제 사용될 때만 메모리에 적재 → 효율적인 메모리 사용 지역성 이론프로그램이 실행될 때 특정 메모리 영역에 집중적으로 접근하는 성질을 지역성이라고 한다. 공간의 지역성: 현재 위치와 가까운 데이터에 접근할 확률이 높음ex) 배열이나 함수 코드처럼 서로 인접한 메모리 위치를 차례로 접근하는 경우이 특성을 기반으로, 근처 데이터까지 한 번에 메모리에 올려두고, 필요 없어 보이는 데이터는 스왑 영역으로 보내서 성능을 높이는 방식이 사용됨 시간의 지역성: 최근 접근했던 데이터가 오래 전에 접근했던 데이터보다 접근할 확률이 높음ex) 방금 쓴 변수나 반복문에서 쓰인 코드들이 다시 사용되는 경우이 특성을 활용해서, 캐시나 페이지 교체 알고리즘에서 최근 사용 여부를 판단하는 데 쓰임 페이지 교체 정책프로세스가 어떤 데이터를 사용하려고 할 때, 그 데이터가 메모리에 없다면 스왑 영역(디스크)에서 가져와야 한다.근데 메모리 공간이 꽉 차 있다면, 기존에 있던 데이터를 하나 꺼내고, 새 데이터를 그 자리에 넣어야 함.이때 어떤 데이터를 꺼낼지 정하는 기준이 바로 페이지 교체 정책이다.1. 무작위로 선택하는 방법지역성을 전혀 고려하지 않기 때문에, 자주 쓰는 데이터가 교체될 수 있어서 성능이 안 좋음하지만 구현은 제일 간단함2. 메모리에서 가장 오래된 페이지를 선택하는 방법(FIFO)자주 쓰는 페이지라도 먼저 들어왔다는 이유로 교체될 수 있음단점은 있지만, 구현이 쉬워서 변형을 거쳐 실제로 많이 사용됨3. 앞으로 가장 오랫동안 쓰이지 않을 페이지를 선택하는 방법(Optimum)이론적으로 가장 완벽한 방식이지만,미래를 예측할 수 없기 때문에 실제 구현은 불가능함다른 알고리즘과 성능 비교할 때 기준점으로 사용함4. 최근에 가장 사용이 적은 페이지를 선택하는 방법(LRU)최근에 사용된 데이터를 우선적으로 보존하는 방식이라 지역성에 잘 맞음단점은, 언제 사용됐는지를 추적하기 위해 시간 정보나 카운터, 비트 등이 필요함 → 구현이 복잡하고 성능 부담이 생길 수 있음시간이 지나면 오버플로우 문제도 발생 가능5. Clock AlgorithmLRU의 단점을 보완한 방식각 페이지에 참조 비트를 붙이고,일정 시간마다 비트를 확인하며 시계 방향으로 스캔참조되지 않은 페이지를 교체하고, 참조된 페이지는 기회를 한 번 더 줌구조는 단순하고 성능도 괜찮아서 실제 운영체제에서 자주 사용됨 6. 2차 기회 페이지 교체 알고리즘FIFO의 단점을 개선한 방식FIFO는 자주 쓰는 페이지라도 먼저 들어왔으면 교체됨 → 이걸 해결함페이지가 교체 대상이 되었는데 최근 사용된 페이지라면, 그 페이지를 맨 뒤로 보내고 한 번 더 기회를 주는 방식간단하면서도 성능이 괜찮은 알고리즘 스레싱프로세스들이 계속 스왑만 하느라 정작 일은 못 하는 상태멀티프로그래밍 수준을 너무 높이면, 한정된 메모리를 너무 많은 프로세스가 나눠 쓰게 된다.이때 필요한 페이지가 자꾸 메모리에 없어서, 운영체제는 디스크와 메모리 사이에서 페이지를 계속 교체(스왑) 하게 된다.결과적으로 CPU는 일은 안 하고, I/O 대기만 계속하면서 놀게 된다.주변 장치그래픽 카드, HDD, SDD, 키보드, 마우스 등 컴퓨터 외부와 연결되는 장치들을 말함.캐릭터 디바이스마우스, 키보드, 사운드카드 등데이터 전송 단위가 '문자 단위(캐릭터)'로 상대적인 크기가 작다블록 디바이스HDD, SSD, 그래픽카드 등데이터 전송 단위가 '블록 단위(범위)'로 상대적인 크기가 크다입출력 제어기예전에는 주변 장치를 CPU가 직접 관리했기 때문에, I/O 명령을 만나면 CPU가 멈춰버리고 입출력이 끝날 때까지 기다려야 했음 → 비효율적이걸 보완하기 위해 입출력 제어기가 생김.이제는 I/O 명령을 만나면, 제어기가 입출력 작업을 대신 맡고, CPU는 다른 작업을 계속 실행할 수 있게 됨 → CPU 사용률이 올라감 3주차 회고벌써 3주차가 되어버렸다..이번 주는 뭔가 유독 어렵게 느껴졌다.아무래도 점점 이전 강의 위에 지식이 쌓여가다 보니, 강의를 봐도 이해가 잘 안 되는 순간들이 많았다.그래서 같은 영상을 계속 반복해서 보면서 겨우겨우 따라갔던 것 같다.특히 재귀는 진짜 어렵다.자주 보려고는 하지만, 어렵다 보니 손이 잘 안 간다… 하하(타뷸레이션 짱😀)3주 전, 아무것도 모르던 나는 그냥 "CS 한 번 배워보자!"는 마음으로 신청했었다.그런데 막상 3주 동안 공부하면서 내가 몰랐던 걸 많이 알게 됐고,동시에 더 꾸준히 공부해야겠다는 자극도 받았다.코드를 직접 치고, 프레임워크나 기술을 익히는 것도 물론 중요하지만,이런 이론적인 부분(CS)도 기초 체력을 길러주는 느낌이라 꼭 필요하다고 생각하게 됐다.아마 완주 포인트를 받으면… 감자님의 알고리즘 상버전을 결제하러 가지 않을까 싶다 😎이 강의를 듣고 싶거나, 워밍업 클럽에 참여할까 고민 중이라면 망설이지 말고 그냥 해보는 걸 추천한다.나는 CS 강의는 처음이라 다른 강의랑 비교할 순 없지만,지금까지는 충분히 만족이다.그리고 솔직히 말해서, 워밍업 클럽이 아니었다면 3주 동안 완강 못 했을 거다.혼자였다면 진작에 놓았을지도… 마지막으로 우리 모두 파이팅! 🔥🔥
자료구조
・
알고리즘
・
운영체제
・
인프런워밍업클럽
・
CS
2025. 03. 15.
0
인프런 워밍업 클럽 3기 풀스택 - 2주차 발자국
2주차 학습 내용Part 1 - Git Repository 생성 및 초기 설정 진행create-next-app을 통해 초기 세팅을 했으며,이전에 TODO에서 했던 코드들을 일부 가져와서 빠르게 세팅함. Part 2 - UI 작업알게된 사실 - page.tsx에는 클라이언트 컴포넌트를 사용하면 좋지않다.그 이유는 나중에 메타데이터를 쓰고 하는데 그건 서버 컴포넌트에서만 돌아가기 때문에 피해줘야 한다.나는 평소 flex만 사용하고 grid는 잘 사용하지 않는다. 항상 쓰던것만 써서 그렇기도 하고 grid로 편하게 구현하는 것도 flex로 구현은 가능하기 때문에 그렇게 했다. 강의에서는 grid를 사용했고 디테일하진 않지만 간단하게 3단계로 반응형도 쉽게 구현되는 모습을 보고 grid를 다시보게 됨className="grid md:grid-cols-3 lg:grid-cols-4 grid-cols-2"그 이후로는 컴포넌트 별로 분리해서 퍼블리싱 작업을 구현했다. Part 3 - 파일 업로드 구현(Supabase Storage) 사진을 업로드 하는데 알 수 없는 에러가 있었고, 분명 코드도 다른부분이 없는데 문제가 생겨서 오랫동안 붙잡고 있었다.원인은 사진이름이 한글로된 경우 안되는 부분이였고, 잠시 오류 수정으로 고쳐서 한글이름으로 된 사진도 업로드가 가능하게 했다. 하지만 한글이름이 아닌 a__a__a같은 이름으로 저장되는 문제가 발생해서 이 문제는 추후 고쳐봐야 할 문제 같다.// actions/storageActions.ts function sanitizeFileName(fileName: string) { return fileName .normalize("NFKD") // 유니코드 정규화 .replace(/[^\w.-]/g, "_") // 특수 문자 제거 .replace(/\s+/g, "_") // 공백을 `_`로 변경 .toLowerCase(); // 소문자로 변환 } export async function uploadFile(formData: FormData) { const supabase = await createServerSupabaseClient(); const file = formData.get("file") as File | null; if (!file) { console.error("❌ 업로드할 파일이 없습니다."); throw new Error("파일이 없습니다."); } // 파일 이름을 안전한 형식으로 변환 const safeFileName = sanitizeFileName(file.name); console.log("✅ 변환된 파일 이름:", safeFileName); const { data, error } = await supabase.storage .from(process.env.NEXT_PUBLIC_STORAGE_BUCKET!) .upload(safeFileName, file, { upsert: true }); if (error) { console.error("❌ Supabase 업로드 실패:", error.message); throw new Error(error.message); } return data; } Part 4 - 파일제거 구현, Darg & Drop, 멀티파일 업로드 구현Darg & Drop을 위해 설치해줌. npm i --save react-dropzone이번주 미션 - 파일의 마지막 수정(업로드) 시간을 표시하는 기능을 추가하기!// components/dropbox-image.tsx 생성일: {formatDate(image.updated_at)} 간단하게 이 부분 넣어서 해결함. 미션 이외로...- 강사님과 같은 코드로 하니까 생긴 에러가 있어서 코드를 약간 수정함.수정한 부분은 actions/storageActions.ts 의 uploadFile 부분임1⃣ 파일 필터링 (undefined 값 제거)✅ 첫 번째 코드 (위 코드) → undefined 또는 잘못된 파일 제거const files = Array.from(formData.entries()) .map(([name, file]) => file as File) .filter((file) => file instanceof File && file.name); // ✅ undefined 제거 filter()를 사용하여 undefined 또는 비정상적인 파일을 제거파일이 null이거나 undefined면 upload()에서 에러 발생 가능성이 있음 → 이를 방지❌ 두 번째 코드 (아래 코드) → 필터링 없음const files = Array.from(formData.entries()).map(([name, file]) => file as File); undefined 파일이 포함될 가능성이 있음 → 업로드 시 오류 발생 가능 2⃣ 파일명 변환 (sanitizeFileName)✅ 첫 번째 코드 (위 코드) → 파일명 변환 추가function sanitizeFileName(fileName: string) { return fileName .normalize("NFC") // ✅ 한글 깨짐 방지 .replace(/[^a-zA-Z0-9ㄱ-ㅎㅏ-ㅣ가-힣_.-]/g, "_"); // ✅ 특수 문자 제거 } const safeFileName = sanitizeFileName(file.name); 특수 문자, 공백 제거 (file.name을 정리)한글 깨짐 방지 (NFC 정규화)→ Supabase는 일부 특수 문자나 공백이 포함된 파일명을 허용하지 않으므로 안정적❌ 두 번째 코드 (아래 코드) → 원본 파일명 그대로 사용supabase.storage .from(process.env.NEXT_PUBLIC_STORAGE_BUCKET) .upload(file.name, file, { upsert: true }); 파일명을 그대로 사용하기 때문에, 특수 문자나 공백이 포함되면 Supabase에서 오류 발생 가능 3⃣ async 처리 및 오류 핸들링✅ 첫 번째 코드 (위 코드) → async 사용 및 오류 처리const results = await Promise.all( files.map(async (file) => { // ✅ async 사용 const safeFileName = sanitizeFileName(file.name); const { data, error } = await supabase.storage .from(process.env.NEXT_PUBLIC_STORAGE_BUCKET) .upload(safeFileName, file, { upsert: true }); if (error) { // ✅ 오류 처리 console.error("❌ Supabase 업로드 실패:", error.message); throw new Error(error.message); } return data; }) ); 각 파일 업로드가 비동기(async)로 처리됨오류 발생 시 console.error로 출력하고 예외 처리각 파일 업로드 후 결과(data) 반환❌ 두 번째 코드 (아래 코드) → 오류 핸들링 없음const results = await Promise.all( files.map((file) => supabase.storage .from(process.env.NEXT_PUBLIC_STORAGE_BUCKET) .upload(file.name, file, { upsert: true }) ) ); async 키워드 없이 바로 upload() 실행오류가 발생해도 catch되지 않으며, 전체 업로드가 실패할 가능성이 있음업로드 성공 여부를 확인할 방법 없음 (data를 반환하지 않음) 2주차 회고 2주차에는 중간점검을 하는 시간을 가졌다. 수강생들이 하고 싶었던 질문을 하나하나 답변해주시는 시간을 가져서 꽤 유용한 시간이였고, 더 열심히 하자는 마음을 다지는 계기가 되었다.첫주때보단 수퍼베이스에 적응을 하는거같다. 아직 친해지기에는 시간이 더 많이 필요할꺼 같긴한데 정처기 준비하고 CS 스터디 하고, 다른 프젝도 마무리 하고, 매일 알고리즘 문제도 풀고 있다보니 시간이 많이 부족한 것 같다.중간점검때 강사님께서 시간관리에 대한 얘기도 했었는데, 매우 동감하는 부분...시간 관리나 스케줄 관리를 잘 해야 할 것 같다.. 의욕만 앞서서 살짝 망하는거 같기도함.그래도 뭐 흥미있고 재미있으니까 만족한다.
풀스택
・
풀스택
・
미션
・
인프런워밍업클럽
・
supabase
・
next.js
2025. 03. 10.
0
인프런 워밍업 클럽 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가지 규칙을 지켜도 예방하기란 쉽지 않았고, 결국 교착상태에 빠졌을 경우 해결하는 방법에 대해 연구하게 된다.
알고리즘 · 자료구조
・
자료구조
・
알고리즘
・
운영체제
・
미션
・
인프런워밍업클럽
・
CS
2025. 03. 10.
0
인프런 워밍업 클럽 3기 CS - 2주차 발자국
2주차 학습 내용 - 발자국자료구조 & 알고리즘재귀함수function sum(n) { if (n === 1) return 1; // ✅ 기본 조건(Base Case): n이 1이면 재귀 종료 return n + sum(n - 1); // 🔁 재귀 호출(Recursive Case): sum(n-1) 호출 } console.log(sum(5)); // 5 + 4 + 3 + 2 + 1 = 15함수 내부에서 자기 자신을 다시 호출하는 구조를 가진 함수기본조건재귀 함수가 계속 반복되지 않도록 종료 조건(기저 조건)을 설정해야 함.없으면 무한 루프가 발생하여 Stack Overflow(스택 오버플로우) 오류가 발생함.재귀 호출재귀 호출을 통해 문제를 점점 더 단순하게 만들어 Base Case에 도달하도록 함. 하노이 탑(재귀)function hanoi(count, from, to, temp) { if (count === 0) return; hanoi(count - 1, from, temp, to); console.log(`원반${count}를 ${from}에서 ${to}로 이동했습니다.`); hanoi(count - 1, temp, to, from); } hanoi(3, "A", "C", "B"); 재귀문제의 기본으로 알려진 하노이탑 문제의 원리큰 원반을 옮기기 전에, 그 위에 있는 원반들을 다른 기둥으로 옮긴다.가장 아래에 있는 큰 원반을 목표 기둥으로 이동한다.다른 기둥에 옮겨둔 원반들을 다시 목표 기둥으로 옮긴다.hanoi 함수의 매개변수는 (원반개수, 시작위치, 도착위치, 거치는위치)4개로 구성된다. 버블정렬function bubbleSort(arr) { let n = arr.length; for (let i = 0; i arr[j + 1]) { // 오름차순 정렬 [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; // Swap (교환) } } } return arr; } let arr = [5, 3, 8, 4, 2]; console.log(bubbleSort(arr)); // [2, 3, 4, 5, 8] 배열을 반복하면서 인접한 두 요소를 비교하고 조건에 따라 서로의 위치를 바꿈구현하기는 쉽지만 성능면(O(n²))에서는 그렇게 좋지 않음. 선택정렬function selectionSort(arr) { let n = arr.length; for (let i = 0; i 배열영역의 첫 번째 원소를 시작으로 마지막 원소까지 비교 후 가장 작은 값을 첫 번째 원소로 가져온다.버블정렬과 같은 경우로 구현하기는 쉽지만 성능면(O(n²))에서는 그렇게 좋지 않음. 운영체제 프로세스 간 통신한 컴퓨터내에 있는 다른 프로세스와 통신하는 방법 ex) 파일, 파이프파일: 프로세스 간 데이터를 저장하고 읽을 수 있음.파이프: 한 프로세스의 출력이 다른 프로세스의 입력이 되는 방식.네트워크로 연결된 다른 컴퓨터에 있는 프로세스와 통신을 하는 방법 ex) 소켓통신, RPC소켓통신: 네트워크를 통해 데이터를 주고받는 방식RPC: 원격 프로시저 호출을 이용하여 다른 컴퓨터에서 실행되는 함수 호출.쓰레드 간 통신같은 프로세스 내에서 실행되는 여러 개의 쓰레드 간의 통신 방법쓰레드는 코드, 데이터, 힙을 공유하며, 각자의 스택만 별도로 가짐.전역 변수(Global Variable)나 힙(Heap)을 이용하면 쓰레드 간 데이터 공유 가능. 공유자원프로세스나 쓰레드 간의 통신에서 공동으로 사용하는 변수나 파일을 의미한다.임계구역여러 프로세스가 동시에 접근하면 안 되는 공유 자원의 영역세마포어공유자원을 함께 쓰는 프로세스 간의 충돌을 막기 위해 프로세스가 사용하는 동안 다른 프로세스는 동작하지 않고 기다리는 것모니터세마포어의 단점을 개선한 방법운영체제(OS) 차원이 아니라, 프로그래밍 언어에서 제공하는 동기화 방법내부적으로 뮤텍스(Mutex)와 조건 변수(Condition Variable)를 사용하여 동기화 수행여기부터교착상태(데드락)프로세스들이 서로가 가진 자원을 기다리면서 아무것도 실행되지 않는 상태각 프로세스가 다른 프로세스의 작업이 끝나기를 기다리지만, 아무도 자원을 해제하지 않음교착상태가 발생하려면 다음 4가지 조건이 모두 충족되어야 한다.상호배제: 자원은 한 번에 하나의 프로세스만 사용할 수 있어야 한다.비선점: 점유한 자원을 강제로 빼앗을 수 없다.점유와 대기: 이미 자원을 점유한 상태에서 추가적인 자원을 기다려야 한다.원형 대기: 프로세스들이 서로 다음 프로세스의 자원을 기다리는 원형 구조가 형성되어야 한다.하지만 필요조건을 지켜도 교착상태는 발생한다는 것을 깨달았고, 교착상태를 예방하기보단 교착상태가 발생했을때 해결하는 방법을 찾으려고 했다.교착상태 해결방안교착상태 회피프로세스들에게 자원을 할당할 때 어느정도 자원을 제공해야 교착상태가 발생하는지 파악해서 교착상태가 발생하지 않는 선에서 할당해주는 것전체 자원의 수와 할당된 자원의 수를 비교해서 안정상태와 불안정 상태로 나눔시스템의 총 자원과 각 프로세스간의 최대 요구자원을 계산해서 여유분의 자원을 남기고 프로세스에게 제공해야 안정상태를 유지할 수 있다.교착상태 검출가벼운 교착 상태 검출: 타이머를 이용해 프로세스가 일정시간 동안 작업을 진행하지 않으면 교착상태가 일어났다고 생각하고 해결함(해결 방법은 주기적으로 상황을 업데이트해서 만약 교착이라고 느끼면 롤백해서 이전으로 되돌아감)무거운 교착 상태 검출: 자원 할당 그래프를 이용하며, 교착 상태를 발견하면(발견은 자원이 순환하면 교착상태임) 해결함.해결방법은 교착상태를 인지하면 교착을 일으킨 프로세스를 강제종료하고 다시 실행할때 이전 업데이트로 롤백함.컴파일 언어소스 코드 전체를 한 번에 기계어(0과 1)로 변환한 후 실행하는 언어속도가 빠름.언어: C, C++, C# 등컴파일에서 실행파일로 변환 과정test.c -> 전처리기 -> test.i -> 컴파일러 -> test.s -> 어셈블리 -> test.o -> 링커 -> test.exe1⃣ test.c → 전처리기(Preprocessor) → test.i (주석 제거, 매크로 처리 등)2⃣ test.i → 컴파일러(Compiler) → test.s (어셈블리 코드 생성)3⃣ test.s → 어셈블러(Assembler) → test.o (목적 파일 생성)4⃣ test.o → 링커(Linker) → test.exe (최종 실행 파일 생성) 인터프리터 언어코드를 한 줄씩 읽고 실행하는 방식의 언어컴파일 과정 없이 즉시 실행되지만, 실행 속도는 컴파일 언어보다 느림언어: JS, Python, Ruby 등 메모리 종류 레지스터CPU 내부에 존재하는 가장 빠른 기억장소매우 빠른 연산을 위해 사용되며, CPU가 직접 접근할 수 있음휘발성(Volatile) 메모리 → 전원이 꺼지면 데이터가 사라짐 캐시메인 메모리(RAM)와 CPU(레지스터) 사이에 위치하는 고속 메모리CPU가 자주 사용하는 데이터를 미리 저장하여 접근 속도를 높임 메인메모리(RAM)운영체제(OS)와 실행 중인 프로그램이 올라가는 공간휘발성 메모리가격이 비싸기 때문에, 데이터 저장보다는 실행 중인 프로그램을 로드하는 용도로 사용HDD(하드디스크)나 SSD보다 훨씬 빠르지만, 레지스터나 캐시보다는 느림 보조저장장치(HDD,SSD)가격이 저렴하며, 데이터를 영구적으로 저장하는 용도로 사용됨비휘발성(Non-Volatile) 메모리 → 전원이 꺼져도 데이터가 유지됨 메모리 할당 방식 메모리 오버레이프로그램이 메모리보다 클 경우, 실행에 필요한 부분만 메모리에 로드하는 방식나머지 코드는 하드디스크에 저장되며, 필요할 때만 메모리에 불러옴가변 분할 방식프로세스 크기에 맞춰 메모리를 동적으로 분할하는 방식외부단편화 발생: 여러 개의 작은 빈 공간이 생겨 새로운 프로세스를 할당하기 어려운 문제고정 분할 방식프로세스 크기와 상관없이 미리 정해진 크기로 메모리를 나누는 방식장점: 구현이 간단하고 오버헤드가 적음단점: 작은 프로세스는 큰 영역에 할당되서 공간이 낭비되는 내부단편화 발생버디 세스템가변 분할 방식과 고정 분할 방식을 혼합하여 단점을 최소화한 메모리 할당 방식메모리를 2의 승수 크기로 분할하여 할당2주차 회고재귀가 너무 어렵다.. 정렬은 그래도 예전에 공부해본적이 있어서 한두번 더 보니까 이해가 되는데 재귀는 봐도봐도 이해가 어려움..특히 하노이ㅋㅋㅋㅋ 새로운 벽이였다. 그래도 자주 보다보니 적응이 되는것 같기도 하고 아닌거 같기도하고,,,그렇다 보니 미션 3번째 문제는 도무지 이해가 쉽지 않았다. 그래서 GPT의 도움과 함께 계속 이해해려하고 있고 지금도 하고있다,,ㅎ그리고 2주차때는 중간점검을 통해 다같이 구글밋을 했다. 주 내용은 운영체제같은 CS지식이 있으면 다른 프레임워크나 컴퓨터 쪽의 지식을 쌓고 배울때 지식이 없는사람에 비해 더 빠르게 습득할 수 있고, 흡수하는게 빠르다고 했다. 벌써 다음주가 3주차라서 CS는 마지막 주 인데 마무리 잘해서 수료하고, 수료 이후에도 강의 반복해서 듣고 자료구조 & 알고리즘은 심화버전이 있어서 그걸 들어야 할 것 같다.
알고리즘 · 자료구조
・
자료구조
・
알고리즘
・
운영체제
・
인프런워밍업클럽
・
CS
2025. 03. 08.
0
인프런 워밍업 클럽 3기 풀스택 - 1주차 발자국
1주차 학습 내용Firebase vs SupabaseFirebase 특징BaaS: 서버 없이도 빠르게 앱 출시 가능커뮤니티, 문서화 잘되어 있음, 단순한 NoSQL 기반으로 돌아감Supabse보다 비쌈, 오픈소스 아님NoSQL기반이라 복잡한 쿼리 불가하고, 웹 개발엔 그닥,, Supabase 특징오픈소스 구성, PostgreSQL 기반다양한 연동 방식을 지원함커뮤니티, 문서화 부족비교적 적은 기능 Server Action서버에서 실행되는 비동기 함수API 호출 없이 서버에서 바로 데이터 변환 메타데이터SEO를 정의하는 방식Static과 Dynamic 방식이 있는데 추 후 더 배울 예정Tailwindcss 테일윈드 CSS 예제 유틸리티 퍼스트(Utility-First) 방식의 CSS 프레임워크로, 미리 정의된 클래스를 조합하여 빠르게 스타일을 적용할 수 있도록 도와준다.CSS를 직접 작성할 필요 없이 클래스만 조합하여 스타일링 가능 RecoilReact에서 상태 관리를 쉽게 할 수 있도록 도와주는 상태 관리 라이브러리Redux 같은 라이브러리보다 가볍고 사용법이 간단함전역 상태뿐만 아니라 컴포넌트 간의 상태 공유를 효율적으로 관리할 수 있음비동기 상태 관리도 지원하여 서버 데이터를 다룰 때도 유용함 React Query React Query는 비동기 데이터(fetching, caching, synchronization)를 효율적으로 관리하는 라이브러리다.서버 상태 관리에 특화되어 있으며, API 호출 후 데이터를 캐싱하고 자동으로 최신 상태를 유지할 수 있도록 도와준다.React에서 API 요청을 효율적으로 관리하려면 필수적인 라이브러리다.1주차 미션1주차 미션에서는 강의에서 배운 TODO 앱을 기반으로,새로 생성한 TODO는 생성된 시간(created_at)을 표시하고,수정한 TODO는 수정된 시간(updated_at)을 즉시 UI에 반영하도록 구현하는 것이 목표였다. // ui.tsx const createTodoMutation = useMutation({ mutationFn: () => createTodo({ title: "New TODO", completed: false, created_at: new Date().toISOString(), }), onSuccess: () => { todosQuery.refetch(); }, });✅ useMutation을 통해 새로운 TODO를 생성할 때, created_at을 추가하여 서버에 요청하도록 구현했다.✅ 이를 통해 TODO가 생성된 시간을 함께 저장할 수 있도록 설정했다. // todo.tsx const [updatedTime, setUpdatedTime] = useState(todo.updated_at); const updateTodoMutation = useMutation({ mutationFn: () => updateTodo({ id: todo.id, title, completed, updated_at: updatedTime, }), onSuccess: () => { setIsEditing(false); queryClient.invalidateQueries({ queryKey: ["todos"], }); }, }); ---------------------- {title} {new Date(todo.updated_at ?? todo.created_at).toLocaleString( "ko-KR", { year: "numeric", month: "2-digit", day: "2-digit", hour: "numeric", minute: "2-digit", hour12: true, } )} ✅ 수정할 때마다 updated_at을 추가하여 최신화된 시간을 서버로 전송하도록 설정했다.✅ 수정된 TODO(updated_at)가 있다면 수정 시간을, 그렇지 않다면 생성 시간(created_at)을 표시하도록 구현했다.✅ 기본적으로 ?? 연산자를 사용해 updated_at이 존재하는 경우 이를 우선적으로 표시하도록 처리했다.✅ 시간 포맷이 "2025.03.09 오후 7:34" 형식으로 나타나도록 toLocaleString()을 활용해 변환했다. 1주차 회고 내가 이 강의를 수강한 이유는 배우고 싶었던 Recoil, React Query, Supabase를 익히기 위해서였다.하지만 생각보다 많이 어려웠다. 역시 한 번 본다고 해서 쉽게 익힐 수 있는 건 아니라고 느꼈다.섹션 2까지는 본격적인 실습을 하기 전에 준비 단계라고 생각했다.그리고 섹션 3부터는 본격적으로 TODO 프로젝트를 만들면서 학습을 진행했다.Supabase를 사용하면서 백엔드의 기본적인 동작 방식을 조금이나마 이해할 수 있었다.신기하기도 했지만, 한편으로는 어렵기도 했다.미션 자체는 그렇게 어렵다고 느껴지지는 않았다.결국 등록 시간과 수정 시간을 표현하는 것이 핵심이었기 때문이다.하지만 강의에서 React Query나 Supabase를 다루는 부분은 이해가 잘되지 않아 여러 번 반복해서 학습해야 할 것 같다.어려워서 살짝 우울하기도 하지만...결국 어려운 만큼 성장할 수 있는 부분이 많다는 뜻이니까! 😂🔥
풀스택
・
풀스택
・
미션
・
인프런워밍업클럽
・
supabase
・
next.js
2025. 03. 07.
0
인프런 워밍업 클럽 3기 CS - 1주차 미션
1주차 학습 내용 - 미션자료구조 & 알고리즘 1. 여러분은 교실의 학생 정보를 저장하고 열람할 수 있는 관리 프로그램을 개발하려고 합니다.이 때 여러분이라면 학생의 정보를 저장하기 위한 자료구조를 어떤 걸 선택하실 건가요? 이유를 함께 적어주세요. 학생의 정보를 저장하기 위해서는 이름, 학번, 반 번호 등의 데이터를 함께 관리해야 한다.이때 빠르게 학생을 검색하고 관리할 수 있도록 키-값(Key-Value) 구조를 사용하는 해시테이블(Hash Table)을 선택하는 것이 적절하다. 2. 여러분은 고객의 주문을 받는 프로그램을 개발하려고 합니다. 주문은 들어온 순서대로 처리됩니다.이 때 여러분이라면 어떤 자료구조를 선택하실 건가요? 이유를 함께 적어주세요. 주문이 들어온 순서대로 처리되어야 하므로 먼저 들어온 데이터가 먼저 처리되는 FIFO(First In, First Out) 구조가 필요하다.따라서 큐(Queue)를 사용하는 것이 가장 적절하다. 3. 우리가 구현한 스택은 0번 인덱스, 즉 입구쪽으로 데이터가 삽입되고 나오는 구조입니다.반대로 마지막 인덱스, 즉 출구쪽으로 데이터가 삽입되고 나오는 구조로 코드를 변경해주세요.// 원래 스택 코드 -> 0번 자리에 삽입하고 0번 자리를 삭제함 push(data) { this.list.insertAt(0, data); } pop() { try { return this.list.deleteAt(0); } catch (e) { return null; } } -------------------------------- // 문제에서 요구하는 스택 코드 -> 마지막 자리에 삽입하고 마지막 자리를 삭제함 push(data) { this.list.insertAt(this.list.count, data); } pop() { try { return this.list.deleteAt(this.list.count - 1); } catch (e) { return null; } } this.list.count는 현재 연결 리스트에서 저장된 노드의 개수를 의미한다.그러므로 this.list.count를 응용해서 0자리에 넣어줬다.pop의 경우 마지막 인덱스를 알기위해서는 -1 까지해줘야 끝자리를 알 수 있다. 4. 해시테이블의 성능은 해시 함수에 따라 달라집니다. 수업 시간에 등번호를 이용해 간단한 해시 함수를 만들어봤습니다. 이번엔 등번호가 아닌 이름을 이용해 데이터를 골고루 분산시키는 코드로 수정해주세요.힌트: charCodeAt() 함수를 이용 예시: name1 = "이운재"; name1.charCodeAt(0); // 51060 이운재의 0번 인덱스 ‘이’의 유니코드 출력 // 원래 코드, 등번호를 10으로 나눠서 데이터를 분산시킴 hashFunction(number) { return number % 10; } -------------------------------------- // 문제에서 요구하는 코드, 아스키코드를 활용해서 이름의 성으로 데이터를 분산시킴 hashFunction(name){ return name.charCodeAt(0) % 10; } -------------------------------------- // 실행 코드 import { HashTable } from "./HashTable_mission.mjs"; let hashTable = new HashTable(); hashTable.set("이운재", 1); hashTable.set("최진철", 4); hashTable.set("홍명보", 20); hashTable.set("유상철", 6); hashTable.set("송종국", 22); hashTable.set("박지성", 21); hashTable.set("김남일", 5); hashTable.set("이영표", 10); hashTable.set("최태욱", 8); hashTable.set("설기현", 9); hashTable.set("이천수", 14); console.log(`이운재: ${hashTable.get("이운재")}`); // 1 console.log(`박지성: ${hashTable.get("박지성")}`); // 21 console.log(`홍명보: ${hashTable.get("홍명보")}`); // 20 hashTable.remove("이운재"); console.log(`이운재: ${hashTable.get("이운재")}`); // null (제거됨) charCodeAt을 활용해서 코드를 수정했고,문제점이 생기게 됨.1. TypeError: name.charCodeAt is not a function원인은 기존 코드에서는 키가 등번호, 값이 이름이었기 때문에 등번호(숫자)와 charCodeAt()이 만나면서 에러가 발생했다.이를 해결하기 위해 키와 값의 역할을 바꿔 이름을 키로, 등번호를 값으로 사용하도록 수정했다.그 결과 에러는 해결되었고, 각 이름이 올바르게 해시 테이블에 저장되도록 변경할 수 있었다. 2. 하지만 새로운 문제 발생현재 로직에서는 배열 크기가 10이므로, 이름의 첫 글자의 유니코드 값을 this.arr.length로 나눈 나머지를 사용하여 10개의 버킷 안에서만 데이터를 분산시키게 된다.즉, 같은 나머지 값을 가지는 성씨끼리 같은 버킷을 공유해야 하는 문제가 발생한다.예를 들어, "이"씨(유니코드 51060)와 "한"씨(유니코드 54620)는51060 % 10 = 0, 54620 % 10 = 0이므로 둘 다 arr[0]에 저장된다.이는 실행 코드에서 주어진 인원들에게는 문제가 되지 않지만,새로운 성씨가 추가될 경우 충돌(Collision)이 발생할 가능성이 높다.3. 유니코드를 직접 키 값으로 사용할 경우?유니코드를 직접 해시 키로 사용해봤지만, 그렇게 되면 해시 키 값이 51060, 44608, 48149 같은5만이 넘는 숫자가 되어 배열을 활용한 해시 테이블의 장점(빠른 접근)이 사라지는 문제가 생긴다.4. 결론 & 의문점결국, 내가 문제를 잘못 이해한 것인지, 아니면 단순히 실행 코드에 있는 인원들만 고려하면되는 문제인지 애매한 부분이 남았다. 운영체제 1. 해당 코드는 1초 마다 플레이어가 스킬을 사용했는지 체크하는 코드입니다.while(true){ wait(1); // 1초 멈춤 bool isActivated = checkSkillActivated(); // 체크 }이 방식은 폴링방식입니다. 1초마다 체크하기 때문에 성능에 좋지 않습니다. 이를 해결하기 위한 방식으로 어떤 걸 이용해야 할까요?폴링 방식은 CPU가 일정한 주기로 이벤트 발생 여부를 확인해야 하기 때문에 불필요한 연산이 많아 성능이 저하된다.즉, 이벤트가 발생하지 않아도 CPU가 계속 체크해야 하므로 CPU 자원이 낭비됨이 문제를 해결하려면 인터럽트 방식을 사용해야 한다.인터럽트 방식은 이벤트가 실제로 발생할 때만 CPU가 반응하여 처리하는 방식이므로, CPU가 불필요한 작업을 하지 않고 효율적으로 사용할 수 있다.결론적으로 CPU는 이벤트가 발생할 때만 작업을 중단하고 처리를 한 후, 다시 원래 작업을 수행할 수 있다. 2. 프로그램과 프로세스가 어떻게 다른가요?프로그램은 저장장치에 보관된 실행 가능한 명령어들의 집합으로 실행되지 않은 상태를 의미한다.프로세스는 프로그램이 메모리에 적재되어 CPU에서 실행되는 상태를 뜻하며 실행 중인 코드와 필요한 메모리 공간 그리고 시스템 자원을 포함한다. 3. 멀티프로그래밍과 멀티프로세싱이 어떻게 다른가요? 멀티프로그래밍은 단일 CPU에서 여러 프로그램을 번갈아 실행하며 CPU 활용도를 높인다.멀티프로세싱은 여러 개의 CPU를 사용해 실제로 동시에 여러 작업을 수행한다. 4. 운영체제는 프로세스를 관리하기 위해서 어떤 것을 사용하나요?프로세스가 생성되면 운영체제는 해당 프로세스의 상태, 메모리 정보, CPU 레지스터 값, 우선순위 등의 정보를 담은 PCB(Process Control Block) 를 생성하고 저장한다. 운영체제는 PCB를 이용해 프로세스를 추적하고 관리하며, 문맥 전환(Context Switching) 시 필요한 정보를 저장하고 복원한다. 5. 컨텍스트 스위칭이란 뭔가요?컨텍스트 스위칭(Context Switching)은 현재 실행 중인 프로세스를 중단하고 다른 프로세스를 실행하기 위해 CPU의 상태(레지스터 값, 프로그램 카운터, 스택 포인터 등)를 저장하고 복원하는 과정이다.운영체제는 프로세스 간 전환을 원활하게 하기 위해 각 프로세스의 상태 정보를 PCB(Process Control Block) 에 저장하며 이후 프로세스가 다시 실행될 때 저장된 정보를 복원하여 이어서 작업을 수행한다.
알고리즘 · 자료구조
・
자료구조
・
알고리즘
・
운영체제
・
미션
・
인프런워밍업클럽
・
CS
2025. 03. 03.
0
인프런 워밍업 클럽 3기 CS - 1주차 발자국
1주차 학습 내용 - 발자국자료구조 & 알고리즘 자료구조데이터가 어떤 구조로 저장되고 어떻게 사용되는지 나타낸 것예를들어 데이터를 변수에 담아 처리하는 평균을 구하는 식과 배열에 담아 평균을 구하는 식이 다른 로직으로 돌아가는 것 처럼?알고리즘어떤 문제를 해결하기 위한 확실한 방법같은 자료구조에도 다양한 알고리즘(풀이법)이 존재하기 때문에 적합하다고 판단되는 것을 골라 사용하면 됨.시간복잡도특정 알고리즘이 어떤 문제를 해결하는 데 걸리는 시간표기법은 빅오 표기법으로 사용하고 반복문이 한번 돌면 O(n)이라고 함. O(n) -> O(n²)연결리스트데이터를 저장하는 선형 자료구조, 각 요소(Node)가 다음 요소를 가리키는 방식으로 연결된 구조Node의 구성요소: data(자신), next(다음)장점: 아무 곳에 데이터를 생성하고 연결만 해주면 되기때문에 배열의 단점을 극복함단점: 배열은 인덱스를 통해 O(1)로 즉시 접근 가능하지만, 연결 리스트는 head부터 순차적으로 접근해야 하므로 O(n)의 탐색 시간이 필요함 스택(FILO)먼저 들어간 데이터가 나중에 나오는 자료구조 큐(FIFO)먼저 들어간 데이터가 먼저 나가는 자료구조 덱데이터의 삽입과 제거를 자유롭게 할 수 있는 자료구조, 쉽게말해 스택 + 큐 같은 느낌 해시테이블Key-Value(키-값) 쌍으로 데이터를 저장하는 자료구조장점: 빠른 데이터 읽기, 삽입, 삭제단점: 메모리를 많이 차지함 셋 데이터의 중복을 허용하지 않는 자료구조운영체제커널운영체제의 핵심프로세스와 메모리, 저장장치를 관리하는 핵심적인 기능 담당사용자는 커널에 접근하기 위해 인터페이스(GUI, CLI)를 통해 접근 가능함.CPU제어 장치, 산술논리 연산장치, 레지스터로 나뉨폴링과 인터럽트폴링은 CPU가 하드웨어 쪽에서 어떤 일이 바로 발생하는지 인지할 수 없어서 입출력 명령이 왔는지 주기적으로 확인하여 작업을 완료하는 방식인터렙트는 이런 불필요하게 확인하는 폴링의 단점을 보완해서 CPU에서 입출력 명령을 내리고 다른일을 하다가 입출력이 완료 되었다는 신호를 받고 작업을 완료하는 방식프로그램과 프로세스프로그램은 저장장치에 저장된 명령문의 집합체( 앱, .exe )프로세스는 실행중인 프로그램(하드디스크에 저장된 프로그램이 메모리에 올라갔을 경우 실행중이라고 함)멀티프로그래밍과 멀티프로세싱멀티프로그래밍은 메모리로 여러개의 프로그램을 올려놓고 사용하는 것멀티프로세싱은 시분할 처리로 CPU가 각각의 프로세스를 짧은 시간 동안 교대로 실행하는 것컨텍스트 스위칭프로세스를 동작하다가 다른 프로세스를 동작시키기 위해 현재 프로세스를 저장하고 다른 프로세스로 바꾸는 과정현재까지 진행된 CPU의 레지스터 값을 동작했던 프로세스에 저장하고, 나중에 다시 그걸 가지고 이어서 작업함.CPU 스케줄링운영체제가 여러 프로세스의 실행을 기다릴 때, CPU를 어떤 순서와 방식으로 할당하고 해제할지를 결정하는 과정FIFO가장 먼저 들어온 프로세스를 먼저 처리하는 방식단점: P1이 실행되는 동안 P2, P3가 기다려야해서 대기 시간 지며 CPU 사용률이 떨어짐.SJF실행 시간이 제일 짧은 프로세스를 먼저 처리하는 방식단점: 프로세스가 얼마나 실행될지 알 수 없음, 실행시간이 긴 프로세스는 오랫동안 실행되지 않을수도 있음.RR모든 프로세스에게 공평하게 CPU 시간을 할당하는 방식단점: 타임 슬라이스가 너무 길면 굉장히 끊기고, 너무 짧으면 컨텍스트 스위칭이 자주 일어나며 불필요한 처리를 해야함. 그래서 적절한 타임슬라이스를 지정해줘야 함.MLFQ여러 개의 큐를 사용하여 우선순위를 동적으로 변경하는 방식짧은 작업은 낮은 타임슬라이스를 주고, 긴 작업은 높은 타임슬라이스를 부여함. (현대에서 제일 많이 사용)1주차 회고비전공자여서 CS지식은 완전 0이라 복습을 자주 해야할 것같다고 생각했습니다.감자 강사님께서 강의는 지루하지 않고 이해가 편하도록 노력해서 만드신게 눈에 보였음(각종 더빙, 캐릭터들), 사물궁이라는 유튜버가 있는데 그 방식과 굉장히 흡사해서 재미있게 볼 수 있음. 저같은 경우는 익숙하지가 않아서 한번 본다고 머리에 잘 들어오진 않아서, 대중교통 타거나 심심할때마다 반복해서 보면 자연스럽게 조금씩 이해가 되는거같아서 좋았습니다.
알고리즘 · 자료구조
・
자료구조
・
알고리즘
・
운영체제
・
인프런워밍업클럽
・
CS