블로그

빠타박스

[인프런 워밍업 클럽 2기 - CS] 지난 3주간의 여정 속에서 - 완주 후기

처음 이걸 왜 들었을까?이 과정을 듣기 2일쯤 됬던가. 벤처 게임회사에 면접을 보았다.그 회사의 면접은 그냥 말아먹었다.그 이유는 역시 기초 지식이다.  공부한지 어연 5년이 다된간다. 이쯤되면 게임개발이라는 것을 포기할만도 했다...어떻게 해야할까 하는 찰나에 인프런에 들어와 여느때 처럼 그냥 공부를 하고자 한숨을 내쉬며 들어왔는데바로 보이는... CS 이게 무슨일이지 하면서 한번 볼까? 무료라고?아.. 근데 아니였다... 기본적으로 할인을 해주나 로드맵에 있는 수강내역을 구매해야만 참가가 가능했다.나는 좀 아쉬웠다.. 가뜩이나 백수 5년째 거금을 들이기가 선뜻 겁이 났다... 그렇게 많은 돈은 아닐 수 있었지만... 나에게는 식비와 공과금을 충당해야만 하는 비용이였기 때문이다.하지만 면접에서 탈탈 털린 나로써는 CS지식이 시급했다... 나에겐 여러 장애물이 있었다...자격증 시험이였다... 항상 내 발목을 묶는 장애물이였다.이 과정을 진행하면서 실기일이 얼마 남지 않은 상태였다... 그럼에도 불구하고 CS 지식을 터득하자. 하지만 가볍게 보고 다음에 다시 보도록 하자는 마인드였다.(내가 반복하는 걸 싫어하다 보니까... 이게 참 문제다... )그렇게 그냥 열심히 했다...그냥 할 수 있는 만큼...  공부는 어떻게 해야 하죠? 난 솔직히 아직도 개발 공부란 것을 어떻게 해야할 지 모르겠다...그냥 받아적고 천천히 느리게 한다. 하나 볼때 최대한 이해하려고 다 적는다.하지만 남는게 별로 없다...반복학습이 생명인 것을 알겠다..ADHD를 겪고 있던 나로써 반복학습은 정말 지겨웠다.. 그래도 반드시 해내자 라는 마인드로 임했다...그렇게 공부한 것들을 필기하고 요약하려고 하였지만 쉽지 않았고, 최대한 가볍게 이해하려고 했다. 가장 어려웠던건 알고리즘 부분이였다... javascript로 하다보니 C++로 변환하려니까. 뭔가 비슷은 한데 헷갈리는 부분이 많았다... 안되던 것도 있었고,,,... 쉽지 않았다... 정처기 얼마 남지 않았는데 계속 붙들고 있는 경우도 발생했다그게 1주차 때이다. 그냥 무작정 하라는 대로 하였다. 최대한 깊어보이면서 간결하게다른 사람들이 쓴 것도 보았으면 좋았겠지만. 쓰고 바로 정보처리기사 공부를 해야만 했다. 18일 금요일 모든 과정이 종료 되었고, 이제 수료식만을 남겨둔채 나는 정보처리기사 공부를 집중했다.10월 20일 일요일 정보처리기사 D-Day...,..실기는 매우 어려웠었고 조졌다.... 그렇게 돌아와 낙심에 빠졌다... 그리 며칠 가지 않아서하.. CS 관련해서 심화적으로 봐야만 한다는 것을 어떻게 할까 하다가.최대한 쿠폰을 사용해서.. 보고 싶은데 해서 결국 구매를 강행했다..아직 보진 않았다. 왜냐하면 이전꺼도 다시한번 봐야만한다.다시 반복학습을 해야만 하니까. 이 과정이 끝나고 정말 운수 좋은날인가... 아는 분을 통해 일자리를 얻게 되었다...처음에는 어리둥절했다... 뭔지도 모르고 뭘 시킬지도 모르는데... 게임개발만 3년 정도를 팠다....언리얼엔진....갔더니 대표님이 언리얼엔진에 대한 이전 문제 때문에 나를 궁금해 하셨고 그일을 나에게 맡기셨다..부담스럽기도 하고 기회다 하며 재밌겠다 하며 그 기회를 붙잡았다...11월 4일 부로 출근하게 되었다. 그래서 언리얼엔진 심화 및 기초에 대한 내용을 공부하고 있어서 해당 자료구조를 못보고 있었다.  수료식그렇게 11월 1일(금)원래대로면 오프라인에 참석해야 하나.. 나의 직업군인시절 후유증으로 인해...갑자기 도져서 가지 못한다고 말하게 되었다...시작된 워밍업 클럽 수료식 과정중 코치님 감자 강사님께서 나오셔서 질의 응답 시간을 가졌다.유익한 시간이였고 좋은 정보도 얻었다. 추천 받은 책 : CODE (컴퓨터 구조에 대한 내용 밑바닥?)https://elfmfl.tistory.com/33 (펌 정보) 난 아직도 많은 공부를 해야만한다는 것을 느꼈다. 저곳에 모인 사람들 중에 분명 나보다더 대단한 사람도있고젊고 파릇파릇한 분들도 있을테고 여럿 사람들이 모였었을 것이다.부러웠다.. 저 자리에 위치할 수 있어서...하지만 또 나름 나의 시간을 아끼며 공부를 했다. 그렇게 질의응답시간이 끝나고 수료식의 대망의 수상 발표이다. 응?뭐지.. 적어도 26~30명 정도 CS 과정을 들었던거 같은데.. 우수러너에 뽑히게 되었다....다들 수상을 하고 있을 때 그저 축하해주기 위해서 남아있었는데.내가 수상하게 될 줄 은 꿈에도 몰랐다. 그래서 이 감사를 어떻게 해야 할지 바로 누군가에게 자랑을 했다. ㅎㅎ;;감사한 하루였다. 앞으로 어떤 과정이 또 생길지 모르겠다.하지만 이제 일을 시작했고, 이 일을 완벽히 하기 위해 더더욱 기초가 다져져야 한다.이 과정과 고난의 길 위를 즐기자. 기쁨으로 하루를 살아가자 이 과정을 겪을 수 있어서 감사합니다.인프런을 통해 많은 청년들이 새 꿈을 이룰 수 있게 해줬으면 좋겠다. " 모든 것의 가장 빠른 배움은 부딪히는 것이다. 그게 밑바닥이 되었든.가장 좋은것은 프로젝트를 하고 현업처럼 부딪히는 것 "     이제 다가올 2025년도를 위해인프런 공부를 하며 여러 사건과 여러 정치적인 이슈들이 있었다.우리는 내일을 위해 무언가를 지켜야 하고 싸워야 하는 경우가 생길 것이다.그저 지금 편안하게 우리가 공부할 수 있는 것은 누군가 희생되고 있음을 깨달아야 한다. "모든 일에는 당연한 것이 없다" 누군가의 배품, 누군가의 선함, 누군가의 악행,모든 것에는 이유가 있다. 포괄적차별금지법북한군파병이스라엘과 하마스 및 헤즈볼라윤모의 자금 횡령 및 국가비상금 빼돌림 여러 이슈들이 존재 한다. 우리는 공부하면서 깨어있어야 한다. 우리 미래가 결정되고우리 후대의 미래가 결정된다.해외 부자들 CEO들이 우리나라의 급격한 인구가 줄어드는 것을 바라보고 있다..대책이 없다... 그저 장막 안에서 보호를 받으면서 공부를 하는것도 그렇지만. 나라가 없어지면..공부도 무의미 하다... 깨어있는 공부를 하자. 부디 25년도에는 많은 것들이 청렴해지고 나아지길 바란다. 끝없이 성장하는 개발자가 되고생존하자. 버티며 끝까지 임하자 최선을 다하자. 내일 죽는한이 있더라도 자신의 위치에서 최선을다하자

알고리즘 · 자료구조인프런인프런워밍업클럽스터디2기자료구조알고리즘감자워밍업클럽

rhkdtjd_12

인프런 워밍업 클럽 2기 - CS 전공지식 스터디 3주차 마지막 발자국

 3주차 회고1주일에 3회 발표 하는 방식의 복습 스터디가 3주만에 드디어 끝이 났다.팀원 분들이 없었다면 나는 아마 완강도 못했을것같다. 사실 이렇게 1주일에 3번의 스터디를 한다는거와 그중 1번은 무조건 발표 해야 한다는것은 굉장히 부담이다.근데 무려 참석률 100% 를 달성하며 무사히 스터디를 마칠 수 있었던것은 정말 좋은 스터디원들을 만났기 때문이다.스터디는 확실히 나에게 좋은 영향력을 끼친것 같다. 우선적으로 내가 공부하는 방법에 대해서 고민하게 되었다. 원래 내가 강의를 공부하는 방법은 강의를 한번 보면서 중요한것들만 요약하면서 공부를 했었다. 근데A팀원분은 강의를 보면서 1차 정리를 하고 그다음에 한번더 2차정리를 하신다고 한다. 그러한 과정에서 이제 그림 그리면서 내용을 정리 하시는데 확실히 이렇게 2회독 정도 하면서 그림과 설명을 붙여가면서 정리를 하니까 복습도 잘되고 이해도 잘되는것 같았다.B팀원분은 강의를 빠르게 1번 보고 2번째 볼때 꼼꼼하게 정리를 하신다고 하셨다. 근데 꼼꼼하게 정리한다는것이 나 같은 경우에는 강의에 있는 내용들만 보통 보고 넘어간다면 이분은 좀 더 자세하게 다른 서적이나 자료들을 찾아보면서 연관되는 내용들도 함께 공부하신다. 확실히 CS 개념들을 정확하게 짚고 넘어가려면 이렇게 꼼꼼하게 공부하는게 맞는것 같다. 왜냐하면 운영체제에 대한 질문이 들어오고 강의에 대한 내용만 기억하고 있다면 첫번째 질문에는 답변 할 수 있겠지만 그에 맞는 꼬리 질문이 들어온다면 아마 대답하지 못할것이기 때문이다.앞으로 나에게 맞는 공부방법을 변형해가면서 연구 해봐야겠다. 추가적으로 해당 CS정리를 잘 하고 난후에 어떻게 해당 내용들을 개발 관련일을 하면서 휘발 되지 않고 오래 기억에 가져갈 수 있는지에 대한 고민도 해봐야겠다. 끝으로 마지막 발표 자료 캡쳐로 마무리 짓겠다.3주차 학습 요약운영체제가상메모리 개요: 물리 메모리의 한계를 극복하여 프로그램이 실제 메모리 크기와 상관없이 실행될 수 있게 해줌. 스왑 영역과 함께 사용.세그멘테이션과 페이징:세그멘테이션: 프로그램을 함수나 모듈로 나누어 할당. 외부 단편화 o, 내부 단편화 x페이징: 메모리를 동일 크기로 나누어 할당. 외부 단편화x . 내부 단편화 o혼용기법 (페이지드 세그멘테이션): 세그멘테이션과 페이징의 장점을 결합.디맨드 페이징: 자주 쓰이는 데이터만 메모리에 로드. 페이지 교체 알고리즘 사용.스레싱과 워킹셋: 과도한 스왑 작업으로 인해 성능 저하가 발생하는 현상. 워킹셋은 자주 쓰이는 페이지 집합을 유지.주변장치: 캐릭터 디바이스(마우스, 키보드)와 블록 디바이스(하드디스크, SSD)로 구분됨. DMA로 메모리에 접근.파일과 파일시스템: 파일 관리자는 파일 생성, 수정, 삭제, 권한 관리 등을 수행. 디렉토리는 파일을 체계적으로 관리하기 위한 구조.자료구조와 알고리즘정렬 알고리즘:삽입정렬: 이미 정렬된 부분에 새 값을 삽입. 시간복잡도 O(n²).병합정렬: 재귀적으로 나눈 후 병합. 시간복잡도 O(n log n).퀵정렬: 피벗을 기준으로 좌우 분할. 평균 시간복잡도 O(n log n), 최악 O(n²).동적 프로그래밍:메모이제이션: 재귀로 계산 시 결과를 저장해 중복 계산을 피함. 하향식 접근.타뷸레이션: 상향식으로 필요한 값을 모두 미리 계산해 테이블에 저장.

알고리즘 · 자료구조알고리즘자료구조운영체제

rhkdtjd_12

인프런 워밍업 클럽 - CS 3주차 미션

운영체제1. 메모리의 종류는 어떤것들이 있나요? 각 메모리의 특징도 함께 적어주세요.- 레지스터 : CPU 내부에 위치한 가장 빠른 메모리로 CPU가 명령어를 실행할 때 직접 사용합니다.- 캐시 : CPU와 메인 메모리(RAM) 사이에 위치하고 CPU의 성능을 높이기 위해 사용되는 고속 메모리입니다.- 메인 메모리(RAM) : 빠르지만 휘발성 메모리입니다.- 보조 저정장치(HDD,SSD) : 영구 저장 장치로 데이터의 비휘발성 저장합니다.2. 사용자 프로세스가 메모리의 운영체제 영역에 침범하지 못하도록 만든 레지스터는 어떤 레지스터일까요?- 경계 레지스터입니다.- 경계 레지스터는 CPU내에 존재하고 메모리 관리자가 사용자 프로세스가 경계 레지스터값을 벗어나면 해당 프로세스를 종료 시킵니다.3. 메모리 할당 방식에서 가변 분할 방식과 고정 분할 방식의 장단점은 뭔가요?- 가변 분할방식장점 : 1. 메모리를 가변적으로 분할 가능2. 코드, 데이터, 힙, 스택 영역을 모듈로 처리 가능3. 해당 영역을 쉽게 공유 할 수 있고 메모리 접근 보호도 편리합니다.4. 내부 단편화가 없습니다.단점 1. 외부 단편화가 발생합니다. -> 이를 해결하기 위해 조각모음을 사용하는데 -> 이는 모든 프로세스를 정지하고 해야하기 때문에 굉장히 오버헤드가 큰작업 입니다.- 고정 분할 방식장점1. 메모리를 정해진 크기 만큼 분할 가능2. 구현이 간단하고 오버헤드가 작습니다.3. 외부 단편화가 없습니다.단점1. 내부 단편화가 발생합니다. -> 이를 해결 할순 없지만 내부 단편화를 최소화 하는것이 제일 메모리를 효율적으로 사용 할 수 있는 방법입니다.4. CPU 사용률을 올리기 위해 멀티프로그래밍을 올렸지만 스왑이 더 많이 이루어져 CPU 사용률이 0%에 가까워 지는 것을 뭐라고 할까요?스레싱이라고 합니다.CPU 사용률은 높지만 시스템 성능이 떨어지는 현상을 말합니다.5. HDD나 SSD는 컴퓨터를 실행시키는데 꼭 필요한 걸까요?> 컴퓨터를 부팅하는데 필요한 os가 필요한데, HDD나 SSD에 해당 os가 저장되어 있다고 알고 있습니다.> 근데 생각 해보니까 만약에 USB에 os를 두고 컴퓨터와 연결시켜서 실행 한다면 실행 할 수 있을것 같습니다!!!> 옛날에 어릴때 컴퓨터를 처음 삿을때 window 운영체제를 설치 해야 되는데 그걸 USB를 통해서 설치 했던 기억이 있습니다. 즉, 그때도 컴퓨터를 실행할때 USB를 통해서 실행한것이지 SSD와 HDD와는 상관 없었던것 같습니다.6. 파일을 삭제해도 포렌식으로 파일을 복구할 수 있는 이유가 무엇일까요?사용자가 파일을 삭제 했을때 파일 테이블에서 해당 파일의 헤더를 지웁니다.사용했던 블록을 free block list에 넣습니다.즉, 사용자는 파일이 삭제된것처럼 느끼지만 실제로는 사용 했던 블록의 데이터는 free block list에 그대로 남아 있어서 파일을 복구 할 수 있게 됩니다.자료구조와 알고리즘1. 지금까지 배운 5개의 정렬 알고리즘의 장단점과 시간 복잡도를 적어주세요.버블 정렬 - 장점 : 구현이 쉽다.- 시간 복잡도 : O(n2)- 단점 : 시간 복잡도가 O(n2)으로 성능이 안좋다.선택 정렬 - 장점 : 구현이 쉽다.- 시간복잡도 : O(n2)- 단점 : 시간 복잡도가 O(n2)으로 성능이 안좋다.삽입정렬- 장점 : 구현이 쉽다.- 시간 복잡도 : O(n2)- 단점 : 시간 복잡도가 O(n2)으로 성능이 안좋다.병합 정렬- 장점 : 성능이 좋다.- 시간 복잡도 : nlogn- 단점 : 추가 메모리 공간이 필요하다.퀵 정렬- 장점 : 평균적으로 가장 빠른 정렬 중 하나이며, 메모리 사용이 효율적- 시간 복잡도 : 평균 : nlogn, 최악 : O(n2)- 단점 : 피벗 선택이 잘못되면 성능이 나빠진다.2. 메모리가 부족한 시스템에서 어떤 문제를 해결하는데 재귀로 쉽게 구현이 가능할 것 같습니다. 여러분이라면 메모이제이션과 타뷸레이션 중 어떤 걸 이용하실 건가요? 이유를 함께 적어주세요.메모리가 부족한 시스템에서는 저는 타뷸레이션(Tabulation)을 사용하는 것이 더 적합하다고 생각합니다.우리는 서비스를 제공하는 입장에서 치명적인 오류나 결함을 방지하고 사용자 경험을 보호하는 것이 가장 중요하다고 저는 생각합니다.메모이제이션은 힙메모리에 저장하기 때문에 메모리 부족 현상으로 인해 힙 메모리 부족으로 인한 오류가 발생하여 사용자에게 서비스 중단이나 예기치 못한 오류를 발생시킬 수 있습니다. 반면, 타뷸레이션은 반복문을 사용하여 스택 메모리를 절약하고, 필요 이상으로 힙 메모리를 사용하지 않아 메모리 효율적입니다. 또한 속도 측면에서 비교 해보았을때도 메모이제이션과 타뷸레이션의 성능은 거의 비슷하기 때문에 메모리가 부족한 시스템에서는 타뷸레이션을 선택하는게 바람직 하다고 생각합니다.

알고리즘 · 자료구조알고리즘자료구조운영체제

rhkdtjd_12

[인프런 워밍업클럽 CS 2기] 2주차 발자국

[2주차 학습 내용]자료구조와 알고리즘재귀: 자기 자신을 참조하는 방식. 프로그래밍에서는 콜 스택을 사용하며 FILO(First In Last Out)의 특징을 가짐.버블 정렬: 인접한 값들을 비교하여 정렬하는 알고리즘. 단순하지만 비효율적이며 O(n²)의 시간복잡도를 가짐.선택 정렬: 정렬되지 않은 부분에서 가장 작은 값을 찾아 정렬하는 방식. O(n²)의 시간복잡도를 가짐.  운영체제CPU 스케줄링: FIFO, SJF, RR, MLFQ 등 다양한 스케줄링 방식이 있음.프로세스 간 통신 (IPC): RPC, 공유 자원과 임계 구역, 세마포어, 모니터 등을 사용하여 프로세스 간의 통신 및 자원 접근을 관리함.교착 상태 (Deadlock): 상호 배제, 비선점, 점유와 대기, 순환 대기의 조건으로 발생. 식사하는 철학자 문제와 은행원 알고리즘이 교착 상태를 설명함.메모리 관리:메모리 종류: 상대 주소와 절대 주소.메모리 할당 방식: 고정/가변 분할 방식, 버디 시스템 [2주차 회고]순탄치 않았지만 개발 관련 인생 첫 스터디라는것을 모집해서 처음으로 참여를 하고 있습니다.처음에는 복습과 완강하자! 이런 가벼운 마음으로 시작한것인데 함께 참여하는 팀원 분들이 너무 잘하시고 열정적이십니다.즉, 저는 팀원복이 꽤 있는것 같습니다. 아마 혼자 달렸으면 완강은 못했을것 같은데 팀원들과 스터디를 진행 하면서 이분들과의 약속을 지키기 위해서라도 완강 하게 되는것 같습니다.발표 자료 캡쳐화면

알고리즘 · 자료구조운영체제자료구조알고리즘

Taeho

인프런 워밍업 클럽 - CS Week 2

AlgorithmRecursion(재귀)어떠한 것을 정의할 때 자기 자신을 참조하는 것을 의미한다.재귀함수 : 재귀적으로 정의된 함수재귀함수는 콜스택이라는 메모리 가득차게 되는 경우 자동으로 종료된다.기저 조건 : 재귀함수가 종료될 수 있는 탈출 조건기저 조건이 반드시 있어야 정상적으로 수행할 수 있다.재귀함수는 함수를 호출할 때마다 Call Stack이라는 메모리 공간에 호출정보가 저장된다.→ 재귀함수는 Loop문보다 더 많은 메모리 공간을 차지한다.Call Stack(= Stack)함수가 호출되면서 올라가는 메모리 영역함수가 종료되면 콜스택에서 제거된다.FILO(First-In Last-Out)재귀함수를 사용하는 이유Loop를 대신한다기 보다는 더 복잡한 문제를 쉽게 해결하기 위해 사용된다.ex) Factorial재귀함수를 쉽게 작성하는 방법재귀함수 내에서 자기 자신을 호출할 때 해당 함수가 벌써 구현이 되어있다고 가정한다.재귀 사용하는 패턴단순 반복문반복문으로 구현했을 때보다 이점이 되는 부분이 없음Call Stack에 공간을 많이 차지해 성능이 반복문보다 좋지 않다.하향식 계산하향식 계산 : 하위문제의 결과를 기반으로 현재 문제를 계산하는 방식재귀가 반복문보다 성능이 좋은 경우큰 문제를 해결하기 위해 작은 재귀 함수를 호출한다.재귀를 사용해서만 구현이 가능하다.상향식 계산 : 하위 문제를 모아서 현재 문제를 계산하는 방식반복문으로 구현한 것보다 성능이 좋지 않음반복문이나 재귀를 사용해서 구현할 수 있다.하노이의 탑하향식 계산 방식의 좋은 예시→ 재귀함수의 좋은 예시제약 조건한 번에 하나의 원반을 움직일 수 있다.가장 위에 있는 원반만 옮길 수 있다.아래에 작은 원반이 올 수 없다. Bubble Sort인접한 두 원소를 비교하여 두 원소의 위치를 교환한다.과정배열을 처음부터 끝까지 순회하며 인접한 두 원소를 비교한다.왼쪽 원소가 오른쪽 원소보다 크면 두 원소를 교환한다.이 과정을 배열이 정렬될 때까지 반복한다.시간 복잡도O(n^2)장점이해와 구현이 간단한다.단점성능이 좋지 않다.Selection Sort배열에서 최솟값을 찾아 맨 앞으로 이동시킨다.과정정렬되지 않은 부분에서 최솟값을 찾는다.찾은 최솟값을 정렬되지 않은 부분의 첫 번째 원소와 교환한다.정렬된 부분을 한 칸 늘리고, 정렬되지 않은 부분에서 위 과정을 반복한다.시간 복잡도O(n^2)장점이해와 구현이 간단하다.단점성능이 좋지 않다.참고 : https://visualgo.net/en/sortingCPU Scheduling AlgorithmSJF(Shortest Job First)Burst Time이 짧은 작업부터 CPU를 할당한다.문제점어떤 프로세스가 얼마나 실행될지 예측하기 힘들다.→ 예측하는 것이 거의 불가능하다.Burst Time이 긴 프로세스는 아주 오랫동안 실행되지 않을 수 있다.→ Burst Time이 긴 프로세스는 Burst Time이 짧은 프로세스에게 계속해서 우선순위가 밀린다.⇒ 사용되지 않는다.RR(Round Robin)하나의 프로세스에게 일정 시간만 CPU를 할당하고 할당된 시간이 지나면 강제로 다른 프로세스에게 일정시간만큼 CPU를 할당하는 방식→ 강제로 CPU를 뺏긴 프로세스는 Queue의 가장 마지막으로 밀려난다.Time Slice(=Time Quantum) : 프로세스에게 할당하는 일정 시간Time Slice에 따라서 RR의 성능이 좌지우지된다.Time Slice를 작게 만드는 경우 Context Switching이 빈번하게 발생된다.→ Context Switching이 빈번하게 발생함에 따라 성능이 떨어진다.Time Slice가 큰 경우 FIFO와 동일하게 동작한다.Time Slice 예시Window Time Slice : 20msUnix Time Slice : 100ms단점Context Switching이 존재한다.→ 평균 대기시간이 FIFO와 동일하다면 FIFO가 더 성능이 좋다.MLFQ(Multi Level Feedback Queue)RR의 업그레이드 버전주로 사용되는 CPU 스케줄링 알고리즘CPU Bound Process : CPU를 할당받은 시간을 대부분 CPU 연산을 수행하는 프로세스CPU 사용률과 처리량이 중요I/O Bound Process : 대부분의 시간을 I/O 작업에 수행하고 적은 시간만 CPU 연산을 하는 프로세스- 응답시간이 중요MLFQ는 기본적으로 CPU 사용률과 I/O 사용률이 좋게 나오는 작은 크기의 Time Slice를 사용한다.CPU Bound Process에게는 CPU 사용률을 높이기 위해 Time Slice를 높게 할당한다.I/O Bound Process에게는 I/O 사용률을 높이기 위해 Time Slice를 낮게 할당한다.OS는 어떻게 CPU Bound Process와 I/O Bound Process를 구분할까?CPU를 사용하는 프로세스가 실행하다가 스스로 CPU를 반납하는 경우 CPU 사용률이 낮음→ I/O Bound Process일 확률이 높음CPU를 사용하는 프로세스가 실행하다가 CPU 스케줄러에 의해 강제로 CPU를 뺏기는 상황인 경우 CPU 사용률이 높음→ CPU Bound Process일 확률이 높음구현 방법우선순위를 갖는 큐를 여러개 준비한다.우선순위가 높으면 Time Slice가 작다.우선순위가 낮아질수록 Time Slice가 커진다.Process간 통신하나의 컴퓨터 내에서 프로세스간 통신하는 방법Pipe운영체제가 생성한 파이프를 이용해 데이터를 읽고 쓰는 방법File통신을 하려는 프로세스들이 하나의 파일을 이용해 읽고 쓰는 방법Thread를 이용한 통신하나의 프로세스 내에서 쓰레드간 통신하는 방법쓰레드는 코드, 데이터, 힙 영역을 공유한다.(스택 영역만 별도로 갖는다.)데이터 영역의 전역 변수나 힙 영역을 이용하여 통신할 수 있다.NetworkOS가 제공하는 Socket 통신RPC(Remote Procedure Call)다른 컴퓨터의 함수를 호출하는 방법공유자원과 임계구역공유자원 : 프로세스간 통신을 할 때 공용으로 이용하는 변수나 파일여러 프로세스가 공유하기 때문에 각 프로세스의 접근 순서에 따라서 결과가 달라질 수 있다.컨텍스트 스위칭으로 시분할 처리를 하기 때문에 프로세스간의 실행 순서를 예측하기 어렵다.⇒ 동기화 문제가 발생할 수 있다.임계규역 : 여러 프로세스가 동시에 사용하면 안되는 영역상호배제 메커니즘을 통해 해결할 수 있다.경쟁조건 : 공유자원을 사용하기 위해 서로 경쟁하는 것상호배제 요구사항임계영역엔 동시에 하나의 프로세스만 접근한다.여러 요청에도 하나의 프로세스의 접근만 허용한다.임계구역에 들어간 프로세스는 빠르게 나와야한다.Semaphore상호배제 메커니즘의 한 종류Semaphore :  정수 값을 가지는 변수로, 공유 자원에 접근할 수 있는 프로세스/스레드의 수를 나타낸다.세마포어를 갖고 있는 프로세스가 실행되고 세마포어를 반납한다.기본 연산wait(S): 세마포어 값을 감소시킨다.값이 0이면 프로세스/스레드를 대기 상태로 만든다.signal(S): 세마포어 값을 증가시킵니다.대기 중인 프로세스/스레드가 있다면 깨운다.종류이진 세마포어: 0과 1 두 가지 값만 갖는다.(뮤텍스와 유사하게 사용한다.)카운팅 세마포어: 0 이상의 정수 값을 갖는다.(여러 자원을 관리할 때 사용된다.)장단점장점: 여러 프로세스/스레드 간의 복잡한 동기화 문제를 해결할 수 있다.단점잘못 사용하면 교착 상태나 기아 상태를 유발할 수 있다.ex) 세마포어를 획득하는 함수와 세마포어를 반납하는 함수의 위치 잘못 사용Mutex(MUTual EXclusion)뮤텍스는 이진 세마포어의 특수한 경우여러 스레드가 공유 자원에 동시에 접근하는 것을 방지하는 기술기본 연산Lock: 스레드가 임계 영역에 진입할 권한을 획득Unlock: 임계 영역 사용을 마치고 다른 스레드가 진입할 수 있게 한다.뮤텍스와의 차이세마포어는 여러 프로세스/스레드의 접근을 허용할 수 있지만, 뮤텍스는 하나의 프로세스/스레드만 접근을 허용한다.Monitor세마포어의 단점을 보완한 상호배제 메커니즘OS가 처리하는 것이 아니라 프로그래밍 언어단에서 지원하는 기능ex) Java : synchronized 키워드한 번에 하나의 프로세스/스레드만 실행할 수 있다.교착상태여러 프로세스가 서로 다른 프로세스의 작업이 끝나길 기다리다가 아무 작업도 수행되지 않는 상태발생 원인상호 배제 : 공유 자원은 한 번에 하나의 프로세스만 사용할 수 있다.비선점 : 다른 프로세스가 사용 중인 자원을 강제로 빼앗을 수 없다.점유와 대기 : 프로세스가 이미 자원을 보유한 상태에서 다른 자원을 요청하며 대기한다.원형 대기 : 점유와 대기를 하는 프로세스들의 관계가 원형이다.하나라도 충족하지 않으면 교착상태가 발생하지 않는다.→ 교착 상태를 예방하는 것을 구현하기는 매우 어려워서 교착 상태를 해결하는 방향으로 발전됐다.해결방법교착상태 회피프로세스들에게 자원을 할당할 대 어느 정도 자원을 할당해야 교착상태가 발생하는지 파악해서 교착상태가 발생하지 않는 수준의 자원을 할당한다.전체 자원의 수와 할당된 자원의 수를 기준으로 안정상태와 불안정 상태로 나뉜다.OS는 안정상태를 유지하려 한다.안전 상태: 모든 프로세스가 요구한 최대 자원을 할당받아 실행을 완료할 수 있는 상태불안정상태에 있더라도 무조건 교착상태에 들어가는 것이 아니라 교착상태에 빠질 확률이 높아지는 것이다.은행원 알고리즘작동 원리프로세스가 자원을 요청할 때, 그 요청이 시스템을 안전 상태로 유지할 수 있는지 확인한다.안전 상태를 유지할 수 있는 요청만 수락하고, 불안정한 상태를 초래할 수 있는 요청은 거절한다.주요 개념최대 요구량(Max Need): 프로세스가 실행을 완료하기 위해 필요한 최대 자원 양할당량(Allocation): 현재 프로세스에 할당된 자원 양필요량(Need): 최대 요구량에서 현재 할당량을 뺀 값가용량(= 시스템 총 자원, Available): 시스템에서 현재 사용 가능한 자원 양단점비용이 비싸고 비효율적이다.교착상태 검출가벼운 교착 상태 검출타이머를 이용하는 방식프로세스가 일정시간 동안 작업을 진행하지 않는다면 교착상태가 발생했다고 간주하고 교착상태를 해결한다.교착상태 해결 방법일정 시점마다 체크포인트를 만들어 작업을 저장하고 타임아웃으로 교착상태가 발생했다면 마지막으로 저장했던 체크포인트로 롤백한다.무거운 교착 상태 검출자원 할당 그래프를 이용하는 방식OS가 자원 할당 그래프를 유지하고 검사해야 하기 때문에 오버헤드가 발생한다.But. 가벼운 교착 상태 검출에서 발생할 수 있는 억울하게 종료되는 프로세스가 발생하지 않는다.OS에서 프로세스가 어떤 작업을 사용하는지 지켜보고 교착상태가 발생했다면 해결한다.Programming LanguageCompile Language개발자가 코드를 작성하고 컴파일을 수행하여 0과 1로된 기계어로 실행파일을 만든다.→ 기계어로 되어 있어 실행 속도가 인터프리터 언어에 비해 빠르다.컴파일 과정에서 개발자의 문법오류를 체크한다.ex) C, C++, C#Interpreter Language개발자가 작성한 코드를 미리 기계어로 만들어 놓지 않고 실행시 코드를 한줄씩 해석해 실행하는 언어→ 미리 검사를 하지 않기 때문에 실행할 때 오류가 발생할 수 있고, 컴파일 언어보다 느리다.ex) Javascript, Python, Ruby프로세스의 영역코드 영역실행해야 할 코드가 들어간다.데이터 영역전역 변수나 배열이 들어가는 영역스택 / 힙프로세스가 실행될 때 할당되는 메모리스택 : 지역변수와 함수 관련 값들이 저장힙 : 실행 중에 메모리 공간을 할당할 수 있는 유동적인 공간Compile 언어가 Process가 되는 방법개발자가 코드 작성전처리 단계 실행개발자가 작성한 코드를 확인하고 전처리 구문을 처리한다.C에서는 #이라는 키워드로 선언된다.ex) #include<stdio.h>, #define MY_NUMBER 100코드에 있는 모든 주석은 삭제된다.결과물로 .i 파일이 생성된다.전처리기에서 나온 결과파일을 컴파일러가 처리한다.컴파일러는 .i 파일을 기계어에 가까운 어셈블리어로 변환시킨다.결과물로 .s 파일이 생성된다.어셈블러 작업이 수행된다.오브젝트 파일.o로 변환된다.오브젝트 파일은 0과 1로 구성되어 있다.코드영역과 데이터 영역이 나뉘어져 있다.링커 작업이 수행된다.모든 오브젝트 파일을 하나의 코드 영역과 데이터 영역으로 묶어준다.실제로 실행될 주소를 매핑시켜준다.결과물로 .exe 파일이 생성된다.사용자가 .exe파일을 실행시키면 OS가 프로세스를 생성한다.OS는 파일에 있는 코드 영역과 데이터 영역을 가져와 프로세스의 코드 영역과 데이터 영역에 넣어주고, 빈 상태의 스택과 힙을 할당한다.PCB를 만들어 프로세스를 관리가 가능하게 한다.PC(프로그램 카운터)에 다음 실행할 명령어의 주소를 생성한 프로세스의 코드영역의 첫번째 주소로 설정한다.→ OS의 CPU 스케줄링에 따라서 프로세스가 실행되다가 작업을 마친다.메모리 종류레지스터가장 빠른 기억장소, CPU 내에 존재한다.휘발성 메모리CPU를 나타내는 값에서 32bit, 64bit를 의미하는 것이 레지스터의 크기이다.CPU는 계산을 수행할 때 메인 메모리에 있는 값을 레지스터로 가져와서 계산한다.계산 결과는 메인 메모리에 저장한다.캐시휘발성 메모리속도가 매우 빠른 레지스터와 레지스터에 비해 상대적으로 느린 메인 메모리 사이의 속도 간극을 메우기 위해 필요한 데이터를 미리 가져와 저장하는 저장소성능의 이유로 여러 개가 존재한다.L1, L2, L3→ 숫자가 커질 수록 느린 캐시CPU가 값을 요청해 레지스터로 값을 옮겨야 한다면 빠른 캐시를 순차적으로 확인하고, 캐시에 데이터가 없으면 메인 메모리를 조회한다.ex) L1 → L2 → L3 → 메인 메모리보조 저장장치(HDD, SSD)비휘발성 메모리메인 메모리실제 운영체제와 다른 프로세스들이 올라가는 공간휘발성 메모리데이터를 저장하기 보다는 실행중인 프로그램만 저장한다.OS는 메모리를 관리하기 위해서 1Byte 크기로 구역을 나누고 숫자(주소)를 매긴다.32bit CPU, 64bit CPU32bit CPU레지스터, ALU, Data Bus : 32bit메모리 : 2^32 = 4GB64bit CPU레지스터, ALU, Data Bus : 64bit메모리 : 2^64 = 16384PiB64bit CPU가 32bit CPU 보다 한번에 처리할 수 있는 양이 많기 때문에 속도가 더 빠르다.물리 주소 & 논리 주소물리 주소 공간 : 0x0부터 시작하는 주소 공간논리 주소 : 사용자 관점에서 바라 본 주소 공간사용자는 물리 주소를 몰라도 논리 주소로 물리 주소에 접근할 수 있다.OS를 위한 공간은 따로 확보한다.경계 레지스터H/W적으로 OS 공간과 사용자 공간을 나누는 레지스터CPU 내에 존재하는 레지스터메모리 관리자가 사용자 프로세스가 경계 레지스터의 값을 벗어났다면 검사하고, 벗어났다면 해당 프로세스를 종료시킨다.절대 주소 & 상대 주소개발자가 프로그램이 실행될 주소를 신경쓰지 않고 개발할 수 있는 이유→ 컴파일러가 컴파일을 할 때 메모리 0번지에서 실행한다고 가정하기 때문절대 주소 : 메모리 관리자가 바라본 프로세스가 올라간 물리 주소상대 주소 : 사용자가 바라보는 논리 주소재배치 레지스터프로그램의 시작 주소가 저장되어 있다.사용자가 요청한 논리 주소의 데이터를 물리 주소로 치환해준다.사용자가 메모리에 접근할 때마다 논리 주소를 물리 주소로 치환해준다.메모리 할당 방식메모리 오버레이메모리보다 용량이 큰 프로그램을 실행시키는 방법큰 프로그램을 메모리에 올릴 수 있을 정도로 분할하여 일부만 실행하고, 실행되지 않은 프로그램은 HDD의 스왑 영역에 저장하는 방식Swap스왑영역에 있는 데이터 일부를 메모리로 가져오고 메모리에 있는 데이터를 스왑영역으로 옮기는 것가변 분할 방식(= Segmentation, 세그멘테이션)프로세스의 크기에 따라 메모리를 나누는 방식하나의 프로세스가 메모리에 연속된 공간에 할당된다.→ 연속 메모리 할당이라고 한다.장점메모리에 연속된 공간에 할당된다.→ 내부 단편화가 없다.단점외부 단편화가 발생한다.고정 분할 방식(= Paging, 페이징)프로세스의 크기와는 상관없이 정해진 크기로 나누는 방식하나의 프로세스가 메모리에 분산되어 할단된다.→ 비연속 메모리 할당이라고 한다.장점구현이 간단하고 오버헤드가 적다.단점작은 프로세스도 큰 영역에 할당되어 내부 단편화가 발생한다.내부 단편화프로세스에 필요한 메모리보다 더 큰 고정 크기의 메모리 블록이 할당될 때 발생한다.할당된 메모리와 실제 사용된 메모리 사이의 차이로 인해 메모리 공간이 낭비된다.고정 크기 분할 방식에서 주로 발생한다.해결 방법은 딱히 없고, 분할되는 크기를 조절하여 내부 단편화를 최소화한다.외부 단편화메모리 할당과 해제를 반복하면서 작은 빈 공간들이 메모리 곳곳에 흩어져 생기는 현상전체 가용 메모리는 충분하지만, 연속된 큰 블록을 할당할 수 없는 상황을 만든다.가변 분할 방식에서 주로 발생한다.조각모음외부 단편화가 발생한 공간을 합쳐주는 작업현재 메모리에서 실행되고 있는 프로세스들의 작업을 일시 주징하고, 메모리 공간을 이동시켜야 한다.→ 오버헤드가 발생한다.버디 시스템가변 분할 방식 + 고정 분할 방식오늘날의 OS가 채택한 메모리 할당 방식2의 제곱으로 메모리를 분할하여 할당하는 방식→ 근접한 메모리 공간을 합치기 쉽다.→ 조각 모음보다 훨씬 간단하다.장점가변 분할 방식처럼 프로세스 크기에 따라 할당되는 메모리 크기가 달라지고, 외부 단편화를 방지하기 위해 메모리 공간을 확보하는 것이 간단하다.내부 단편화가 발생할 수 있지만 고정 분할 방식에 비해 많은 공간이 낭비되지는 않는다.Retrospect잘한 점매일매일 빠지지 않고 강의를 들은 점매일 들은 강의 내용을 요약/정리하고 그 주차의 내용들을 하나의 게시글로 정리한 것

알고리즘 · 자료구조워밍업클럽CS전공지식Week2

tenenger

인프런 워밍업 클럽 CS 2기 - 1주차 발자국

자료 구조 및 알고리즘 배열다른 프로그래밍 언어 vs 자바스크립트 특징다른 프로그래밍 언어의 경우는 배열의 크기를 정하고 연속적인 공간을 차지한다. 반면 자바스크립트 언어의 경우에는 배열의 크기를 정하지 않고 비연속적인 공간을 차지한다.다른 프로그래밍 언어의 배열은 배열의 크기를 늘릴경우 연속적인 공간을 새로 찾아서 기존의 내용을 복사붙여넣기 하기 때문에 성능이 좋지 않다. 반면 자바스크립트 언어의 경우에는 배열의 크기를 정하지 않기 때문에 비연속적인 공간에 값을 넣어 성능이 상대적으로 좋다.다른 프로그래밍 언어의 배열은 배열의 크기를 할당해야하기 때문에 불필요한 공간을 차지할 수 있다. 반면 자바스크립트 언어의 배열은 배열의 크기를 정하지 않고 동적으로 크기가 정해지기 때문에 불필요한 공간을 줄일 수 있다. 공통 특징배열의 시작주소 + 인덱스를 이용하여 참조를 하고, 참조의 경우 O(1) 의 성능을 보여준다. 🏷 자바스크립트 언어의 경우 비연속적인 공간을 차지하는데, 연결리스트로 노드가 연결되어 있어 인덱스로 접근할 수 있어 다른 프로그래밍언어에서 사용되는 배열과 유사하게 연속적인 공간을 차지하는 것 처럼 보여진다. 단방향 연결리스트특징연결리스트는 다른 노드를 가르키는 포인터가 있고, 하나의 노드가 다른 하나의 노드를 가르키며 서로 연결되어 있지 않아 단방향 연결리스트라고 불린다. 데이터 추가시, 인덱스의 위치에 따라 성능이 달라지는데 맨 앞에 데이터 추가시 O(1)의 성능을 가지는 반면, 맨 뒤에 데이터를 추가시 마지막 노드를 확인하고 추가해야하므로 O(n)의 성능을 가진다.데이터 삭제와 조회도 마찬가지이다. 연관된 자료구조스택 스택(Stack)특징First In Last Out (FILO) 방식이며, 가장 첫번째로 들어간 노드가 가장 마지막으로 나오는 순서를 따른다. 예시로 설거지를 한 접시를 탑을 쌓는다면 가장 위의 접시부터 빼는 것을 생각하면 이해가 쉽다. 구현단방향 연결리스트를 이용하여 위에서 부터 값을 넣는 push, 가장 위에서 제거하는 pop, 가장 위에 위치한 값을 확인하는 peek, 스택이 비어있는지 확인하는 isEmpty 메서드를 구현했다. 양방향 연결리스트특징양방향 연결리스트의 경우 하나의 노드가 다른 하나의 노드를 가리키고 있는데, 서로간에 참고하는 경우를 양방향에서 알 수 있다고 해서 양방향 연결리스트라고 한다. 연관된 자료구조큐, 덱, 셋 큐(Queue)특징First In First Out (FIFO) 방식이며, 가장 첫번째로 들어간 노드가 가장 첫번째로 나오는 순서를 따른다. 예시로 마트 계산대에서 가장 먼저 줄을 선 사람부터 계산을 진행하는 것을 생각하면 이해가 쉽다. 구현양방향 연결리스트를 이용하여 값을 넣는 enqueue, 값을 제거하는 dequeue, 가장 첫번째로 위치한 값을 확인하는 front, 큐가 비어있는지 확인하는 isEmpty 메서드를 구현했다. 데크(Deque)특징스택과 큐를 특징이 혼합된 자료구조로, 데이터를 첫번째와 마지막에 데이터를 추가, 삭제, 조회를 할 수 있다. 구현양방향 연결리스트를 이용하여 맨 앞의 값을 넣는 addFirst, 맨 앞의 값을 제거하는 removeFirst, 맨 뒤의 값을 넣는 addLast, 맨 뒤의 값을 제거하는 removeLast, 데크가 비어있는지 확인하는 isEmpty 메서드를 구현했다. 해시테이블특징해시 함수 + 테이블을 합친 개념으로 프로그래밍 언어마다 용어의 차이가 있다. 자바스크립트의 경우 해시 테이블이라고 한다.테이블을 배열로 만드는 방식의 경우 테이블의 키(숫자)를 인덱스로 하여 값을 저장했다. 이 방법은 사용되지 않는 인덱스의 경우 낭비되는 공간이기 때문에 메모리 낭비를 초래한다. 그래서 해시 함수를 사용하여 낭비되는 공간을 줄이는 방식이 해시 테이블이라고 한다.해시테이블의 경우 해시 함수에 따라 성능이 좋고 나쁨이 결정되기 때문에 좋은 해시 함수를 만드는 것이 가장 중요하다. 구현배열을 만들고, 양방향 연결리스트를 배열의 원소로 넣어 하나의 배열에 여러개의 양방향 연결리스트를 가진다. 연관된 자료구조셋 셋(Set)특징중복된 자료를 허용하지 않는다. 구현해시테이블을 이용하여 값을 넣는 add, 값을 제거하는 remove, 맨 뒤의 값을 넣는 addLast, 값을 초기화하는 clear, 저장된 값들을 출력하는 printAll, 셋이 비어있는지 확인하는 isEmpty 메서드를 구현했다. 미션1여러분은 교실의 학생 정보를 저장하고 열람할 수 있는 관리 프로그램을 개발하려고 합니다. 이 때 여러분이라면 학생의 정보를 저장하기 위한 자료구조를 어떤 걸 선택하실 건가요? 이유를 함께 적어주세요.배열 또는 해시테이블을 선택할 거 같습니다.만약 학생을 나누는 키 값이 연속적인 경우 배열을 선택해도 메모리 낭비 공간이 없겠지만, 만약 키값이 불연속적인 경우 배열로 저장할 경우 낭비되는 공간이 생길 수 있으므로, 해시 함수를 이용하여 낭비되는 메모리 공간을 줄이는 해시테이블을 사용합니다. 여러분은 고객의 주문을 받는 프로그램을 개발하려고 합니다. 주문은 들어온 순서대로 처리됩니다. 이 때 여러분이라면 어떤 자료구조를 선택하실 건가요? 이유를 함께 적어주세요.큐 자료구조를 선택할 거 같습니다.큐 자료구조의 특징이 첫번째 들어온 데이터가 가장 첫번째로 나가는 FiFO 방식이기 대문에 들어온 순서대로 처리하기에 적합한 자료구조입니다. 자료 구조 및 알고리즘 인터럽트입출력 장치의 데이터를 읽거나 쓰려고 할 때 기존의 폴링 방식의 단점을 해결하려고 나온 방식이다.기존의 폴링방식은 입출력 장치의 데이터를 지속적으로 확인해야하기 때문에 성능이 좋지 않았고, 인터럽트를 통해 입출력 장치가 CPU에게 신호를 주면 CPU는 그때 처리하는 방식이어서 성능상에 이점이 있다. 인터럽트입출력 장치의 데이터를 읽거나 쓰려고 할 때 기존의 폴링 방식의 단점을 해결하려고 나온 방식이다.기존의 폴링방식은 입출력 장치의 데이터를 지속적으로 확인해야하기 때문에 성능이 좋지 않았고, 인터럽트를 통해 입출력 장치가 CPU에게 신호를 주면 CPU는 그때 처리하는 방식이어서 성능상에 이점이 있다. 프로그램과 프로세스프로그램은 저장장치에 저장된 명령문의 집합체이다. 프로세스는 프로그램이 메모리에 적재되어 실행중인 상태, 즉 실행중인 프로그램을 뜻한다. 멀티프로그래밍과 멀티프로세싱유니프로그래밍은 메모리에 하나의 프로그램이 올라갔으며, 즉 하나의 프로세스가 있다.멀티프로그래밍은 메모리에 여러개의 프로그램이 올라갔으며, 즉 여러개의 프로세스가 있다.멀티프로세싱은 CPU가 여러개의 프로세스를 처리하는 것이다. PCB운영체제가 CPU가 프로세스를 효과적으로 관리하기 위해 PCB를 사용한다.PCB에는 프로세스에 대한 정보가 있어 시분할 시스템에서 CPU를 이용하여 여러개의 프로세스를 관리할 때 사용한다. 프로세스 상태시분할 시스템으로 여러 프로세스를 돌아가며 실행하여, 동시에 실행되는 것 처럼 보인다.생성 : PCB생성 후 메모리에 프로그램 적재 요청준비 : CPU에 의해 사용을 기다리고 있음, CPU 스케줄러에 의해 할당실행 : 준비 상태에 있는 프로세스가 CPU를 할당받아 실행되는 상태대기 : 프로세스가 입출력 요청을 하면 입출력이 완료까지 대기완료 : 프로세스 종료 및 PCB제거컨텍스트 스위칭프로세서를 실행 중에 다른 프로세스를 실행하기 위해 현재 프로세서의 상태 값을 저장하고, 다른 프로세스의 상태 값으로 교체하는 것을 뜻합니다.PCB의 프로세스 상태, 프로그램 카운터, 레지스터 정보, 메모리 관련 정보 등이 변경된다.프로세스 생성과 종료초기 컴퓨터 부팅 후 부모 프로세스가 생성된다.이후 모든 다른 프로세스는 부모 프로세스를 복사하여 생성되며, 이는 프로세스를 새로 생성하는 것보다 성능에 이점이 있다.내부의 코드는 자식 프로세스가 exec() 함수가 실행되면 덮어쓰게된다. 쓰레드하나의 프로세스에 하나 이상의 쓰레드가 존재한다.프로세스가 많아질 수록 PCB, 코드, 데이터, 스택, 힙 영역을 만들어 줘야하기 때문에 메모리를 많이 차지하는 이슈가 있었다. 그리고 브라우저의 탭들은 프로세스마다 통신을 하기 위해 IPC를 이용해야하는데 IPC의 비용이 많은 이슈가 있었다.쓰레드는 이러한 문제를 해소하기 위해 Code, data, heap을 공유하며, stack은 쓰레드마다 하나씩 가지고, IPC 비용을 줄일 수 있었다.쓰레드를 이용하면 IPC 비용을 줄일 수 있고 메모리 공간을 절약할 수 있다. 그러나 하나의 프로세스에 문제가 생기면 프로세스에 있는 쓰레드가 모두 문제가 생기는 단점이 있다. CPU 스케줄링프로세스를 실행하기 위해 CPU 스케줄링은 고려해야할 사항이 2가지 있다.어떤 프로세스에게 CPU를 할당할 것인가.어떤 프로세스에게 얼만큼의 CPU 할당 시간을 줄것인가. 다중큐준비 상태에 있는 프로세스는 실행 상태로 변환된다.준비 상태에 있는 프로세스의 PCB는 준비 상태의 다중 큐에 존재하며 CPU 스케줄러에 의해 실행이 결정된다.대기 상태에 있는 I/O 작업의 프로세스의 PCB가 대기 상태의 다중큐에 존재하며, CPU스케줄러에 의해 실행이 결정된다.스케줄링 목표리소스 사용률오버헤드 최소화공평성처리량대기시간응답시간FIFO스케줄링 큐에 들어온 순서대로 할당하며, 먼저 들어온 프로세스가 종료되어야 다음 프로세스가 실행된다.만약 Burst Time이 오래 걸리는 프로세스의 위치에 따라 평균 대기시간이 크게 차이가 난다.현대에서는 사용되지 않으나, 일괄처리시스템에서 주로 사용된다. 미션2 while(true){ wait(1); // 1초 멈춤 bool isActivated = checkSkillActivated(); // 체크 }위 코드는 1초 마다 플레이어가 스킬을 사용했는지 체크하는 코드입니다. 이 방식은 폴링방식입니다. 1초마다 체크하기 때문에 성능에 좋지 않습니다. 이를 해결하기 위한 방식으로 어떤 걸 이용해야 할까요?인터럽트 프로그램과 프로세스가 어떻게 다른가요? 프로그램은 저장장치에 저장된 명령문의 집합체입니다.프로세스는 메모리 상에 적재되어 실행중인 프로그램입니다. 멀티프로그래밍과 멀티프로세싱이 어떻게 다른가요? 멀티프로그래밍은 메모리 관점에서 메모리에 여러개의 프로세스가 존재하는 것을 뜻합니다.멀티프로세싱은 CPU 관점에서 여러개의 프로세스를 처리하는 것을 뜻합니다. 운영체제는 프로세스를 관리하기 위해서 어떤 것을 사용하나요?운영체제는 PCB를 사용하여 프로세서를 관리합니다.예를 들어 시분할 시스템으로 여러개의 프로세스를 번갈아가며 프로세스를 실행해야할 때, CPU에서 특정 프로세스 실행 후 레지스터를 해당 프로세서의 PCB에 저장하고 다른 프로세스의 PCB의 레지스터 정보를 불러와서 실행하는 것을 반복하여 마치 여러개의 프로세스가 동시에 실행되는 것처럼 관리할 수 있습니다. 컨텍스트 스위칭이란 뭔가요?프로세서를 실행 중에 다른 프로세스를 실행하기 위해 현재 프로세서의 상태 값을 저장하고, 다른 프로세스의 상태 값으로 교체하는 것을 뜻합니다. PCB의 프로세스 상태, 프로그램 카운터, 레지스터 정보, 메모리 관련 정보 등이 변경됩니다. 

알고리즘 · 자료구조인프런워밍업클럽CS2기

Taeho

인프런 워밍업 클럽 - CS Week 1

그림으로 쉽게 배우는 자료구조와 알고리즘(기본편)자료구조 & 알고리즘자료구조 : 데이터가 어떤 구조로 저장되고, 어떻게 사용되는지를 나타낸다.자료구조에 따라서 결과를 얻기 위한 처리 방법이 달라진다.알고리즘 : 어떤 문제를 해결하기 위한 확실한 방법시간 복잡도특정 알고리즘이 어떤 문제를 해결하는 데 걸리는 시간Bit-Ω : 최선의 시간 복잡도Big-O : 최악의 시간 복잡도가장 많이 사용된다.Big-θ : 평균의 시간 복잡도ADT(Abstract Data Type)데이터의 논리적인 동작을 정의한다.구현 방법을 명시하지 않고, 자료구조의 특성과 연산만을 설명한다.내부 구현 세부사항은 숨기고 인터페이스만을 제공한다.Array배열의 인덱스 참조는 길이에 상관없이 한 번에 가져온다.삽입, 삭제의 성능이 좋지 않다.Linked List배열의 단점인 삽입, 삭제의 성능을 보완하기 위한 자료구조특정 데이터를 찾고 싶다면 노드를 순차적으로 순회해야 한다.저장하려는 데이터들을 메모리에 분산하여 할당하고, 해당 데이터를 서로 연결한다.노드를 사용하여 데이터들을 저장하고, 각 노드가 다음 노드를 가리키도록 한다.첫 노드의 주소만 알고 있으면 그 이후의 모든 노드에 접근할 수 있다.StackLIFO(Last-in First-out)단방향 Linked List를 사용하여 구현할 수 있다.head를 사용하여 스택을 간단하게 구현할 수 있다.데이터 삽입을 무조건 첫 번째 인덱스에 수행한다.QueueFIFO(First-in First-out)양방향 Linked List를 사용하여 구현할 수 있다.Deque데이터의 삽입과 제거를 head와 tail에서 자유롭게 할 수 있는 자료구조Hash TableHash Function해시 함수는 키(key)를 입력받아 해당 키의 저장 위치(버킷 또는 인덱스)를 결정하는 계산을 하는 함수좋은 해시 함수 ⇒ 데이터를 골고루 분배시켜주는 함수 Hash Collision해시 충돌은 해시 함수가 서로 다른 두 개 이상의 입력 값에 대해 동일한 해시 값을 출력하는 상황을 의미Hash 충돌이 발생한 곳의 Value들을 연결리스트로 구성하여 데이터들을 연결한다.기존값과 새로운 값을 동시에 저장할 수 있다.찾고자 하는 Value가 나올 때까지 연결리스트를 탐색한다.→ O(n)의 성능을 갖는다.Set데이터의 중복을 허용하지 않는 자료구조HashTable을 사용하여 구현할 수 있다.→ HashTable을 사용하기 때문에 HashSet이라고도 한다.→ HashTable의 value 값은 사용하지 않고 key만 사용하여 구현한다.(key가 key와 value의 역할을 수행한다.)그림으로 쉽게 배우는 운영체제OS가 하는 일프로세스 관리 : 여러 개의 프로그램들을 동시에 수행할 수 있게 한다.메모리 관리 : 모든 프로그램은 메모리에 올라가서 동작한다.H/W 관리 : 사용자가 직접 H/W에 접근하는 것을 막는다.File System 관리Program저장장치에 저장된 명령문의 집합체저장 장치만 사용하는 수동적인 존재Process실행중인 프로그램저장장치에 저장된 프로그램이 메모리에 올라갔을 대 프로세스라고 한다.메모리, CPU, I/O 작업을 수행하는 능동적인 존재Multi-Programming메모리 관점메모리에 여러개의 프로세스가 올라온 상태Multi-ProcessingCPU 관점CPU가 여러 개의 프로세스를 처리하는 것을 의미PCB(Process Control Block)프로세스가 만들어지면 운영체제는 해당 프로세스의 정보를 갖고 있는 PCB를 만들고 저장한다.PCB들은 연결 리스트로 저장된다.운영체제는 프로세스가 종료되면 연결리스트에서 해당 프로세스의 PCB를 제거한다.Context Switching프로세스를 실행하는 중에 다른 프로세스를 실행하기 위해 실행중인 프로세스의 상태를 저장하고, 다른 프로세스의 상태값으로 전환하는 작업작업 과정에서 PCB의 내용(프로세스 상태, 프로그램 카운터, 레지스터 정보, 메모리 관련 정보 등)이 변경된다.Process의 생성OS가 부팅되고 0번 프로세스가 생성될 때 딱 한 번만 수행된다.→ 그 이후에 생성되는 프로세스는 fork()를 사용하여 복사해서 사용된다.→ 새로 생성하는 것보다 복사를 하는 것이 더 빠르기 때문좀비 프로세스부모 프로세스가 자식 프로세스보다 먼저 종료되거나 자식 프로세스가 비정상적으로 종료돼 exit()신호를 주지 못해서 Exit Status를 읽지 못해 메모리에 계속 살아있는 상태Thread프로세스 내에 존재하고, 1개 이상이 존재할 수 있다.하나의 프로세스 내에 있는 쓰레드들은 프로세스의 PCB, Code, Data, Heap 영역을 공유한다.Stack은 공유하지 않고, 쓰레드 마다 하나씩 갖고 있다.OS에서 작업을 처리하는 단위이다.Process vs Thread안정성Process는 독립적이기 때문에 서로 영향을 받지 않는다.Thread는 하나의 Process를 공유하기 때문에 하나의 Thread에 이상이 생기면 다른 Thread에도 이상이 전파될 수 있다.⇒ Process가 유리속도와 자원각각의 Process는 서로 고유한 자원을 갖는다.코드, 데이터, 힙, 스택 영역을 전부 따로 두고 있다.Process간에 통신을 하려면 IPC를 사용해야 해서 오버헤드가 크고 속도가 느리다.쓰레드는 하나의 Process의 자원을 스택 영역을 제외한 영역을 모두 공유하기 때문에 오버헤드가 느리다.CPU Scheduling목표목표들을 전부 만족할 수는 없다.→ 목표들에 따라 Trade-Off가 있기 때문ex) 처리량 ↑ ⇒ CPU 오래 할당, 응답시간 ↓ ⇒ 여러 프로세스에 CPU를 골고루 할당⇒ 처리량과 응답시간 사이에 Trade-Off가 발생한다.리소스 사용률CPU 사용률 높이기I/O 디바이스의 사용률 높이기오버헤드의 최소화Context Switching시에 발생하는 오버헤드를 최소화하는 것공평성모든 프로세스에게 우선순위에 따라 공평하게 CPU가 할당되어야 한다.처리량같은 시간내에 더 많은 처리를 할 수 있게 하는 것대기시간작업을 요청하고 실제 작업이 실행되기 전까지 대기하는 시간이 짧은 것응답시간사용자의 요청이 얼마나 빨리 요청하는지Retrospect아쉬운 점커리큘럼을 잘못 봐서 운영체제 쪽은 쉬는 날에 몰아서 들었다.커리큘럼을 명확하게 파악하고 당일에 들을 강의들을 정확히 정리해야겠다.잘한 점매일매일 빠지지 않고 강의를 들은 점매일 들은 강의 내용을 요약/정리하고 그 주차의 내용들을 하나의 게시글로 정리한 것

알고리즘 · 자료구조워밍업클럽CS전공지식Week1

강동훈

[인프런 워밍업 클럽 4기 - CS] - 3주차 발자국

📕 자료구조와 알고리즘(심화)✅ 트라이와 자동완성📌 개념자동완성 기능을 구현할 수 있는 최적의 자료구조retrieval에서 유래되었다.이진트리는 아니라 자식 노드의 개수 제한이 없음저장하려는 단어를 한 글자씩 저장해서 key엔 글자, value에는 자식 노드를 저장한다.📌 성능해시테이블 검색 시간 복잡도 = O(1)트라이 시간 복잡도 = O(k) - 트라이에 저장된 노드 수에 따라 다름✅ 그래프📌 개념트리는 그래프의 종류 중 하나이다. 트리는 그래프이지만 그래프는 트리가 아니다.트리노드는 부모와 자식으로 계층적 구조를 가지며그래프에서 사이클이 없어야 한다.연결되지 않는 노드가 있으면 안된다.용어정점: 노드간선: 노드를 연결하는 선인접(adjacent): 간선으로 연결된 정점이웃(neighbor): 인접한 정점a와 b는 인접해있으며 a는 b의 이웃이며 b는 a의 이웃이다.방향 그래프: 양방향으로 간선의 방향이 정해져있음무방향 그래프: 간선의 방향이 없음 📌 깊이 우선 탐색 알고리즘(DFS)방문한 정점을 해시 테이블에 저장한다.사이클이 있는 경우 무한 루프에 걸릴 수 있음1. 현재 정점을 해시테이블에 방문한 정점으로 저장2. 현재 정점의 인접 정점들을 순회 (방문한 정점이라면 순회하지 않는다)3. 방문하지 않은 정점이면 재귀적으로 깊이 우선 탐색 수행📌 너비 우선 탐색 알고리즘(BFS)1. 방문한 정점을 저장하고 큐에 삽입2. 큐에 dequeue3. dequeue한 인접 정점을 순회한다1. 이미 방문한 정점이라면 건너뛰고2. 방문하지 않은 경우 첫 번째 경우 반복📌 DFS vs BFSDFS는 깊이를 우선 탐색BFS는 너비를 우선 탐색상황에 맞게 적절하게 사용하는 것친구 추천을 제공: 너비 우선 탐색 사용특정 지인을 찾는 경우: 깊이 우선 탐색 사용성능그래프의 성능은 정점 뿐만 아니라 간선에 따라서도 달라질 수 있다.O(V + E)V: 정점E: 간선 ✅ 가중 그래프📌 개념간선의 크기를 저장한다.- 크기는 사용자가 정하기 나름(정점 간의 거리나 비용이 될 수 있음)간선은 방향도 있으며 방향에 따라 가중치가 달리질 수도 있음 📌 다익스트라 알고리즘최적의 경로를 찾을 때 최적의 알고리즘1. shorted_path_table에 목표 정점과 거리를 초기화2. visited와 unvisited 배열로 구분3. unvisited에서 차례로 visited로 이동하면서 표 업데이트1. 인접도시의 거리들을 shorted_path_table에 저장하고2. 가까운 거리의 정점을 선택하여 visited로 이동3. 표의 값 + 인접 도시 거리 > 표의 값이면 표 수정 X ✅ 알고리즘📌 탐욕 알고리즘최적해를 구하는데 사용되는 근사적인 방법최적해를 구하는 보장은 없지만 단순하게 구할 수 있음매 선택지에서 가장 좋은 선택을 고름조건1. 탐욕스러운 선택 속성1. 앞의 선택이 이후의 선택에 영향을 주지 않음2. 최적 부분 구조 조건1. 문제에 대한 최적해는 부분에 대해서도 최적해이다=> '매트로이드' 📌 최소 신장 트리신장 트리그래프에 순환 구조없이 모든 정점이 연결되어 있음최소 신장 트리: 간선의 길이가 가장 짧은 신장 트리1. 크루스칼 알고리즘2. 프림 알고리즘1. 다익스트라 알고리즘과 비슷2. 최소 비용으로 연결3. 무방향 그래프에서 동작 📌 최대 유량 문제(Network Flow)용량이 다른 여러 상수관을 통해 Source에서 Sink까지 최대한 많은 양의 물을 보내는 문제1. 용량(Capacity): 한 상수관에 최대한 흐를 수 있는 물의 양2. 유량(Flow): 현재 상수관에 흐르고 있는 물의 양3. 잔여 용량 = 용량 - 유량탐색 알고리즘1. 포드 폴커슨 알고리즘: DFS1. Source에서 Sink로 가는 경로 하나를 DFS로 찾는다. (증가경로 찾긴)2. 증가 경로에 흐를 수 있는 최대 유량을 찾는다3. 찾은 증가 경로에서 보낼 수 있는 최대 유량을 흘린다.2. 에드몬드 카프 알고리즘: BFS📕 컴퓨터 구조✅ 제어장치📌 명령어제어장치: RAM에 저장된 데이터를 가져와 정해진 동작을 수행하는 장치이다.명령어, 데이터 모두 제어장치에 저장되어 있음.상위 4비트 명령어, 하위 4비트 데이터(주소, 값)📌 프로그램 카운터RAM에서 메모리 주소를 이동시키거나 원하는 주소로 바로 접근할 수 있게 해주는 장치다음 실행한 명령어의 주소를 가리킨다.JK Flip-Flop을 통해 메모리 주소 1씩 카운팅혹은 JUMP를 통해 원하는 주소로 바로 이동 📌 스탭 카운터명령어 인출, 해석 및 실행 단계를 카운팅해주는 장치후기이번 주차에서는 그래프와 다양한 알고리즘에 대해서 배웠다. 매일 알고리즘 문제를 풀면서 개념은 알지 못하였지만 dfs나 bfs 혹은 그래프 문제를 해결하면서 접한 풀이과정에 대해 익혀가면서 단순히 재귀적인 문제의 심화 과정이라고 생각을 하였지만 이번 과정에서 해당 개념에 대해 깊이 있게 배울 수 있었고 간단한 풀이 예시와 함께 공부하다보니 더 쉽게 체감해볼 수 있었다. 컴퓨터 구조에서는 지금까지 배웠던 개념들을 토대로 본격적인 CPU 를 간단하게 제작해볼 수 있는 실습이 진행되었다. 개념적인 내용은 실습을 진행하면서 깊이 있게 다루지는 못하였지만 실제 동작되는 과정을 보면서 CPU의 명령과 연산 하나하나가 어떻게 동작하는 지 확인해볼 수 있었다. 점점 다양한 입력 핀들과 동작들을 혼합하여 제작하니 점점 구조가 복잡해지고 이해하는 것이 어려워지긴 하였지만 복습과 미션을 통해서 더 깊이 있게 이해해보려고 한다.

알고리즘 · 자료구조자료구조알고리즘컴퓨터구조

suover

인프런 워밍업 클럽 스터디 4기 - CS 전공지식 3주차 발자국

그림으로 쉽게 배우는 자료구조와 알고리즘 (심화편)만들면서 쉽게 배우는 컴퓨터 구조강의와 함께한 인프런 워밍업 클럽 스터디 4기 - CS 전공지식 (자료구조, 알고리즘, 컴퓨터구조)3주차 발자국 입니다.학습 내용 요약자료구조·알고리즘트라이(Trie)와 자동완성개념: 문자열 집합을 효율적으로 저장·탐색하기 위해, 각 노드가 문자 하나를 나타내며 공통 접두사를 공유하는 트리 구조입니다.학습: 삽입 및 탐색 로직의 흐름을 개념적으로 이해하였습니다.인사이트: 삽입·탐색이 문자열 길이에 비례하기 때문에, 대규모 단어 집합에서 접두사 검색이 빠르지만 메모리 사용이 커질 수 있음을 감안해야 함을 체감했습니다.그래프개념: 그래프는 정점과 간선으로 관계를 표현하는 자료구조로, 방향 여부나 가중치 유무에 따라 다르게 다루며 인접 리스트와 인접 행렬 방식으로 표현할 수 있습니다.학습: 간단한 예제 그래프를 구성해 보고, DFS는 재귀나 스택으로 깊이 우선 탐색하며 방문 체크로 순환을 막고, BFS는 큐로 레벨별 탐색해 비가중치 최단 경로에 유리함을 코드로 확인했습니다.인사이트: DFS는 깊이 탐색이 필요할 때, BFS는 단계별 탐색이 필요할 때 유용하며, 그래프 표현 방식도 데이터 크기와 목적에 맞춰 결정해야 한다는 점을 깨달았습니다.가중 그래프와 다익스트라 알고리즘개념: 가중치가 있는 그래프에서 시작 정점으로부터 다른 정점까지 최단 경로를 찾는 문제입니다.다익스트라 알고리즘원리: 현재까지 알려진 최단 거리 후보 정점을 선택해 인접 간선을 완화(relaxation)하며 거리 배열을 갱신합니다.인사이트: 그래프가 커질수록 일반 방식은 느려지고, 우선순위 큐(힙)를 쓰면 더 빠르게 최단 경로를 구할 수 있음을 느꼈습니다.컴퓨터 구조제어 장치 없는 컴퓨터 & 조립CPU 주요 구성 요소(CPU 레지스터, ALU, 프로그램 카운터, 스텝 카운터)를 복습하고, 실습을 통해 신호 흐름을 이해했습니다.CPU 만들기: 제어 장치(Control Unit)명령어 처리 흐름: 명령어 인출(fetch), 디코딩, 실행(execute) 단계의 제어 신호 타이밍을 확인했습니다.주요 명령어: NOP, LOADA, ADD, SUB, STOREA, LOADI, JMP/JMPC/JMPZ, OUT, HLT 등의 제어 신호와 ALU·레지스터·메모리 동작 방식을 이해했습니다. 제어 장치 조립: Logisim에서 각 단계별 신호를 조합해 제어 유닛을 완성하고, 시뮬레이션으로 신호 흐름과 분기 동작을 확인했습니다.미션🎯 자료구조·알고리즘 미션3: 허프만 코딩 구현목표주어진 문자열에 대해 HuffmanCoding.compress(str)를 호출했을 때, [ [문자, 코드], … ]형태의 배열을 출력하도록 허프만 코딩을 구현합니다.class Node { constructor(char = null, freq = 0, left = null, right = null) { this.char = char; this.freq = freq; this.left = left; this.right = right; } } class HuffmanCoding { compress(str) { if (!str) return []; // 빈도 계산 const freqMap = new Map(); for (const ch of str) { freqMap.set(ch, (freqMap.get(ch) || 0) + 1); } // 초기 노드 리스트 생성 const nodes = []; for (const [ch, f] of freqMap.entries()) { nodes.push(new Node(ch, f)); } // 허프만 트리 구성 while (nodes.length > 1) { nodes.sort((a, b) => a.freq - b.freq); const a = nodes.shift(); const b = nodes.shift(); nodes.push(new Node(null, a.freq + b.freq, a, b)); } const root = nodes[0]; // 코드 생성 const codes = {}; const build = (node, prefix) => { if (node.char !== null) { codes[node.char] = prefix || "0"; } else { build(node.left, prefix + "0"); build(node.right, prefix + "1"); } }; build(root, ""); // [문자, 코드] 쌍 배열 반환 return Object.entries(codes); } } const huffmanCoding = new HuffmanCoding(); const str = "Lorem ipsum dolor sit amet consectetur adipiscing elit. " + "Consectetur adipiscing elit quisque faucibus ex sapien vitae. " + "Ex sapien vitae pellentesque sem placerat in id. " + "Placerat in id cursus mi pretium tellus duis. " + "Pretium tellus duis convallis tempus leo eu aenean."; const result = huffmanCoding.compress(str); console.log(result);흐름 및 구현 요약빈도 계산문자열을 순회해 Map 또는 객체에 문자별 등장 빈도를 집계했습니다.코드 생성재귀 탐색으로 왼쪽 자식은 '0', 오른쪽 자식은 '1'을 prefix에 추가하며 리프에서 코드 할당. 단일 문자 입력 시 빈 prefix에 "0" 처리 로직도 반영했습니다.검증실행 결과에서 빈도가 높은 문자는 짧은 코드, 낮은 문자는 긴 코드가 할당되는지 확인했습니다.빈도와 코드 길이 관계가 적절한지, 모든 문자가 포함되었는지, 코드끼리 충돌이 없는지 점검했습니다. // 결과 [ [ 'i', '000' ], [ 'q', '001000' ], [ 'v', '001001' ], [ 'o', '00101' ], [ 'l', '0011' ], [ 'd', '01000' ], [ 'E', '0100100' ], [ 'g', '0100101' ], [ 'x', '0100110' ], [ 'P', '0100111' ], [ 'a', '0101' ], [ 'e', '011' ], [ 'm', '10000' ], [ 'r', '10001' ], [ 'u', '1001' ], [ 't', '1010' ], [ 'p', '10110' ], [ 'L', '10111000' ], [ 'C', '10111001' ], [ 'f', '10111010' ], [ 'b', '10111011' ], [ '.', '101111' ], [ ' ', '110' ], [ 's', '1110' ], [ 'c', '11110' ], [ 'n', '11111' ] ]느낀 점허프만 코딩의 "빈도 기반 병합 → 트리 구조 → 코드 생성" 흐름을 직접 구현하며 원리 습득이 명확해졌습니다. 결과 검증 과정에서 빈도와 코드 길이 관계, 프리픽스 성질 확인 등이 중요함을 체득했습니다. 🔗 자료구조·알고리즘 미션3 블로그 링크🎯 컴퓨터 구조 미션3: STOREB 명령어와 A·B 비교 어셈블리어 구현목표STOREB 명령어(OPcode 1001)를 추가해 레지스터 B의 값을 메모리 주소에 저장하도록 구현합니다.A와 B 값을 비교해 같으면 0, A>B면 1, A<B면 2를 출력 레지스터에 내보내는 어셈블리어를 작성하고 검증합니다.구현STOREB(1001) 명령어 추가기존 STOREA 처리 경로를 참고하여 opcode 1001 분기 로직을 제어 장치에 추가했습니다.스텝 카운터가 각 단계에 진입할 때, STOREB 신호와 연관된 핀들이 의도한 타이밍에 활성화되는지 확인했습니다.A·B 비교 어셈블리어메모리에 저장된 A와 B 값을 불러와 비교하는 순서LOADA addrA → SUB addrB (A = A - B, 플래그 설정)JMPC 분기로 A≥B 처리, 아닐 경우 LOADI 2로 A<B 결과 세팅 후 출력분기한 경우 ZF 검사: ZF=1일 때 A=B(LOADI 0), ZF=0일 때 A>B(LOADI 1)이후 OUT, HLT로 마무리주소 라벨 매핑과 분기 주소 계산을 꼼꼼히 검토했습니다.Logisim에서 다양한 A·B 조합 테스트를 통해 출력 레지스터가 기대값(0/1/2)을 잘 내보내는지 확인했습니다.LOADA 14 // A = RAM[14] SUB 15 // A -= RAM[15] JMPC 5 // CF = 1 → A ≥ B일 때 5번 주소로 점프 LOADI 2 // A < B → 결과 2 JMP 9 // 결과 출력으로 점프 JMPZ 8 // ZF = 1 → A = B일 때 8번 주소로 점프 LOADI 1 // A > B → 결과 1 JMP 9 // 결과 출력으로 점프 LOADI 0 // A = B → 결과 0 OUT // 결과 출력 HLT // 프로그램 종료 0 0 0 7 // A값 3 // B값느낀 점제어 장치에 새로운 명령어를 추가할 때, 기존 신호 경로와 타이밍 흐름을 정확히 이해해야 오류를 줄일 수 있음을 확인했습니다.분기 주소 계산이 미흡하면 예상치 못한 동작이 발생하므로, 어셈블리어 작성 시 라벨 관리가 중요함을 체감했습니다. 🔗 컴퓨터 구조 미션3 블로그 링크회고잘한 점단계적 접근: 컴퓨터 구조와 알고리즘 미션을 작은 단위로 나눠 핵심 로직과 흐름을 차근차근 구현하고 검증했습니다.디버깅 습관 강화: Logisim 시뮬레이션과 코드 실행 결과를 반복 확인하며, 문제 발생 시 신호 흐름이나 분기 주소 동작을 빠르게 점검했습니다.이론·실습 병행: 트라이, 그래프, 다익스트라 개념 학습 뒤 직접 구현 연습, 제어 유닛 명령어 설계 뒤 Logisim 실습, 허프만 코딩 이론 뒤 코드 작성으로 이론과 실습을 잘 연결했습니다. 아쉬웠던 점 & 보완테스트 부족 : 테스트가 부족해 다양한 상황을 확인하지 못했습니다. 다음에는 다양한 입력과 경계값을 더 많이 시도해 보겠습니다.성능 최적화 부족: 성능 최적화 연습이 부족했습니다. 시간이 된다면 구현했던 자료구조와 알고리즘을 재작성해보고, 다양한 시도를 통해 실행 시간을 비교해 보겠습니다. 마치며이번 주차에는 Trie, 그래프, 다익스트라 학습을 진행하고, 제어 장치 명령어 확장과 허프만 코딩 구현 미션을 병행하며 이론과 실습을 모두 경험했습니다. 단계별 실습을 통해 개념이 실제 코드나 회로로 연결되는 과정을 체감했고, 디버깅과 테스트 습관을 강화할 수 있었습니다. 다음주에는 추가 알고리즘 학습을 통해 더욱 탄탄한 이해를 쌓아가겠습니다. 감사합니다!

알고리즘 · 자료구조인프런워밍업클럽스터디CS전공지식자료구조컴퓨터구조발자국회고4기

suover

인프런 워밍업 클럽 스터디 4기 - CS 전공지식 2주차 발자국

그림으로 쉽게 배우는 자료구조와 알고리즘 (심화편)만들면서 쉽게 배우는 컴퓨터 구조강의와 함께한 인프런 워밍업 클럽 스터디 4기 - CS 전공지식 (자료구조, 알고리즘, 컴퓨터구조)2주차 발자국 입니다.학습 내용 요약그림으로 쉽게 배우는 자료구조와 알고리즘 (심화편)이번 주에는 균형 이진 탐색 트리의 대표 주자인 Red-Black 트리의 삽입·삭제 개념과 실제 구현을 다뤘습니다.개념(삽입/제거) 단계에서 색상 규칙과 회전을 통해 균형을 유지하는 원리를 학습했고보조 함수(색 변경, 회전 함수), 삽입 로직, 삭제 로직을 차례로 완성하며, 각 단계마다 균형 인자가 올바르게 갱신되는지 확인했습니다.이어 우선순위 큐와 힙을 학습했습니다.힙(Heap) 의 개념과 완전 이진 트리 구조를 이해하고, 힙 삽입, 힙 제거 과정을 직접 구현해 보았습니다.이를 기반으로 미션에서 CpuScheduler 를 만들어, 실행 횟수 우선 & I/O 바운드 우선 정책을 Heap 비교 함수를 수정해 적용했으며마지막으로 힙 정렬(Heapsort) 알고리즘까지 학습했습니다.만들면서 쉽게 배우는 컴퓨터 구조지난주 불 대수·진리표·Logisim 기초를 다진 뒤, 이번 주에는MUX: 1비트 2입력부터 8비트 16입력까지 다양한 MUX 설계디코더: 3비트·4비트 디코더 설계컨트롤 버퍼(Buffer) 이해ALU: 반 가산기·전 가산기·ALU 제작메모리: SR/D/JK 래치, 플립플롭, 레지스터, RAM 구현까지 확장하며, 각 모듈을 직접 구현하고 테스트하며 신호 흐름을 검증했습니다.미션🎯 미션1. 자료구조와 알고리즘 미션: CPU 스케줄링목표프로세스의 executionCount(실행 횟수)와 cpuReturnCount(I/O 바운드 횟수)로 우선순위를 매기는 스케줄러 구현실행 횟수(executionCount)가 가장 작은 프로세스가 우선순위가 높다.실행 횟수가 같을 경우, I/O Bound 프로세스(cpuReturnCount가 큰 프로세스) 가 우선순위가 높다.구현 개요자료구조: 완전 이진 트리 기반의 Heap 활용비교 함수 재정의// CpuScheduler 생성자 내부 this.heap.isBigPriority = (first, second) => { if (first.executionCount !== second.executionCount) { // 실행 횟수가 적은 프로세스가 우선 return first.executionCount < second.executionCount; } // 실행 횟수가 같다면 I/O Bound 정도(cpuReturnCount)가 큰 쪽이 우선 return first.cpuReturnCount > second.cpuReturnCount; }; CpuScheduler 클래스import { Heap } from "../../heap/heap.mjs"; class Process { constructor(name, cpuReturnCount, executionCount) { this.name = name; this.cpuReturnCount = cpuReturnCount; this.executionCount = executionCount; } } class CpuScheduler { constructor() { this.heap = new Heap(); this.heap.isBigPriority = (first, second) => { if (first.executionCount !== second.executionCount) { return first.executionCount < second.executionCount; } return first.cpuReturnCount > second.cpuReturnCount; }; } enqueue(process) { this.heap.insert(process); } dequeue() { const node = this.heap.remove(); return node ? node.getData() : null; } } let cpuScheduler = new CpuScheduler(); cpuScheduler.enqueue(new Process("수치계산프로그램", 4, 0)); // cpu반납 4회, 실행횟수 0회 cpuScheduler.enqueue(new Process("뮤직플레이어", 11, 10)); // cpu반납 11회, 실행횟수 10회 cpuScheduler.enqueue(new Process("웹브라우저", 27, 25)); // cpu반납 27회, 실행횟수 25 cpuScheduler.enqueue(new Process("터미널1", 34, 2)); // cpu반납 34회, 실행횟수 2회 cpuScheduler.enqueue(new Process("터미널2", 93, 2)); // cpu반납 93회, 실행횟수 2회 console.log(cpuScheduler.dequeue()); // 수치계산프로그램 프로세스 출력 console.log(cpuScheduler.dequeue()); // 터미널2 프로세스 출력 console.log(cpuScheduler.dequeue()); // 터미널1 프로세스 출력 console.log(cpuScheduler.dequeue()); // 뮤직플레이어 프로세스 출력 console.log(cpuScheduler.dequeue()); // 웹브라우저 프로세스 출력테스트 결과Process { name: '수치계산프로그램', cpuReturnCount: 4, executionCount: 0 } Process { name: '터미널2', cpuReturnCount: 93, executionCount: 2 } Process { name: '터미널1', cpuReturnCount: 34, executionCount: 2 } Process { name: '뮤직플레이어', cpuReturnCount: 11, executionCount: 10 } Process { name: '웹브라우저', cpuReturnCount: 27, executionCount: 25 }O(log N) 삽입·삭제 성능으로 대규모 프로세스 관리 가능비교 함수만 바꿔 다양한 스케줄링 정책 가능🔗 자료구조·알고리즘 미션2 블로그 링크🎯 미션2. 컴퓨터 구조 미션: 터널 연결부터 32바이트 RAM까지미션 구성모든 회로 연결을 터널(Tunnel)로 대체8비트 32입력 MUX 제작10비트 입력 두 개(A, B)를 계산하는 ALU 설계32바이트 RAM 구현1) 모든 회로 연결을 터널(Tunnel)로 대체목표: Logisim의 Tunnel 컴포넌트를 사용해 복잡한 선 숨기기결과: 캔버스가 한눈에 들어오고, 라벨만으로 신호 흐름 파악 가능2) 8비트 32입력 MUX 제작목표: IN_0…IN_31 중 하나 선택하여 출력구현: Logisim 내장 32-to-1 MUX + 8비트 버스검증: SELECTION 값 변화 시 기대 출력 확인3) 10비트 입력 두 개(A, B)를 계산하는 ALU 설계목표: 덧셈(SU=0)/뺄셈(SU=1), Carry-in/Carry-out, Zero Flag구현:10개 Full Adder 체인B 입력 XOR + SU → 뺄셈 지원마지막 Adder의 Carry-out → CF, 출력 전 비트 OR·NOT → ZF검증: 다양한 A, B 조합 테스트, CF/ZF 정상 동작4) 32바이트 RAM 구현목표: 5비트 주소 + 8비트 데이터 입·출력, ENABLE_WRITE, ENABLE_OUT구현:5→32 디코더 + AND → 각 레지스터 Load읽기 MUX로 선택 출력검증: WRITE=1 시 해당 워드에 저장, OUT=1 시 올바른 데이터 읽기 🔗 컴퓨터 구조 미션2 블로그 링크회고잘한 점단계적 학습Red-Black 트리 개념 → 보조 함수 → 삽입 → 삭제까지 차근차근 구현하며 균형 유지 원리를 확실히 체득했습니다.힙 기반 스케줄러와 힙 정렬, 다양한 크기의 MUX·디코더 구현으로 자료구조·회로 설계 감각을 크게 확장했어요.모듈화 & 재사용성Heap 비교 함수만 바꿔 다양한 스케줄링 정책을 손쉽게 실험했고, Logisim 터널·버퍼 적용으로 회로 블록을 깔끔하게 재사용할 수 있었습니다.플래그·메모리 회로 반복 학습반·전 가산기, Zero/Carry Flag, 래치·플립플롭, 레지스터 파일, RAM까지 차례로 구현하며 신호 흐름과 제어 신호 이해가 깊어졌습니다.아쉬웠던 점 & 보완테스트 케이스 부족Red-Black 트리 삭제의 예외 케이스를 더 다양하게 검증하지 못했습니다.힙 스케줄러에도 executionCount·cpuReturnCount 동률 시나리오를 추가할 필요가 있습니다.시간 관리다양한 모듈 구현에 몰두하느라 후반부 학습이 빠듯했습니다. 마치며이번 주차에도 "작게 쪼개고 하나씩 검증하는" 학습 방식을 통해, 알고리즘과 회로 설계 모두에서 자신감을 많이 얻었습니다.다음 주에는 부족했던 것들을 보완해, 더 탄탄한 결과물을 만들어 보겠습니다. 감사합니다!

알고리즘 · 자료구조인프런워밍업클럽스터디CS전공지식자료구조컴퓨터구조발자국회고4기

강동훈

[인프런 워밍업 클럽 4기 - CS] - 2주차 미션 (자료구조와 알고리즘 심화)

문제여러분은 간단한 운영체제를 개발하고 있습니다. 운영체제의 CPU 스케줄링을 구현해야 하는 차례입니다. 여러 프로세스들이 골고루 실행되도록 하기 위해, 프로세스 실행 횟수(executionCount)가 작은 프로세스의 우선순위를 높게 설정하는 CPU 스케줄링 정책을 만들려고 합니다. 또한, 모든 프로세스가 비슷하게 실행될 때는 사용자의 반응성을 높이기 위해 I/O Bound 프로세스들의 처리를 우선적으로 하려고 합니다. I/O Bound 프로세스는 CPU를 사용하다가 자발적으로 CPU를 반납(cpuReturnCount)하는 것으로 판단할 수 있습니다. 따라서 다음 두 가지 조건으로 CPU 스케줄러를 구현해 보세요:프로세스 실행 횟수가 가장 적은 프로세스가 우선순위가 높습니다.실행 횟수가 같을 경우, I/O Bound 프로세스가 우선순위가 높습니다.class Process{ constructor(name, cpuReturnCount, executionCount){ } } let cpuScheduler = new CpuScheduler(); cpuScheduler.enqueue(new Process("수치계산프로그램", 4, 0)); // cpu반납 4회, 실행횟수 0회 cpuScheduler.enqueue(new Process("뮤직플레이어", 11, 10)); // cpu반납 11회, 실행횟수 10회 cpuScheduler.enqueue(new Process("웹브라우저", 27, 25)); // cpu반납 27회, 실행횟수 25 cpuScheduler.enqueue(new Process("터미널1", 34, 2)); // cpu반납 34회, 실행횟수 2회 cpuScheduler.enqueue(new Process("터미널2", 93, 2)); // cpu반납 93회, 실행횟수 2회 console.log(cpuScheduler.dequeue()); // 수치계산프로그램 프로세스 출력 console.log(cpuScheduler.dequeue()); // 터미널2 프로세스 출력 console.log(cpuScheduler.dequeue()); // 터미널1 프로세스 출력 console.log(cpuScheduler.dequeue()); // 뮤직플레이어 프로세스 출력 console.log(cpuScheduler.dequeue()); // 웹브라우저 프로세스 출력 풀이풀이 1Process 클래스와 생성자에 필요한 property들을 설정해주었다.PriorityQueue에 Heap 메서드인 isBigPriority를 오버라이드하여 필요한 함수로 작성해주었다.조건문을 통해 executionCount가 적은 프로세스 먼저 실행시키고(오름차순) 만약 executionCount가 동일하다면 cpuReturnCount가 높은 값부터 호출한다(내림차순)//mission.mjs import { PriorityQueue as CpuScheduler } from "./priorityQueue.mjs"; class Process { constructor(name, cpuReturnCount, executionCount) { this.name = name; this.cpuReturnCount = cpuReturnCount; this.executionCount = executionCount; } }//priorityQueue.mjs import { Heap } from "./heap.mjs"; export class PriorityQueue { constructor() { this.heap = new Heap(); // 첫 번째 우선순위, 두 번째 우선순위 비교 this.heap.isBigPriority = (first, second) => { if (first.executionCount === second.executionCount) { return first.cpuReturnCount > second.cpuReturnCount; } return first.executionCount < second.executionCount; }; } enqueue(data) { return this.heap.insert(data); } dequeue(data) { return this.heap.remove(data); } }하지만 상위 문제 풀이에는 두 가지 문제점이 있다.첫 번째는 우선 순위의 추가가 불편하다는 점이다. 문제에서는 두 개의 우선순위만 주어졌기에 함수에 isBigPriority 함수에 조건문을 통해 작성하였지만 10개, 100개로 늘어갈 수록 함수의 조건문은 점점 길어져갈 것이다.두 번째는 우선순위의 변경이 불편하다는 점이다. 만약 문제와 반대로 executionCount와 cpuReturnCount의 우선순위가 바뀐다면 함수에서 조건문 전체를 변경해줘야 한다. 두 개의 우선순위를 변경하는 것도 귀찮은 일인데 만약 이 또한 100개가 되는 우선순위 순서를 변경해야한다면 오랜 시간이 걸릴 것이다. 풀이 2Process에서 첫 번째 우선순위 priority를 executionCount로 설정하고, 두 번째 우선순위 secondPriority를 cpuReturnCount를 선언하였다.PriorityQueue에서 Heap 클래스의 isBigPriority를 오버라이드하여 새로운 우선순위 함수로 정의해주었다.첫 번째 우선순위는 오름차순으로 설정하고 조건문을 통해 첫 우선순위가 동일할 경우, 두 번째 우선순위로 비교하여 내림차순으로 설정하였다.//mission.mjs import { PriorityQueue as CpuScheduler } from "./priorityQueue.mjs"; class Process { constructor(name, cpuReturnCount, executionCount) { this.name = name; this.cpuReturnCount = cpuReturnCount; this.executionCount = executionCount; // 첫 번째 우선순위 this.priority = executionCount; // 두 번째 우선순위 this.secondPriority = cpuReturnCount; } }//priorityQueue.mjs import { Heap } from "./heap.mjs"; export class PriorityQueue { constructor() { this.heap = new Heap(); // 1. 첫 번째 우선순위 오름차순 // 2. 두 번째 우선순위 내림차순 this.heap.isBigPriority = (first, second) => { if (first.priority === second.priority) { return first.secondPriority > second.secondPriority; } return first.priority < second.priority; }; } enqueue(data) { return this.heap.insert(data); } dequeue(data) { return this.heap.remove(data); } }상위 풀이는 풀이 1의 두 번째 문제를 해결하였다. 각 우선순위의 대상이 되는 변수를 함수에 직접 구현한 것이 아닌 priority, secondPriority와 같이 우선 순위를 담는 변수를 따로 선언하여 함수에 구현하였기 때문에, 우선순위를 변경하려면 간단히 Process 클래스에서 property만 변경해주면 된다는 이점이 있다. 하지만 풀이 1의 첫 번째 문제는 아직 해결되지 못하였다. 여전히 priority가 10개, 100개로 늘어난다면 Process에 선언해야 할 property가 그만큼 늘어나게 될 것이다. 풀이 3우선순위 큐를 선언하기 전, Priority를 결정하는 rules 배열을 선언해주었다. rules에는 우선순위로 활용할 process 인스턴스의 property와 오름차순, 내림차순을 결정할 type으로 형성된 객체를 배열로 받는다.이 후, 우선순위 큐를 생성하면서 rules를 매개변수로 생성자에 넘겨주고 isBigPriority에서는 전달받은 각각의 rule들을 비교해가며 해당 property을 비교하여 type에 따라 정렬하게 된다.isBigPriority에서는 for 반복문을 돌다가 정렬할 수 있는 상태(값이 동일하지 않은 상태)에는 return을 통해 첫 번째 우선순위만 비교하여 정렬을 하고, 만약 첫 번째 우선순위에서 정렬을 할 수 없다면 다음 rule로 넘어가 비교를 하게된다.// mission.mjs import { PriorityQueue as CpuScheduler } from "./priorityQueue.mjs"; const rules = [ { property: "executionCount", type: "ASC" }, { property: "cpuReturnCount", type: "DESC" }, ]; class Process { constructor(name, cpuReturnCount, executionCount) { this.name = name; this.cpuReturnCount = cpuReturnCount; this.executionCount = executionCount; } } let cpuScheduler = new CpuScheduler(rules);//priorityQueue.mjs import { Heap } from "./heap.mjs"; export class PriorityQueue { constructor(rules) { this.heap = new Heap(); this.rules = rules; this.heap.isBigPriority = (first, second) => { for (const rule of this.rules) { const { property, type } = rule; if (type === "ASC") { if (first[property] < second[property]) return true; if (first[property] > second[property]) return false; } else { if (first[property] > second[property]) return true; if (first[property] < second[property]) return false; } } return false; }; } enqueue(data) { return this.heap.insert(data); } dequeue(data) { return this.heap.remove(data); } }미리 rules라는 배열을 선언하여 해당 변수 안에서 우선순위를 선택할 property와 type을 관리해주면 Process 나 PriorityQueue에서는 우선 순위의 변경이 발생하여도 수정을 할 필요가 없어진다. 현재는 rules를 직접 하드코딩하여 관리해주고 있는데 에러처리나 동적으로 삽입해줄 수 있는 메서드를 활용해봐도 좋을 것 같다. 회고수강하면서 heap과 우선 순위큐를 직접 구현하고 이론을 설명들을 때는 이해가 되지 않는 부분이 많았는데, 이번 미션을 통해서 직접 어떤 상황에서 사용될 수 있는지 이해할 수 있었고 간접적으로 CPU의 우선순위를 구현해보면서 해당 자료구조의 이점을 몸소 체험할 수 있었다. 또한 문제를 풀면서 각각 내가 구현한 방식과 그에 대한 단점들을 발견하면서 이를 개선시키는 과정이 인상깊었던 것 같다.

알고리즘 · 자료구조알고리즘자료구조

avraskio

[워밍업클럽4기-CS] 1주차 미션

컴퓨터 구조4입력 AND, OR, NAND, NOR, XOR 연산의 진리표를 작성해보세요.입력 4개 AND입력 4개 OR입력 4개 NAND입력 4개 NOR입력 4개 XOR다음 불 방정식들을 여러 방법을 이용해 간략화 해보세요.A( (BB)’+ 0A) + (CC)' = A(B’ + 0) + C’ = AB’ + A0 + C’ = AB’ + C’(B’B’) + (AD’ + (CA)’)D = B’ + (AD’ + C’ + A’)D = B’ + C’D + A’D(A’B) + B(B1 + BC) = A’B +B(B(1+C)) = A’B + B = (A’+1)B = BB’(1C + BD) + DB = B’C + B’BD + DB = B’C +DB다음 2진수를 10진수로 변환해보세요.110111 = 32 + 16 + 4 + 2 + 1 = 5510000001 = 128 + 1 = 12911111100000 = 1024 + 512 +256 +128 +64 +32 = 2016101010 = 32 + 8 +2 = 42다음 10진수를 2진수로 변환해보세요.10 = 8 + 2 = 101027 = 16 +8 +2 +1 = 1101186 = 64 +16 + 4 + 2 = 1010110516 = 512 + 4 = 1000000100다음 불 방정식을 logisim을 이용해 회로를 만들어보세요.(회로 이미지와 .circ파일 첨부)(B’C) + (DB)(AB’) +CB’ + (DC’) + (DA’)자료구조와 알고리즘public class BinaryTree<T> { private T data; private BinaryTree<T> leftTree; private BinaryTree<T> rightTree; private int height; public BinaryTree(T data) { this.data = data; this.leftTree = null; this.rightTree = null; this.height = 1; } public T getData() { return this.data; } public void setData(T data) { this.data = data; } public int getHeight() { return this.height; } public void setHeight(int height) { this.height = height; } public BinaryTree<T> getLeftSubTree() { return this.leftTree; } public void setLeftSubTree(BinaryTree<T> leftTree) { this.leftTree = leftTree; } public BinaryTree<T> getRightSubTree() { return this.rightTree; } public void setRightSubTree(BinaryTree<T> rightTree) { this.rightTree = rightTree; } public BinaryTree<T> removeLeftSubTree() { BinaryTree<T> deletingNode = this.leftTree; this.setLeftSubTree(null); return deletingNode; } public BinaryTree<T> removeRightSubTree() { BinaryTree<T> deletingNode = this.rightTree; this.setRightSubTree(null); return deletingNode; } // 전위순회 public void preOrderTraversal() { System.out.print(this.data + " "); if (this.leftTree != null) { this.leftTree.preOrderTraversal(); } if (this.rightTree != null) { this.rightTree.preOrderTraversal(); } } // 중위순회 public void inOrderTraversal() { if (this.leftTree != null) { this.leftTree.inOrderTraversal(); } System.out.print(this.data + " "); if (this.rightTree != null) { this.rightTree.inOrderTraversal(); } } // 후위순회 public void postOrderTraversal() { if (this.leftTree != null) { this.leftTree.postOrderTraversal(); } if (this.rightTree != null) { this.rightTree.postOrderTraversal(); } System.out.print(this.data + " "); } }public class AvlTree { private BinaryTree<Integer> root; public BinaryTree<Integer> getRoot() { return this.root; } public BinaryTree<Integer> searchCeil(int data) { BinaryTree<Integer> currentNode = this.root; BinaryTree<Integer> result = null; while (currentNode != null) { if (currentNode.getData() == data) { return currentNode; } else if (currentNode.getData() < data) { currentNode = currentNode.getRightSubTree(); } else { result = currentNode; currentNode = currentNode.getLeftSubTree(); } } return result; } public Integer search(int data) { BinaryTree<Integer> currentNode = this.root; while (currentNode != null) { if (currentNode.getData() == data) { return currentNode.getData(); } else if (currentNode.getData() > data) { currentNode = currentNode.getLeftSubTree(); } else { currentNode = currentNode.getRightSubTree(); } } return null; } public int getHeight(BinaryTree<Integer> node) { if (node == null) { return 0; } return node.getHeight(); } public void updateHeight(BinaryTree<Integer> node) { int leftChildHeight = this.getHeight(node.getLeftSubTree()); int rightChildHeight = this.getHeight(node.getRightSubTree()); node.setHeight(Math.max(leftChildHeight, rightChildHeight) + 1); } public int getBalanceFactor(BinaryTree<Integer> node) { if (node == null) { return 0; } return this.getHeight(node.getLeftSubTree()) - this.getHeight(node.getRightSubTree()); } public BinaryTree<Integer> rotateLeft(BinaryTree<Integer> node) { BinaryTree<Integer> childNode = node.getRightSubTree(); node.setRightSubTree(childNode.getLeftSubTree()); childNode.setLeftSubTree(node); this.updateHeight(node); this.updateHeight(childNode); return childNode; } public BinaryTree<Integer> rotateRight(BinaryTree<Integer> node) { BinaryTree<Integer> childNode = node.getLeftSubTree(); node.setLeftSubTree(childNode.getRightSubTree()); childNode.setRightSubTree(node); this.updateHeight(node); this.updateHeight(childNode); return childNode; } public BinaryTree<Integer> rotation(BinaryTree<Integer> targetNode, int data) { int balanceFactor = this.getBalanceFactor(targetNode); boolean isRootNode = false; if(targetNode == this.root) { isRootNode = true; } if (balanceFactor < -1 && data > targetNode.getRightSubTree().getData()) { targetNode = this.rotateLeft(targetNode); // LL }else if(balanceFactor > 1 && data < targetNode.getLeftSubTree().getData()) { targetNode = this.rotateRight(targetNode); // RR } else if (balanceFactor > 1 && data > targetNode.getLeftSubTree().getData()) { targetNode.setLeftSubTree(this.rotateLeft(targetNode.getLeftSubTree())); targetNode = this.rotateRight(targetNode); // LR } else if(balanceFactor < -1 && data < targetNode.getRightSubTree().getData()) { targetNode.setRightSubTree(this.rotateRight(targetNode.getRightSubTree())); targetNode = this.rotateLeft(targetNode); // RL } if (isRootNode) { this.root = targetNode; } return targetNode; } public BinaryTree<Integer> getUnBalanceNode(BinaryTree<Integer> targetRootNode, BinaryTree<Integer> unBalanceNode) { if (targetRootNode.getLeftSubTree() == null && targetRootNode.getRightSubTree() == null) { unBalanceNode = targetRootNode; return unBalanceNode; } int balanceFactor = this.getBalanceFactor(targetRootNode); if (balanceFactor > 0) { unBalanceNode = this.getUnBalanceNode(targetRootNode.getLeftSubTree(), unBalanceNode); } else if (balanceFactor < 0) { unBalanceNode = this.getUnBalanceNode(targetRootNode.getRightSubTree(), unBalanceNode); } else { unBalanceNode = targetRootNode.getRightSubTree(); } return unBalanceNode; } public BinaryTree<Integer> insert(BinaryTree<Integer> targetRootNode, int data) { if(targetRootNode == null) { targetRootNode = new BinaryTree<>(data); } if (this.root == null) { this.root = targetRootNode; } else if (targetRootNode.getData() == data) { return targetRootNode; } else if (targetRootNode.getData() > data) { targetRootNode.setLeftSubTree(this.insert(targetRootNode.getLeftSubTree(), data)); } else { targetRootNode.setRightSubTree(this.insert(targetRootNode.getRightSubTree(), data)); } this.updateHeight(targetRootNode); targetRootNode = this.rotation(targetRootNode, data); return targetRootNode; } public BinaryTree<Integer> remove(BinaryTree<Integer> targetRootNode, int data, BinaryTree<Integer> parentNode) { if (targetRootNode.getData() > data && targetRootNode.getLeftSubTree() != null) { targetRootNode.setLeftSubTree(this.remove(targetRootNode.getLeftSubTree(), data, targetRootNode)); } else if (targetRootNode.getData() < data && targetRootNode.getRightSubTree() != null) { targetRootNode.setRightSubTree(this.remove(targetRootNode.getRightSubTree(), data, targetRootNode)); } else if (targetRootNode.getData() == data) { targetRootNode = this.removeHelper(targetRootNode, data, parentNode); if (parentNode == null && targetRootNode != null) { this.updateHeight(targetRootNode); BinaryTree<Integer> unBalanceNode = this.getUnBalanceNode(targetRootNode, null); targetRootNode = this.rotation(targetRootNode, unBalanceNode.getData()); } return targetRootNode; } this.updateHeight(targetRootNode); BinaryTree<Integer> unBalanceNode = this.getUnBalanceNode(targetRootNode, null); targetRootNode = this.rotation(targetRootNode, unBalanceNode.getData()); return targetRootNode; } private BinaryTree<Integer> removeHelper(BinaryTree<Integer> deletingNode, int data, BinaryTree<Integer> parentNode) { BinaryTree<Integer> fakeParentRootNode = new BinaryTree<>(0); fakeParentRootNode.setRightSubTree(this.root); if (parentNode == null) { parentNode = fakeParentRootNode; } BinaryTree<Integer> deletingNodeChild = null; if (deletingNode.getLeftSubTree() == null && deletingNode.getRightSubTree() == null) { if (parentNode.getLeftSubTree() == deletingNode) { parentNode.removeLeftSubTree(); } else { parentNode.removeRightSubTree(); } } else if (deletingNode.getLeftSubTree() == null || deletingNode.getRightSubTree() == null) { if (deletingNode.getLeftSubTree() != null) { deletingNodeChild = deletingNode.getLeftSubTree(); } else { deletingNodeChild = deletingNode.getRightSubTree(); } if (parentNode.getLeftSubTree() == deletingNode) { parentNode.setLeftSubTree(deletingNodeChild); } else { parentNode.setRightSubTree(deletingNodeChild); } } else { BinaryTree<Integer> replacingNode = deletingNode.getLeftSubTree(); BinaryTree<Integer> replacingNodeParent = deletingNode; while (replacingNode.getRightSubTree() != null) { replacingNodeParent = replacingNode; replacingNode = replacingNode.getRightSubTree(); } deletingNode.setData(replacingNode.getData()); if (replacingNodeParent.getLeftSubTree() == replacingNode) { replacingNodeParent.setLeftSubTree(replacingNode.getLeftSubTree()); } else { replacingNodeParent.setRightSubTree(replacingNode.getLeftSubTree()); } deletingNodeChild = deletingNode; } if (fakeParentRootNode.getRightSubTree() != this.root) { this.root = fakeParentRootNode.getRightSubTree(); } return deletingNodeChild; } }public class GarbageCollector { private final AvlTree avlTree; public GarbageCollector() { this.avlTree = new AvlTree(); } public void insertFreeMemory(int size) { this.avlTree.insert(this.avlTree.getRoot(), size); } public BinaryTree<Integer> searchFreeMemory(int size) { return this.avlTree.searchCeil(size); } public void releaseFreeMemory(int size) { this.avlTree.remove(this.avlTree.getRoot(), size, null); } public static void main(String[] args) { GarbageCollector gc = new GarbageCollector(); System.out.println("================= 빈 메모리 영역 초기화 ================="); gc.insertFreeMemory(64); gc.insertFreeMemory(48); gc.insertFreeMemory(87); gc.insertFreeMemory(13); gc.insertFreeMemory(102); gc.insertFreeMemory(34); gc.insertFreeMemory(61); gc.insertFreeMemory(40); gc.insertFreeMemory(6); BinaryTree<Integer> freeMemory1 = gc.searchFreeMemory(64); // 64 System.out.println("Found: " + (freeMemory1 != null ? freeMemory1.getData() : "null")); if (freeMemory1 != null) { gc.releaseFreeMemory(freeMemory1.getData()); } BinaryTree<Integer> freeMemory2 = gc.searchFreeMemory(42); // 48 System.out.println("Found: " + (freeMemory2 != null ? freeMemory2.getData() : "null")); if (freeMemory2 != null) { gc.releaseFreeMemory(freeMemory2.getData()); } BinaryTree<Integer> freeMemory3 = gc.searchFreeMemory(150); // X System.out.println("Found: " + (freeMemory3 != null ? freeMemory3.getData() : "null")); if (freeMemory3 != null) { gc.releaseFreeMemory(freeMemory3.getData()); } } } 첨부파일: https://jeongburgger.notion.site/20538ccc08b98012b5a7c6dd7ddf388d?pvs=73https://inf.run/4sVHg (그림으로 쉽게 배우는 자료구조와 알고리즘 (심화편))https://inf.run/yFzxT (만들면서 쉽게 배우는 컴퓨터 구조)

알고리즘 · 자료구조감자컴퓨터구조알고리즘&자료구조

유일용

인프런 워밍업 클럽 CS4기_1주차 발자국

강의 수강 컴퓨터 구조(1) 컴퓨터 구성 요소CPU, 메모리, 데이터 저장장치 3가지 구조로 구성CPU : 중앙처리장치로 ALU(산술논리장치), 레지스터, 제어유닛으로 구성메모리 : RAM(random acces memory) 휘발성 메모리로 프로그램 실행시 메모리를 적재, HDD 와 같은 데이터 저장장치보다 속도가 빠르다. ROM(Read Only Memory) 읽기전용 메모리로 비휘발성이며 Bios와 같은 OS 부팅시 사용된다. 데이터 저장장치 : HDD(Hard Dirve Disk) 용량이 매우 크지만 데이터 접근시 순회하기 때문에 읽기/쓰기 작업이 오래 걸린다. SSD(Solid State Disk) 장치로 속도가 더 빠른 데이터 저장장치로 있다.(2) 컴퓨터 역사Compute + er의 합성어로 최초의 계산기 개념이 등장주판 -> 펀치홀 방식 -> 진공관 -> 애니악 -> 현대의 컴퓨터 순서로 발전오늘날의 컴퓨터 구조가 폰노이만에 의해서 완성 되었다.(3) 불 대수컴퓨터는 0과 1의 두가지 값으로 데이터를 인식불 연산 : 0, 1의 연산에는 AND, OR, NOT, NAND, NOR, XOR, NOT XOR 등이 존재한다.불 대수의 성질과 법칙 : 교환법칙, 결합법칙, 분배법칙불 함수 : 여러 개의 불 값을 연산을 통해 하나의 불 값을 결정하는 함수, 진리표를 통해 불 함수를 만들어 낼 수 있으며 수식을 만족하는 불 함수는 여러가지가 될 수 있다.진리표: 여러개의 불 값의 연산 결과를 정리해 놓은 표카르노 맵 : 진리 표와 비슷하며 불 함수를 만족하는 카르노 맵을 만들어서 기존의 불 함수를 더 간결하게 만들 수 있다. 카르노 맵의 결과값을 만족하는 2n 승으로 최대한 길게 값을 묶으면 불 함수 수식을 알 수 있다.(4) 비트컴퓨터에서 데이트를 표현하는 방식으로 0과 1로 이루어져 있다.컴퓨터는 8비트, 32비트, 64비트 체계 OS가 존재한다.각 비트마다 자리수를 표현하며 8비트는 1바이트를 나타낸다.진법에는 사람이 인식하기 쉬운 10진법과 컴퓨터에서 데이터를 표현하는 2진법이 존재10진법에서 2진법 변환은 값을 2로 나눈후 그 몫을 역순으로 읽으면 된다.2진수는 16진수로 변환이 가능하며 4비트 하나가 16진수로 변환 가능하다.빅에디안 리틀에디안빅에디안 : 컴퓨터의 메모리 주소 체계에서 가장 큰 값을 순차적으로 저장하는 구조리틀에디안 : 컴퓨터의 메모리 주소 쳬계에서 가장 작은 값을 순차적으로 저장하는 구조오버플로우와 인터럽트오버플로우 : 8비트 체계를 가진 컴퓨터에서 표현가능한 최대 숫자 범위를 넘어서 연산을 한 경우 그 값이 예상된 결과를 벗어나는 현상인터럽트 : 8비트 연산에서 255의 값에 1을 더할 경우 연산의 결과가 0이되면서 발생하는 1의 값음수를 컴퓨터에서 표현하는 방법은 MSB 비트를 부호값으로 사용하여 표현하며 값의 범위는 부호가 없는 경우에 반만 표현 가능하다. 2진수 양수에서 음수를 구하는 방법은 2의 보수를 구하면 가능하다. 자료 구조와 알고리즘(1) 트리와 이진트리개념노드 : 트리에서 표현되는 하나의 값루트 노드 : 트리에서 최상위 값터미널 노드 : 자식트리가 없는 노드트리 : 데이터 구조를 부모 자식형태로 나타낸 형태이며 부모 노드에 여러개의 자식 노드가 있을 수 있다.이진 트리 : 트리 형태를 가지면서 부모 노드의 자식 노드가 최대 2개를 넘지 않는다. 부모 노드의 왼쪽 자식 노드로는 더 작은 값의 노드만 올수 있으며 오른쪽 자식노드로는 더 큰 값만 올 수 있다.포화 이진 트리 : 이진 트리이면서 부모에 자식 노드가 모두 존재하는 트리완전 이진 트리 : 이진 트리이면서 부모의 자식 노드로 자식노드가 하나만 있거나 없는 트리(2)이진 탐색 트리이진 탐색 알고리즘 : 원하는 값을 찾기위해 매번 범위를 반으로 줄여가면서 찾아가는 알고리즘, 데이터가 정렬되지 않은 경우 최대 n의 반복회수가 필요하므로 속도가 매우 느리다.이진 탐색 트리개념 : 이진 탐색 알고리즘의 단점을 보완, 데이터 구조가 이진 트리를 만족하는 형태삽입, 검색, 삭제 중 삭제시에 시간이 올래 걸리고 복잡하다.조건 : 중복된 노드가 없어야 한다, 이진트리의 조건을 자식트리도 만족해야한다.단점 : 데이터 삽입시 이진 트리 구조가 깨진다면 데이터 검색속도는 n의 반복횟수가 되며 장점이 없어지게 된다.(3)AVL 트리이진 탐색 트리의 단점을 보완, 데이터 삽입시 이진 트리의 구조를 깨지 않기 위해 왼쪽 자식 트리의 높이와 오른쪽 자식 트리의 높이 차가 최대 2를 넘지 않도록 조건을 만족하는 값을 구한다.3. 회고 컴퓨터 공학을 전공했기에 대부분 알고 있는 내용이라고 생각했지만 강의를 수강하면서 깊게 알지 못했던 내용들을 다시 한 번 되짚어 부족했던 지식을 채우는 계기가 되었던 것 같습니다. 한 주동안 수강하면서 금방 이해 할 수 있을 거라고 보았지만 중간중간 강의를 다시 보아야 할 만큼 이해하기 어려운 부분들이 있다는 것을 보면서 스스로 부족한 부분들이 아직도 많다는 것을 깨닫게 되었습니다. 지난 한주동안 공부한 내용을 요약하면서도 남들에게 공유할 만큼의 지식을 갖추지 못한 것 같아 갈 깊이 아직 먼 것 같습니다. 다음 주에는 좀 더 강의에 집중하면서 많은 분들에게 지식 공유를 할 만큼 더 알기 쉽고 잘 정리된 강의 노트를 작성해 볼 예정입니다.  미션1. 미션 해결 과정모르는 부분은 강의에서 해당 부분을 찾아서 다시 한 번 복습하는 식으로 해결하였습니다. 풀이하는 방법은 여러가지가 있을 수 있지만 해결한 값의 정답은 GPT를 통해서 검증하였습니다.   자료구조와 알고리즘 1주차 미션 문제의 경우 강의에서 제공하는 AVL 트리 구현을 참고해서 필요한 메소드만 새로 추가하는 방식으로 처리하였습니다. 검증시 Tree자체가 이진 트리 구조로 잘 구성되었을 경우에만 Search함수가 정상 동작하는 문제가 있을 것 같습니다. 2. 회고아직 강의 초반부분임에도 불구하고 미션 해결과정에서 어려움을 느꼈습니다. 좀 더 강의 내용을 깊게 학습하고 복습하면서 어려운 문제에도 문제없이 풀 수 있도록 준비를 해야 할 것 같습니다. 미션에 정답은 하나이지만 풀의 방식은 각자가 다를 것이라고 보고 서로 간의 풀이 과정도 공유하면 유익한 강의가 될 것 같습니다.AVL 트리 구조의 경우 다소 난이도가 있어서 이해하고 구현하는데 많은 시간이 걸려서 다시 한 번 복습해야 할 듯 싶습니다.

알고리즘 · 자료구조스터디CS#발자국

인프런 워밍업 클럽 4기 - CS 전공지식; 컴퓨터 구조 및 알고리즘

인프런 워밍업 클럽 4기 첫 주차!먼저 컴퓨터 구조 강의들을 수강하였다.각 강의들은 큰 주제를 나누어 섹션별로 구분되어있었는데첫 번째 섹션은 컴퓨터 구조 개론 이였다.이 섹션은 4강의로 나누어 이 강의를 들어야 하는 이유 및 컴퓨터의 역사를 배워보는 시간이였다.어릴 적 어딘가 들어봤던 용어들을 다시 떠올리는 기본 워밍업 느낌의 섹션이였다. 두 번째 섹션은 컴퓨터의 구성 요소!가장 중요한 CPU부터 메모리 및 주변 장치들에 대하여 공부하였고다양한 비트의 컴퓨터의 차이점을 배우며 앞으로 실습하게 될 8bit컴퓨터에 대해서 기본을 알 수 있는 강의였다. 다음 섹션은 불 대수에 대한 섹션이였다.6개의 강의로 나누어져 불 대수에 대해서 공부하는 시간이였는데.대학생때로 돌아가 가물가물한 기억들을 더듬어가며 한강의씩 수강해나갔고.첨부링크에 있는 드모르간 법칙의 정의 사이트로 이동하여 시간이 걸리더라도 하나씩 직접 종이에 써가며해당 정의에 대해 친숙함을 가지려고 하였다. 4번째 섹션은 비트에 대한 섹션이였는데.우리가 흔히 사용하는 10진법부터 2진법, 16진법에 대하여 공부하였고어떠한 숫자를 각 진법에 따라 변환하는 방법을 공부하였다.빅 엔디안 및 리틀 엔디안 방법에 대해서도 알게 되었고, 컴퓨터가 음수를 표현하는 방식에 대해서도 공부하였다. 5번째 섹션은 지금까지 기초를 공부했다면 실습에 돌입하는 섹션이였는데.직접 프로그램을 이용해서 NAND, NOT 등 다양한 회로들을 만들어 볼 수 있는 섹션이였다.프로그램을 처음써보다보니 신기하면서도 이렇게 프로그램으로 회로를 만들어 볼 수 있다는 것이 신기하였다.이번 1주차때는 XOR 게이트까지 직접 만들어보는 강의가 이어졌고 다음 2주차에는 비트별 입력회로를 공부하는 것 같았다. 컴퓨터 구조 강의를 듣고 나서는 자료구조와 알고리즘 강의를 수강하였는데.심화편이란걸 좀 더 미리 알았으면 이 워밍업 클럽이 시작되기전에 미리 기본편을 듣는건데너무 늦게 알아버린 바람에 기본편과 같이 조금씩 듣기로 마음먹었다. 알고리즘 강의의 첫 번째 섹션은 정말 기본적인 준비과정이였다.기본편을 듣지 못한 수강생들을 위해 기본 파일들을 다운받을 수 있었고또한 vs코드 프로그램 설치방법부터 시작할 수 있었다.이제 준비가 끝나고 나면 본강의 시작전 P-NP강의를 시작으로 이제 본격적으로 코스가 시작되는 느낌이였다. 두 번째 섹션은 트리와 이진트리 섹션이였는데기본적인 트리와 이진트리의 개념에 대하여 자세한 강의를 듣고 이제 그걸 직접 코드로 구현해보는 강의였다.처음한번 강의만 틀어서 한번 본뒤에 이제 vscode를 켜고 다시 강의를 따라가면서 하나씩 차근차근코드를 치며 이해를 해보려고 하였다. 세 번째 섹션은 이전 섹션에서 이진트리의 기본 개념을 이해했다~이제 심화를 가자 느낌으로두 가지 개념을 합친 이진 탐색 트리에 대한 개념강의가 이어졌고. 마찬가지로 개념 강의가 끝난 뒤에는 삽입의 구현과 제거의 구현이 이어졌다.역시 저번 섹션처럼 단 한번만 강의를 들어서는 무슨 내용인지 이해하기가 쉽지 않았고최대한 이해하려고 노력하며 이번 섹션을 마무리하였다. 몰아치듯 이어지는 다음 섹션은 AVL 트리!앞 섹션과 마찬가지로 개념설명 -> 구현의 형식으로 강의가 이어졌다.벌써부터 어질어질한걸봐선 다음 2주차 진행하기 전에 3~4섹션에 대해서 다시 복습이 필요할 것 같다 하는 생각이 들었다.기본편을 다 듣고 시작했다면 쉬웠을까? 하는 생각이 들어 다음 2주차 발자국을 작성할때에는 기본편을 마무리하고 작성해야겠다 하는 다짐을 하며 한 주 학습을 마무리하였다. 

알고리즘 · 자료구조인프런워밍업클럽CS컴퓨터구조알고리즘심화편

강동훈

[인프런 워밍업 클럽 4기 - CS] - 1주차 미션 (자료구조와 알고리즘 심화)

문제Python, JavaScript, C# 같은 언어는 가비지 컬렉터를 이용해 메모리를 자동으로 정리하는 매니지드 언어(Managed Language)에 속합니다.매니지드 언어의 가비지 컬렉터는 개발자가 메모리를 요청하면 운영체제의 힙 영역에 할당하고, 더 이상 필요하지 않을 때 자동으로 해제하며 메모리를 관리합니다.여러분이 속한 회사에서 새로운 매니지드 언어를 개발 중이며, 여러분은 가비지 컬렉터 개발을 담당하게 되었습니다.특히 메모리 검색 부분을 맡게 되었는데, 사용자가 특정 크기(Byte)의 메모리를 요청하면 사용 가능한 메모리 중 가장 적절한 크기를 찾아 반환하는 GarbageCollector 클래스를 구현해보세요.(같은 크기의 메모리는 없다고 가정)import { AVLTree } from "./avlTree.mjs" class GabageCollector{ } const gc = new GabageCollector(); console.log("========== 빈 메모리 영역 초기화 =========="); gc.insertFreeMemory(64); // 빈 64바이트 삽입 gc.insertFreeMemory(48); // 빈 48바이트 삽입 gc.insertFreeMemory(87); // 빈 87바이트 삽입 gc.insertFreeMemory(13); // 빈 13바이트 삽입 gc.insertFreeMemory(102); // 빈 102바이트 삽입 gc.insertFreeMemory(34); // 빈 34바이트 삽입 gc.insertFreeMemory(61); // 빈 61바이트 삽입 gc.insertFreeMemory(40); // 빈 40바이트 삽입 gc.insertFreeMemory(6); // 빈 6바이트 삽입 let freeMemory1 = gc.searchFreeMemory(64); // 64바이트 메모리 console.log(freeMemory1); if(freeMemory1){ gc.releaseFreeMemory(freeMemory1.data); } let freeMemory2 = gc.searchFreeMemory(42); // 48바이트 메모리 획득 console.log(freeMemory2); if(freeMemory2){ gc.releaseFreeMemory(freeMemory2.data); } 풀이import { AVLTree } from "./avlTree.mjs"; class GabageCollector { constructor() { this.tree = new AVLTree(); } // 노드 추가 insertFreeMemory(data) { this.tree.root = this.tree.insert(this.tree.root, data); } // 가장 인근의 노드 찾기 searchFreeMemory(data) { if (this.tree.root === null) { return null; } let currentNode = this.tree.root; let parentNode = null; while (currentNode !== null) { // 현재 노드가 찾고자 하는 데이터보다 작을 경우 오른쪽 서브트리로 이동 if (currentNode.getData() < data) { currentNode = currentNode.getRightSubTree(); } else { // 찾고자 하는 데이터보다 큰 노드를 발견할 경우 부모 노드에 저장 후 왼쪽 서브트리로 이동 parentNode = currentNode; currentNode = currentNode.getLeftSubTree(); } } return parentNode ? parentNode : null; } // 노드 제거 releaseFreeMemory(data) { this.tree.root = this.tree.remove(this.tree.root, data); } } const gc = new GabageCollector(); console.log("========== 빈 메모리 영역 초기화 =========="); gc.insertFreeMemory(64); // 빈 64바이트 삽입 gc.insertFreeMemory(48); // 빈 48바이트 삽입 gc.insertFreeMemory(87); // 빈 87바이트 삽입 gc.insertFreeMemory(13); // 빈 13바이트 삽입 gc.insertFreeMemory(102); // 빈 102바이트 삽입 gc.insertFreeMemory(34); // 빈 34바이트 삽입 gc.insertFreeMemory(61); // 빈 61바이트 삽입 gc.insertFreeMemory(40); // 빈 40바이트 삽입 gc.insertFreeMemory(6); // 빈 6바이트 삽입 console.log("========== 삽입된 메모리 중위 순회 =========="); gc.tree.root.inOrderTraversal(gc.tree.root); console.log("========== 메모리 제거 1 =========="); let freeMemory1 = gc.searchFreeMemory(64); // 64바이트 메모리 console.log(freeMemory1 ? freeMemory1.getData() : "매모리를 추가할 수 없습니다."); if (freeMemory1) { gc.releaseFreeMemory(freeMemory1.data); } console.log("========== 메모리 제거 2 =========="); let freeMemory2 = gc.searchFreeMemory(42); // 48바이트 메모리 획득 console.log(freeMemory2 ? freeMemory2.getData() : "매모리를 추가할 수 없습니다."); if (freeMemory2) { gc.releaseFreeMemory(freeMemory2.data); } console.log("========== 변경된 메모리 중위 순회 =========="); gc.tree.root.inOrderTraversal(gc.tree.root);문제에서는 총 세 가지 메서드를 구현하여야 했다.insertFreeMemory: 빈 메모리를 삽입할 수 있는 기능searchFreeMemory: 데이터를 할당할 수 있는 최소의 메모리 공간을 검색하는 기능3. releaseFreeMemory: 해당 메모리를 삭제할 수 있는 기능우선적으로 GarbaceCollector에서 메모리 영역은 하나의 AVL 트리로 다뤄진다고 생각을 하여서 this.tree 속성으로 AVL 트리를 생성해주었다. insertFreeMemory의 경우, AVL Tree에서 제공해주는 insert 메서드를 통해 트리의 root를 설정해주고 그 하위에 적절한 위치를 찾아서 각 노드를 삽입해주었다. releaseFreeMemory의 경우, 동일하게 AVL Tree에서 제공하는 remove 메서드를 통해 데이터를 찾아가며 해당 노드를 삭제하고 각 노드의 height나 unbalance한 노드의 균형을 잡아주었다. searchFreeMemory는 새롭게 기능을 추가하여야 하였다. 처음에는 단순하게 매개변수의 데이터 값과 일치하는 노드만 반환하면 될 줄 알았지만 문제에서 '사용 가능한 메모리 중 가장 적절한 크기' 를 반환해야 한다고 적혀있듯 매개변수로 받는 데이터 이상의 노드들 중 최소값을 가진 노드를 반환해야 했다.메서드를 작성하기 전에 먼저 예외처리를 하였다.AVL Tree의 루트 노드가 없을 경우매개변수로 받는 데이터가 모든 노드의 값보다 클 경우두 가지 경우에는 null을 반환하고 "매모리를 추가할 수 없습니다."라고 로그를 찍어주었다.그 외의 경우에는 이제 while문을 통해 가장 인접한 값의 노드로 이동을 시켜주었다.만약 현재 위치한 노드의 값이 찾으려는 데이터보다 작다면 우측 서브트리로 이동해주고,데이터보다 큰 노드를 발견하게 된다면 부모 노드를 미리 저장해주고 좌측 서브트리로 이동해주었다.부모노드를 저장해주는 이유는 좌측 서브트리의 노드를 데이터보다 작을 수도 있기에 반환해줄 수 있는 노드 변수를 만들어주었다.그렇게 while 문을 반복하다보면 현재 위치의 노드가 null이 나오게 되고 기저 조건을 벗어나서 결국 부모 노드에 저장된 노드값이 사용 가능한 메모리 중 가장 적절한 크기가 되며 부모 노드가 null이라면 아까처리한 예외 조건에 의해 로그가 찍히게 된다. 저번 기수보다 더 어려운 문제를 미션으로 출제하신다는 코치님의 말씀에 겁을 먹었었지만 막상 이렇게 실용적인 예제와 직접 구현을 해보면서 미션을 진행하다보니 기존에 배웠던 AVL Tree에 대해 더 자세히 익히게 되고 동작 방식이나 해당 자료구조에 대한 특징을 몸소 체험해볼 수 있었던 것 같다.

알고리즘 · 자료구조미션알고리즘자료구조

suover

인프런 워밍업 클럽 스터디 4기 - CS 전공지식 1주차 발자국

그림으로 쉽게 배우는 자료구조와 알고리즘 (심화편)만들면서 쉽게 배우는 컴퓨터 구조강의와 함께한 인프런 워밍업 클럽 스터디 4기 - CS 전공지식 (자료구조, 알고리즘, 컴퓨터구조)1주차 발자국 입니다.학습 내용 요약이번 주에는 두 가지 강의를 통해 자료구조·알고리즘과 컴퓨터 구조의 큰 틀을 살펴보며, 이론과 실습을 병행했습니다.그림으로 쉽게 배우는 자료구조와 알고리즘 (심화편)크게 트리 구조와 이진 탐색 트리(BST), 그리고 그 위에 균형을 더한 AVL 트리를 다뤘습니다.초반에는 "트리와 이진 트리 개념"으로 부모·자식 노드 간 관계를 복습했고, 이어서 BST의 삽입·검색·삭제 과정을 훑어보았습니다.마지막으로 AVL 트리 개념과 구현(보조 함수, 삽입, 삭제)을 익히며, "왜 균형 인자가 중요한지"와 "삽입/삭제 후 어떻게 회전으로 높이를 조정하는지"를 이해했습니다.만들면서 쉽게 배우는 컴퓨터 구조컴퓨터 구조 전반(블랙박스 관점, CPU·메모리·주변 장치)과 함께, 불 대수 및 논리 게이트 설계로 넘어가 간단한 하드웨어 시뮬레이션을 해보았습니다.먼저 "컴퓨터 구조를 배우는 이유"와 명령어가 메모리→CPU→다시 메모리로 흐르는 과정을 개념적으로 파악했고, CPU 내부와 메모리 계층도 간단히 살펴봤습니다.이어서 불 대수 기본 연산과 성질을 학습한 뒤, 직접 Logisim을 설치해 NAND/NOT/AND/OR/XOR 게이트를 조합해 보는 실습을 경험했습니다.또 10진수↔2진수 변환, 16진법, 빅·리틀 엔디안, 2의 보수 음수 표현 같은 비트 단위 개념을 짚으며, 디지털 회로의 밑바탕이 되는 이진 표현 방식을 정리했습니다.미션🎯 자료구조·알고리즘 미션1: GarbageCollector 클래스 구현목표: AVL 트리로 빈 메모리 블록을 관리해, 요청 크기와 정확히 일치하는 블록이나 그보다 큰 값 중 최소값을 찾아 반환·삭제하도록 한다.코드import { AVLTree } from "../../avlTree/avlTree.mjs"; class GabageCollector { constructor() { this.avlTree = new AVLTree(); } // 빈 메모리 블록 삽입 insertFreeMemory(size) { this.avlTree.root = this.avlTree.insert(this.avlTree.root, size); } // 요청 크기 이상인 블록 검색 searchFreeMemory(requestSize) { let current = this.avlTree.root; let candidate = null; while (current) { const nodeSize = current.getData(); if (nodeSize === requestSize) { // 정확히 같은 크기를 찾으면 즉시 반환 candidate = current; break; } if (nodeSize > requestSize) { // 후보로 저장한 뒤, 더 작은 후보를 찾기 위해 왼쪽 서브트리 탐색 candidate = current; current = current.getLeftSubTree(); } else { current = current.getRightSubTree(); } } return candidate; } // 반환된 블록(크기) 삭제 releaseFreeMemory(size) { this.avlTree.root = this.avlTree.remove(this.avlTree.root, size); } } // 실행 const gc = new GabageCollector(); console.log("========== 빈 메모리 영역 초기화 =========="); gc.insertFreeMemory(64); // 빈 64바이트 삽입 gc.insertFreeMemory(48); // 빈 48바이트 삽입 gc.insertFreeMemory(87); // 빈 87바이트 삽입 gc.insertFreeMemory(13); // 빈 13바이트 삽입 gc.insertFreeMemory(102); // 빈 102바이트 삽입 gc.insertFreeMemory(34); // 빈 34바이트 삽입 gc.insertFreeMemory(61); // 빈 61바이트 삽입 gc.insertFreeMemory(40); // 빈 40바이트 삽입 gc.insertFreeMemory(6); // 빈 6바이트 삽입 let freeMemory1 = gc.searchFreeMemory(64); // 64바이트 메모리 console.log(freeMemory1); if (freeMemory1) { gc.releaseFreeMemory(freeMemory1.data); } let freeMemory2 = gc.searchFreeMemory(42); // 48바이트 메모리 획득 console.log(freeMemory2); if (freeMemory2) { gc.releaseFreeMemory(freeMemory2.data); }실행 요약const gc = new GarbageCollector(); 빈 블록 [64, 48, 87, 13, 102, 34, 61, 40, 6]을 insertFreeMemory(...)로 순차 삽입 searchFreeMemory(64) → 정확히 64 노드를 찾아 반환 → releaseFreeMemory(64) 삭제 searchFreeMemory(42) → 42와 동일한 값이 없어 “42보다 큰 값 중 최소(48)” 반환 → releaseFreeMemory(48) 삭제 회고AVL 트리의 삽입·삭제 시 "LL·RR·LR·RL 회전"이 실제로 동작하는 것을 확인하며, 균형 인자의 중요성을 체감했습니다. 삽입, 삭제, 검색이 모두 로그 시간에 동작하기 때문에, 빈 메모리 블록이 많아질 때도 성능을 보장할 수 있다는 점을 체감했습니다. "정확히 같은 크기가 없을 때, 그보다 큰 값 중 최소값을 찾는 후보(candidate)" 로직을 루트부터 내려가며 올바르게 업데이트해야 합니다.    🔗자료구조·알고리즘 미션1 블로그 링크🎯 컴퓨터 구조 미션1 (총 5개)미션 1. 4입력 논리 연산 진리표 작성내용: 4개의 입력(A, B, C, D)에 대한 AND, OR, NAND, NOR, XOR 진리표를 총 16조합으로 작성실행A B C D를 0000 → 0001 → … → 1111 순서로 나열 각 연산(AND, OR, NAND, NOR, XOR)의 출력(Q)을 직접 채워 넣음느낀 점2진수 순서대로 입력 조합을 정리하니 빠짐없이 작성할 수 있었고, XOR처럼 "1 개수 홀짝 판정" 연산은 중간에 헷갈려도 정리 순서를 엄수하면 실수를 줄일 수 있었다.미션 2. 불 방정식 간략화내용: 아래 네 개의 불 방정식을 단계별로 법칙(아이디엠포턴트, 드모르간, 흡수 등)을 적용해 간략화했다.A( (BB)’ + 0A) + (CC)’ = (AB’) + C’ (B’B’) + (AD’ + (CA)’)D = B’ + (DC’) + (DA’) (A’B) + B(B1 + BC) = B B’(1C + BD) + DB = (B’C) + (DB) 느낀 점드모르간·흡수법칙을 차례로 적용하며 "복잡해 보이던 식이 단번에 간결해지는 과정"이 인상적이었다.단계별로 어떤 법칙을 먼저 적용해야 가장 효율적으로 축약되는지 아직 직관이 부족해, 다음주엔 다양한 예제를 풀어 보며 연습할 예정이다.미션 3. 2진수를 10진수로 변환내용: 다음 네 개의 2진수를 10진수로 바꿔 보았다.110111₂ = 55₁₀ 10000001₂ = 129₁₀ 11111100000₂ = 2016₁₀ 101010₂ = 42₁₀실행 각 2진수를 우측 끝 비트부터 자리값(2⁰, 2¹, 2², …)을 곱해 합산 예: 11111100000₂ = 1·2¹⁰ + 1·2⁹ + … + 1·2⁵ + 0·… = 1024 + 512 + 256 + 128 + 64 + 32 = 2016느낀 점자릿값을 일일이 계산하는 것은 번거롭지만, "가장 큰 2의 거듭제곱부터 차례로 빼 나가는 방식"으로 익히니 긴 이진수도 비교적 빠르게 변환할 수 있었다.미션 4. 10진수를 2진수로 변환내용: 다음 네 개의 10진수를 2진수로 바꿔 보았다.10₁₀ = 1010₂ 27₁₀ = 11011₂ 86₁₀ = 1010110₂ 516₁₀ = 1000000100₂실행 나눗셈→나머지 반복: 예를 들어 86 ÷ 2 = 43, 나머지 0 → 43 ÷ 2 = 21, 나머지 1 → … → 최종 이진수 역순 또는 "가장 큰 2의 거듭제곱(2⁶=64)부터 빼 나가기" 방식으로 빠르게 도출느낀 점처음엔 헷갈렸지만, "2ⁿ 이하 최대값을 찾아서 빼고, 나머지로 또 반복"하는 방식이 머릿속에 각인되자 더 긴 수도 금방 변환할 수 있었다.미션 5. 불 방정식을 Logisim으로 회로 구현내용: 불 방정식을 logisim을 이용해 회로 만들기 실행(B′·C) + (D·B)B → NOT → B′AND1: (B′, C)AND2: (D, B)OR: (AND1, AND2) → 출력(A·B′) + CB → NOT → B′AND: (A, B′)OR: (AND, C) → 출력B′ + (D·C′) + (D·A′)B → NOT → B′ (첫 OR 입력)C → NOT → C′, A → NOT → A′AND1: (D, C′)AND2: (D, A′)OR( B′, AND1, AND2 ) → 출력대표 입력별 검증(B′·C)+(D·B) → B=0,C=1,D=0 → OUT=1, B=1,C=0,D=1 → OUT=1, B=1,C=1,D=0 → OUT=0(A·B′)+C → A=0,B=0,C=1 → OUT=1, A=1,B=1,C=0 → OUT=0B′+(D·C′)+(D·A′) → A=0,B=0,C=0,D=0 → OUT=1, A=1,B=1,C=0,D=1 → OUT=1느낀 점Logisim을 통해 "진리표상의 연산이 실제 게이트 단위 회로에서 어떻게 동작하는지"를 직접 눈으로 확인할 수 있었다.회로가 복잡해질수록 배선이 겹치는 문제가 있었으나, 다음에는 모듈 단위(예: (B′·C) 회로 → (D·B) 회로 → OR)로 나눠서 단계별로 검증하려 한다. 🔗컴퓨터 구조 미션1 블로그 링크회고이번 주에는 AVL 트리와 논리 회로 설계를 함께 학습했습니다.AVL 트리 구현: 삽입·삭제 시 LL·RR·LR·RL 회전을 거쳐 균형을 유지하는 과정을 직접 코드로 확인했습니다. "정확히 같은 값이 없으면 그보다 큰 값 중 최소값을 찾는 로직"을 구현하면서, 균형 인자를 어떻게 업데이트해야 하는지 확실히 알게 되었습니다.논리 회로 설계: 4입력 진리표 작성부터 불 방정식 간략화, Logisim 회로 구성까지 순서대로 진행했습니다. 직접 회로를 만들어 입력을 바꿔 볼 때마다 결과가 즉시 바뀌는 모습을 보면서, 이론이 실제 게이트 동작으로 이어진다는 점이 와닿았습니다.스스로 칭찬하는 점이론과 실습 병행AVL 트리 코드와 Logisim 회로를 동시에 구현하며, 배운 내용을 손으로 직접 확인한 점이 좋았습니다.진리표 정리법 습득2진수 순서대로 진리표를 빠짐없이 작성하면서, 체계적인 정리 방법을 제대로 익혔습니다.아쉬웠던 점 & 보완회로 배선 정리 부족Logisim에서 선이 겹치다 보니 가끔 헷갈렸습니다.→ 다음에는 작은 모듈로 나눠 단계별로 검증하고, 마지막에 합치는 방식을 사용하겠습니다. 개념 정리 자료 부족AVL 트리나 불 대수 법칙을 공부할 때, 머릿속으로만 이해하고 따로 요약해 두지 않아 복습할 때 헷갈리는 부분이 있었습니다.→ 학습 중에는 핵심 개념을 노트에 간단히 정리하여, 부족한 부분을 바로 찾아볼 수 있도록 하겠습니다.마치며이번 주차는 이론을 코드와 회로로 연결해 보는 경험을 했습니다. 다음 주에도 부족했던 부분을 보완하며 차근차근 학습을 이어가겠습니다! 감사합니다!

알고리즘 · 자료구조인프런워밍업클럽스터디CS전공지식자료구조컴퓨터구조발자국회고4기

[워밍업클럽4기-CS] 발자국 1

자료구조와 알고리즘 P-NP 개념P: 결정론적 튜링기계로 다항시간 내 풀수 있는 문제 NP: 비결정론적 튜링기계로 다항시간 내 풀수 있는 문제NP-complete : 다른 NP문제를 환원한 결과인 NP 문제NP-hard : 비결정론적 튜링기계로도 다항시간 내 풀 수 있음이 증명되지 않은 문제P=NP가 증명된다면 존재하는 모든 문제는 결정론적 튜링기계로 해결 가능하다.이진 트리자식 노드를 최대 두 개만 가지는 트리 자료구조모든 자식노드가 2개라면 포화 이진 트리, 왼쪽부터 채워진다면 완전 이진 트리이진탐색트리이진 트리 중 각 서브트리의 루트가 왼쪽 자식노드 보다는 크고 오른쪽 자식노드 보다는 작은 트리균형을 보장하지 않으므로 최악의 경우 탐색에 O(n) 소요AVL트리삽입,제거로 인해 균형이 깨질 경우 회전을 통해 스스로 균형을 맞추는 트리컴퓨터 구조개요 - 블랙박스, 컴퓨터의 역사, 프로그램 동작 원리블랙박스 : 인풋에 따른 아웃풋은 예상 가능하나, 내부 동작 원리는 이해할 수 없음 -> 모듈화에 활용CPU / 메모리 / 주변장치 / bit접근속도 : 하드디스크 < RAM/ROM < 캐시메모리 < 레지스터저장용량 : 하드디스크 > RAM/ROM > 캐시메모리 > 레지스터불 대수 / 진리표1(true)/0(false)를 활용한 대수 연산진리표 : 불 대수 연산의 결과표하드웨어 시뮬레이터를 활용한 게이트 구현 회고인강 수강에 출퇴근 시간 활용이 생각보다 더 효율적임을 알게되었다. 인강 수강과 별개로 금주는 개인 일정 등으로 저녁에 복습을 위해 가진 시간이 많지 않았던 점이 아쉽다.출퇴근 시간에 수강할 수 있는 인강의 양이 예상보다 더 많음을 확인했으니 차주는 출퇴근 시간 활용으로 벌어둔 저녁 시간을 더 활용하면 좋을 것 같다. 

알고리즘 · 자료구조

수뼈

인프런 워밍업 클럽 스터디 3기 - CS 전공지식 <셋째 주 발자국>

[Day 11~13]Algorithm정렬 알고리즘(Sorting Algorithm)개요데이터셋이 주어졌을 때, 이를 사용자가 지정한 기준에 맞게 정렬하여 출력하는 알고리즘.참고: 정렬 알고리즘은 왜 배워야 할까?대표적인 정렬 알고리즘버블 정렬(Bubble Sort) (Day 09 참고)선택 정렬(Selection Sort) (Day 09 참고)삽입 정렬(Insertion Sort)개요 및 특징자료 배열의 모든 요소를 앞에서부터 차례대로 이미 정렬된 배열 부분과 비교해, 자신의 위치를 찾아 삽입하는 알고리즘(참고).구현이 쉬운 편에 속하나 성능은 O(n^2)로 매우 낮음.구현하기첫 번째 구현: 강의 보며 구현 (Done)두 번째 구현: 강의 안 보고 구현하다 기억 안 나면 강의 확인하며 구현 (Done)세 번째 구현: 강의 안 보고 구현하다 기억 안 나면 과거에 내가 짠 코드 확인하며 구현 (Done)네 번째 구현: 아무것도 안 보고 구현 (Done)마지막 구현: 익숙한 파이썬으로 구현(+리팩토링(비파괴적 연산, 예외처리)) (Done)병합 정렬(Merge Sort)개요 및 특징Array를 정렬의 최소 단위(=1개)로 쪼개 정렬한 결과를 병합하여 정렬하는 알고리즘.Devide and Conquer 기법과 재귀 함수를 이용해 정렬함(참고).참고: 여기서 설명하는 건 mergeSort()가 아니라 merge()다. 저걸 누가 헷갈리냐고? NADA재귀적으로 구현해야 하므로 이해와 구현이 어려우나, 성능(O(nlogn))이 매우 높음.구현하기첫 번째 구현: 강의 보며 구현 (Done)두 번째 구현: 강의 안 보고 구현하다 기억 안 나면 강의 확인하며 구현 (Done)세 번째 구현: 강의 안 보고 구현하다 기억 안 나면 과거에 내가 짠 코드 확인하며 구현 네 번째 구현: 아무것도 안 보고 구현 마지막 구현: 익숙한 파이썬으로 구현(+ 리팩토링) 퀵 정렬(Quick Sort)개요 및 특징피벗(Pivot)을 기준으로 작은 값과 큰 값을 분할하며 정렬하는 알고리즘.Devide and Conquer 기법과 재귀 함수를 이용해 정렬함(참고).pivot에 따라 Θ(nlogn), O(n^2)로, 안정적으로 O(nlogn)의 성능을 뽑아내는 병합 정렬이 더 좋음.하지만, 같은 O(nlogn)이라면 Locality of Reference 원리 때문에 더 빠름.구현하기첫 번째 구현: 강의 보며 구현 (Done)두 번째 구현: 강의 안 보고 구현하다 기억 안 나면 강의 확인하며 구현 세 번째 구현: 강의 안 보고 구현하다 기억 안 나면 과거에 내가 짠 코드 확인하며 구현 네 번째 구현: 아무것도 안 보고 구현 마지막 구현: 익숙한 파이썬으로 구현(+ 리팩토링) Operating System가상 메모리(Virtual Memory)개요실행하고자 하는 프로그램을 일부만 메모리에 적재하여 실제 물리 메모리 크기보다 더 큰 프로세스를 실행할 수 있게 하는 기술(혼공컴운 402p.)가상 메모리 시스템에서 MMU는 동적 주소 변환(Dynamic Address Translation; DAT)을 통해 RAM의 물리 주소와 스왑 영역을 하나의 가상 주소로 보고 관리함(참고).가상 주소-물리 주소쌍은 매핑 테이블로 관리됨(참고).프로세스 입장에서 관리 편의성 향상을 위해 생성된 가상의 공간이므로 이론상 크기는 ∞이자만, 실제로는 CPU 비트 수에 따라 OS에 의해 적정 크기로 결정됨(참고).하지만 사용자의 성향에 따라 수동 조정도 가능함(참고).OS가 실행할 프로세스 외 프로세스를 스와핑(Swapping)하는 방식으로 구현되어 있음.주소 공간 분할 방식세그멘테이션(Segmentation) 개요 및 특징프로세스를 세그멘트(Segment)로 잘라서 메모리에 배치하는 방법.MMU는 Segment Table을 통해 DAT하여 각 프로세스의 논리 주소를 물리 주소로 변환함(참고: 1, 2).Segmentation Table이 아님!메모리의 가변적 분할+프로세스 내 각 영역의 메모리 접근 보호 용이성 vs. 외부 단편화DAT 과정 (참고: 1, 2, 3)프로세스가 코드를 실행해 필요한 명령어와 데이터의 가상 주소를 CPU에 전달함.CPU가 MMU에게 특정 논리 주소의 물리 주소 정보를 요청함.MMU가 Segment Table의 Base Address와 Bound Address를 통해 해당 가상 주소와 연결된 물리 주소를 찾음.MMU가 가진 STBR을 통해 S.T.의 물리 메모리상 시작 위치를 찾음.S.T.상 해당 프로세스의 가상 주소가 몇 번째 세그먼트에 위치해 있는지 찾음.세그먼트 테이블의 해당 인덱스로부터 찾은 Base Address와 Bound Address 값을 참고해 진행.가상 주소 값 < Bound Address 값이라면 Base Address 값+가상 주소 값으로 물리 주소 값을 알아냄.가상 주소 값 > Bound Address 값이라면 프로세스를 종료시킴.페이징(Paging) (참고: 1, 2, 3, 4)개요 및 특징프로세스의 논리 주소 공간을 페이지(Page) 단위로, 물리 주소 공간을 프레임(Frame)으로 자른 뒤 페이지를 프레임에 할당하는 가상 메모리 관리 기법(혼공컴운 403p.)페이지 테이블의 크기가 너무 커져서 메모리를 낭비하지 않도록 주의하는 것이 관건.메모리의 효율적 관리 vs. 내부 단편화DAT 과정 (참고: 1, 2, 3)프로세스 코드 실행 ... CPU의 특정 논리 주소의 물리 주소 정보 요청까지는 동일함.MMU가 Page Table을 통해 해당 가상 주소와 연결된 물리 주소를 찾음.해당 가상 주소의 Page Number 및 Offset을 통해 고유 Page Table에 접근함.Page Number = 가상 주소 / 페이지 크기, Offset = 가상 주소 % 페이지 크기PTBR을 통해 P.T.의 물리 메모리상 시작 위치를 찾음.S.T.상 페이지 번호로 프레임 번호를 찾고, 해당 프레임의 시작 주소에 Offset을 더해 변환함.페이지드 세그멘테이션(Paged Segmentation)개요 및 특징프로그램을 Segment로 나누고, 이를 Page들의 집합으로 구성하는 방식(참고).DAT 시 외부의 세그먼트 테이블과 내부의 페이지 테이블로 이루어진 두 단계 테이블을 이용함(참고).세그먼트 테이블 변경 사항보호 비트(Protection Bit) 추가(참고).Base Address -> Page NumberBound Address -> 해당 세그먼트의 페이지 개수Paging과 Segmentation의 장점 vs. 페이지 이중 참조로 인한 Overhead따라서, 현대 OS에서는 페이징과 페이지드 세그멘테이션을 혼용하여 사용함.DAT 과정 (참고: 1, 2, 3)프로세스 코드 실행 ... CPU의 특정 논리 주소의 물리 주소 정보 요청까지는 동일함.S.T.상 해당 프로세스의 가상 주소가 몇 번째 세그먼트에 위치해 있는지 찾음.영상에서 "0x12300 번지이니 1번 세그먼트구만!"이라는 설명은 예시일 뿐, 번지 수와 세그먼트 번호 간의 관계는 없음(참고).해당 세그먼트의 접근 권한 위반 여부 확인위반이라면 해당 요청을 한 프로세스를 Shutdown시킴.페이지 넘버를 통해 프레임 넘버를 가져 온 후, 해당 프레임으로 접근함.Invalid라면 Swap 영역에서 가져옴.해당 프레임의 시작 주소로부터 offset을 더해 원하는 데이터에 접근함(참고: 1, 2).  [Day 14]Algorithm메모이제이션(Memoization) (참고: 1, 2, 3)정의 및 특징함수 호출의 결과를 캐싱하고 동일한 입력이 다시 발생할 때 캐싱된 결과를 반환하는 하향식 접근(참고).공간 복잡도-시간 효율성 간 Trade-off 관계에 있음.계산 결과를 저장하기 위한 추가 메모리가 필요하지만, 일반적으로 중복 계산 제거로 얻는 시간 효율성(Time Effeciency)이 훨씬 높으므로 자주 활용됨.메모이제이션 예제: 피보나치 수열(참고).메모이제이션 없이 구현메모이제이션 활용해 구현Operating System입출력 장치(I/O Device)개요새로운 데이터를 받아들여서 중앙 처리기로 보내고 다시 처리 결과를 받아 알아볼 수 있는 형태로 바꾸어 주는 장치(참고).CPU와 메모리 버스에 직접 연결되지 않고, 간접적으로 연결되면 전부 I/O Device!(참고)유저가 시스템과 소통할 수 있게 하는 장치로, 다른 장치에 비해 처리 속도(=전송률)가 매우 느림.이를 보완하는 기술로 Buffering과 Spooling이 존재함(참고: 1, 2, 3).각 장치는 각자의 Device Controller를 통해 데이터를 보내고, I/O Bus를 통해 CPU를 거쳐 RAM에 도달함.DMA(Direct Memory Access)를 추가해 CPU 없이 I/O Controller가 Event 등 데이터를 RAM에 직접 전달하는 입출력 방식, 즉 Memory Mapped I/O로 확장됨(참고).각 Device의 공통 내부 구조 (※ I/O Device는 종류별, 브랜드별, 제품별로 내부 구조가 천차만별임)Device Controller (참고: 1, 2, 3)System Bus와 장치 사이에서 데이터를 송수신할 수 있도록 Interface 역할을 하는 장치.'해당 I/O 장치를 전담으로 처리하는 작은 전용 CPU 같은 존재'라 이해하면 좋음!(참고)CPU와 I/O Device 간 통신 중개, 오류 검출, 데이터 버퍼링 등의 역할을 수행함.장치 종류에 따라 장치 내부에 있을 수도, 외부(본체)에 있을 수도, 둘 모두에 분산되어 있을 수도 있음.장치의 위치보다 장치의 기능을 위주로 기억하는 것이 핵심!Buffer입출력 장치와 응용 프로그램 사이의 데이터를 임시로 저장하는 메모리 공간.일반적으로 이중 버퍼링, 즉 입력 버퍼와 출력 버퍼를 사용하는 방식이 일반적임.RegistersCPU가 장치 상태를 확인하거나 명령을 보낼 때 사용하는 메모리 공간.데이터 레지스터, 상태 레지스터, 제어 레지스터로 이루어져 있음(참고).데이터 전송 단위에 따른 분류 (※ 한 장치에서도 기능별로 달리 작동하는 기기도 있음) (참고: 1, 2, 3)캐릭터 디바이스(Character Device)정의 및 특징Fixed Size Block로 정보를 기록하는 장치로, Event의 순서가 상관없는 장치에 사용함.B.D.에 비해 데이터 전송 단위가 작음종류마우스(Mouse)정의 및 특징2차원 평면에서의 움직임을 컴퓨터에 전송하는 포인팅 디바이스의 일종.일반적으로 2차원 평면상에서 위치 정보(x, y)와 버튼 클릭 정보, 스크롤 동작 등을 전달함.현대 GUI 기반 OS에서 가장 대중적인 입력장치로 쓰이고 있음.Event 처리 및 전달 과정 (※ 커서 이동 기준)Ball Mouse사용자로부터 Event 발생Optical Mouse 키보드(Keyboard)블록 디바이스(Block Device)개요 및 특징C.D.에 비해 데이터 전송 단위가 큼종류HDD(Hard Disk Drive)정의 및 특징비휘발성, 순차접근이 가능한 컴퓨터의 보조 기억 장치(참고).여러 개의 플래터(Platter)가 회전하며 데이터를 저장하고 읽는 자기식 저장장치임.Flash MemoryCPU와 I/O Device 간 통신 과정MMID (※ 강의에 소개된 방식) PMID  [Day 15]Algorithm타뷸레이션(Tabulation) (참고: 1, 2, 3)정의 및 특징문제를 하위문제로 나눠 계산한 결과를 테이블에 저장한 후, 해당 테이블을 연산에 활용하는 상향식 접근(참고).메모이제이션은 계산 및 저장, 호출을 그때그때 하고, 타뷸레이션은 계산 및 저장을 먼저 해두고 나중에 한꺼번에 호출한다는 게 가장 큰 차이!재귀 호출을 하지 않으므로 공간 복잡도도 낮고, Call Stack 생성/제거 Overhead가 없어 T.E도 높음.반복문의 Overhead는 Loop Unrolling 등의 추가 최적화 여지가 있어 시간 효율성 측면에서는 반복문이 효율적임!단, 일부 상황(예: TSP)에서는 메모이제이션의 시간 효율성이 더 높을 수 있음.재귀적 풀이 과정이 더 가독성이 좋을 때, 계산 가능한 경우의 수에 비해 실제 연산에 쓰이는 연산값은 매우 적을 때 등구현하기타뷸레이션 예제: 피보나치 수열 Operating SystemFile System개요 및 특징 컴퓨터에서 파일이나 자료를 쉽게 발견 및 접근할 수 있도록 보관 또는 조직하는 체제(참고).파일 관리자가 Block 단위로 저장된 Block Device에 Byte 단위로 접근할 수 있도록 변환함. 파일 시스템의 기능파일 및 폴더 생성, 수정, 삭제파일 권한 관리무결성 보장백업 및 복구암호화(Encryption)File Descriptor개요 및 특징Process가 특정 파일에 접근할 때 사용하는 추상적인 값(참고).  [Week Review]일주일 동안 공부하면서 배우고 느낀 점독학으로 CS 공부를 하는 나름의 습관에 감이 잡힌 것 같다.마지막 주 시작을 지난주에 미처 다 이해하지 못한 메모리 분할 방식에 대해 공부하면서 시작했다. 처음엔 정말 이해가 가지 않았지만, 강의를 계속 반복 학습하고, 관련 자료를 찾아보고, 이해가 안 되면 ChatGPT와 충분한 질답을 주고받으면서 공부했다.위 일련의 과정에서 파편화된 지식을 계층적으로 재구성해 정리하는 방법, Hallucination이라는 태생적 한계를 지닌 LLM을 공부에 활용할 때 어느 정도로 참고해야 하는지, 신용할 만한 정보는 어디에 많이 있는지 등에 관한 감이 잡혔다.어려웠던 점강약 조절이 너무 어렵다...감자님 강의를 보면 해당 주제에 대한 감은 오지만 지식이 체계적으로 쌓이는 느낌은 들지 않는다. 이건 감자님 강의가 입문자들을 위한 쉬운 설명에 주안점을 두고 있어서 그런 거지 단점이 아니다. 오히려 나 같은 비전공자들로 하여금 '뭘 공부해야 하지?'에 대한 가이드를 준다는 점에서 최고다.근데 내 성격과 몸이 문제다. 지식을 대충 말고 제대로 정리하다 보니 끝이 없다. 이러다간 이번 주는 발자국을 제때 완성 못하고 스터디도 준비 못할 것 같다.어찌저찌 마무리했다... 휴... 원래 내 방식은 노트 정리를 탑다운으로 틀만 잡고 그 후부터는 바텀업으로 디테일을 계속 파고드는 스타일이었는데, 탑다운으로 강의 내용을 어느 정도(한 60% 정도?) 머릿속에 집어넣기 전까진 정리라는 행위를 하지 않기로 했다. 그 후에 머릿속에 있는 내용을 최대한 있는 대로 정리한 후에 바텀업으로 디테일을 파고들었다. 시간상 정리하지 못한 부분도 있긴 하나 머릿속엔 있기 때문에 반쯤 성공이라고 자축해 본다.향후 목표나만의 CS 완전 정복 로드맵 마스터하기이번 워밍업 클럽은 내 첫 CS 공부였다. 이전까지는 주먹구구식으로 그때그때 필요한 정보만 공부하다 보니 지식이 계속 휘발되는 느낌이었다. 그런데 이번 CS 공부를 하면서 오직 CS 하나만을 집중적으로 공부했다 보니 왜 CS 공부를 해야 하는지 그 이유가 분명해졌다.나는 언젠가 창업을 하고자 한다. 창업해서 서비스를 운영하려면 모르긴 몰라도 아득히 높은 수준의 갖은 능력이 필요하리라 여겨진다. 그러나 요즘은 K-MOOC나 KOCW, edX 등을 통해 전공 강의조차도 무료로 들을 수 있는 시대이니 느리더라도 꾸준히 멈추지 않고 나아간다면 분명 승산이 있다고 생각한다.워밍업 클럽 마무리 관련 소감워밍업 클럽 전반 관련네트워킹이 제대로 이뤄지지 못하고 각자도생하는 느낌이어서 아쉬웠다. 워밍업 클럽이 '특정 목표를 가진 사람들을 모아놓자' 딱 거기에 의의가 있는 프로그램이라면 할 말 없지만, 운영 쪽에서 개별 스터디를 장려하는 유인(스터디 과정 제출 시 가산점, 놀러 와서 커피 쿠폰 뿌리고 가기 등)이 있었다면 훨씬 좋았을 것 같다.감자님 강의 관련 (※ 대문자 T 주의해 주세요 감자님 ㅠㅠㅠ 나쁜 마음은 없습니다ㅠㅠㅠㅠㅠㅠㅠ)자료구조 및 알고리즘 강의는 만점을 줘도 아깝지 않은 강의였다고 생각한다. 자료구조이나 알고리즘 모두 시각화가 정말 중요하다고 생각하는데, 단순히 달달 외우는 게 아니라 생각할 수 있는 힘을 기르게 해주신 훌륭한 강의였던 것 같다.운영체제 강의는 아쉬움이 남는다. (내게 이런 평가를 내릴 만큼의 지식이 있기는커녕 그 1%도 안 되지만) 내용상 잘못 설명하신 부분이나 실제로는 다르지만 같다고 퉁치고 넘어가는 내용들이 가끔 있었다. 나만 해도 지난 3주 동안 강의의 큰 오류를 2개나 찾았다. 강의 수강 대상자가 입문자라면 쉬운 설명만큼이나 내용의 정확성도 중요하다고 생각한다. 초보들은 처음 배운 지식을 수정하기가 매우 어렵기 때문이다.스터디 관련1주차부터 2주차, 그리고 오늘까지 CS 스터디를 모집해 운영해 왔다. 매주 일요일 2시에, 워밍업 클럽 일정대로 공부한 내용을 공유하는 스터디였는데 이탈률도 높고 남은 사람들의 참여율도 저조했다. 더 이상 말은 안 하겠지만... 많이 실망스러웠다.그래도 공유해야 할 내용이 있는 만큼 내가 이해한 내용을 하나라도 더 매끄럽게 설명할 수 있게 노력한다든지, 정확한 내용이 맞는지 더블, 트리플, 쿼드러플 체크를 반복했던 점은 좋았다. 혼자 공부할 때도 늘 그렇게 하고 있었다는 게 문제지만.나 자신 관련우선 나 자신에게 고생했다고 말하고 싶다. 어찌 됐건 수료를 했으니까. 얻은 것들도 무수히 많고. 무엇보다 막연하기만 했던 'CS란 뭘까?'에 대한 해답과 '비전공자인 내가 CS를 감히 도전해도 될까?'에 대한 해답을 얻은 게 긍정적이다.하지만, 개인적으로 내가 나에게 느꼈으면 하는 감정은 답답함과 공포였다. 근데 둘 모두 전혀 없다. '비전공자여도 전공자들을 찍어누를 만큼의 지식과 경험, 능력을 갖고 싶다'는 다소 허황된 꿈이 여기서 현실로 다가왔어야 했는데... 아쉽다.

알고리즘 · 자료구조알고리즘운영체제

강동훈

[인프런 워밍업 클럽 3기 - CS] - 3주차 발자국(자료구조와 알고리즘)

💻 알고리즘 📌 삽입 정렬- 정렬된 영역과 정렬되지 않은 영역을 나누어, 정렬되지 않은 영역의 첫 원소를 정렬된 원소와 비교하여 올바른 위치에 삽입- 성능이 아쉬움(O(n^2))📌 병합 정렬분할 정복(divide and conquer): 해결하기 쉬울 정도로 문제를 쪼갠 후 하나씩 해결- 재귀를 통해 정렬- 배열을 더 이상 나눌 수 없을 때까지 쪼개고 병합하면서 정렬- 시간 복잡도 (O(nlogn))📌 퀵 정렬- 분할 정복 알고리즘 중 하나- 재귀를 사용- 배열 중 하나를 '피봇(pivot)'으로 설정- 배열의 시작: left / 끝: right index값 저장- 값 비교 인덱스: leftStartIndex / rightStartIndex- leftStartIndex > pivot && rightStartIndex < pivot 일 경우 멈춰서 값 교환- 인덱스가 만나면 멈추고 피봇을 rightStartIndex랑 변경- 재귀- 시간 복잡도 (O(nlogn)) / 최악의 경우 (O(n^2))- 병합 정렬보다 더 적은 메모리 사용으로 더 좋은 알고리즘이라고 판단📌 동적 프로그래밍 - 메모이제이션피보나치 수열- 이전 두 수를 무한하게 더하는 수재귀 함수를 실행하면서 중복되는 부분이 무수히 발생한다.- 계산 결과를 저장하고, 중복되는 계산은 저장된 값을 불러온다.- 속도가 빠른 대신, 메모리 공간 차지가 많아진다.function fibonacci(n) { if (n == 0 || n == 1) return n; return fibonacci(n - 1) + fibonacci(n - 2); } function fibonacci2(n, memo) { if (n == 0 || n == 1) return n; if (memo[n] == null) { memo[n] = fibonacci2(n - 2, memo) + fibonacci2(n - 1, memo); } return memo[n]; } console.time("first fibonacci"); console.log(fibonacci(40)); console.timeEnd("first fibonacci"); console.time("second fibonacci"); console.log(fibonacci2(40, {})); console.timeEnd("second fibonacci"); //102334155 //first fibonacci: 867.412ms //102334155 //second fibonacci: 0.073ms 📌 동적 프로그래밍 - 타뷸레이션상향식 계산 방식으로 계산에 필요한 모든 값을 전부 계산 후 테이블에 저장- 적은 메모리 사용 + 빠른 시간- 해결하기 힘든 문제를 하향식으로 접근하여 메모리를 이용하여 빠르게 문제 풀이: 메모이제이션- 직관적이지 못한 재귀, 상향식 접근이 필요: 타뷸레이션 📔 회고🚀 최종 목표 : 로드맵을 마무리하고 알고리즘 문제들을 제대로 이해할 수 있을 정도의 수준이 되기.🚀 매주 규칙:각 섹션마다 하나의 .md 파일을 생성하고, 섹션 내 각 유닛은 헤더로 구분강의를 듣고 최대한 이쁘게 (?) 정리해놓기매 강의를 듣고 궁금하거나 이해가 안가는 부분은 추가적으로 더 찾아서 정리해두기강의에 관련된 알고리즘 최소 1문제씩 풀어 습관화 GPT를 통해 여러 문제를 리스트업하고 최적의 자료구조나 알고리즘을 맞춰보기 이번 인프런 워밍업 클럽을 진행하면서 커리큘럼에 맞춰 매일 강의를 듣고 지키려고 하였던 나의 목표 및 규칙이다.규칙부터 살펴보자면,각 섹션마다 하나의 .md 파일을 생성하고, 섹션 내 각 유닛은 헤더로 구분 : 10 / 10강의를 듣고 최대한 이쁘게 (?) 정리해놓기 : 8 / 10매 강의를 듣고 궁금하거나 이해가 안가는 부분은 추가적으로 더 찾아서 정리해두기: 6 / 10강의에 관련된 알고리즘 최소 1문제씩 풀어 습관화  : 9 / 10GPT를 통해 여러 문제를 리스트업하고 최적의 자료구조나 알고리즘을 맞춰보기 : 7 / 10매 강의를 듣고 섹션별, 유닛별로 모든 내용을 정리하여 저장하였으니 10점을 주었다.강의를 듣고 최대한 이쁘게 정리를 하려고 노력하였지만 2점이 감점된 이유는 시간이 지날 수록 점점 이모지 사용이 줄고 글간, 행간과 같은 사소한 부분을 신경쓰지 않게 된 것같다,, 그래도 이 노력을 통해서 일관된 템플릿을 형성할 수 있었다는 점, md파일로 매일 정리해보며 파일 정리에 조금 익숙해진 것 같다.자료구조 강의는 이론적인 부분이 많아, 찾아볼 자료 혹은 더 공부해 볼 부분이 많이 존재하였지만 알고리즘은 이론보다 실전이 더 중요한 부분이라 궁금한 점 보다는 이해가 안가는 부분을 반복해보며 익숙해지려 노력하였다. 결국, 강의를 들으면서 궁금한 점이 많지 않아서 직접 찾아보려고 한 노력들은 적었기에 6점을 주었다. 스스로 피드백을 주자면, 배운 알고리즘이 어느 문제들에서 유용한 지, 혹은 더 개선된 버전의 알고리즘이 있는지 찾아봤으면 더 좋지 않았을까,, 라는 생각이 든다.강의를 듣고 강의에 관련된 알고리즘 문제를 쉬운 문제라도 최소 하나는 매일 풀어봤던 것 같다. leetcode를 통해서 문제를 찾았고 첫 번째는 효율성을 따지지 않고 스스로 풀어보고, 두 번째는 효율성을 개선할 부분을 찾아 수정하였고 마지막은 더 효율적인 코드가 있는지 다른 코드를 찾아보며 알고리즘 문제에 익숙해지려 하였다. 1점이 감점된 이유는 대부분 하루에 한 문제씩만 풀었다는 아쉬움과 게으름의 후회,,이 부분이 진행하기 가장 어려웠던 것 같다. 아직 기본적인 수준의 자료구조와 알고리즘만 배운 상태이기 때문에 제대로된 답변을 하지 못하는 경우가 많았고 설명을 들어도 잘 이해가 가지 않는 경우가 많았다. 이게 오히려 투지를 불태우긴 하였지만 아직까지는 아쉬운 부분이 커서 7점을 주었다. 하지만 계속해서 반복하다보면 새로운 개념들에 점차 익숙해질 수 있고 알고리즘 공부와 꾸준히 이어서 하면 큰 시너지를 낼 수 있을 것 같다.그래서 최종 목표는로드맵을 마무리하고 알고리즘 문제들을 제대로 이해할 수 있을 정도의 수준이 되기 : 6 / 10알고리즘 문제를 풀거나, GPT를 통해 여러 문제에 대한 효율적인 자료구조를 대답해봐도 아직 내가 어느정도 성장했다고 느끼지는 못하였다. 자료구조와 알고리즘은 확실히 이론을 공부하는 것보다는 반복적인 연습과 실습이 중요하다라는 것을 다시 한 번 더 깨달은 것 같다. 알고리즘 공부 또한 꾸준히 해나갈 것이고 매일 최소 한 문제씩 풀어가면서 성장을 위해 필요한 최소의 연습양을 채우면서 점차 내가 원하는 수준의 알고리즘 문제 풀이 실력까지 높여가고 싶다.

알고리즘 · 자료구조자료구조알고리즘인프런워밍업감자

수뼈

인프런 워밍업 클럽 스터디 3기 - CS 전공지식 <둘째 주 발자국>

[Day 06]Algorithm재귀(Recursion): 어떠한 것을 정의하는 과정에서 자기 자신을 참조하는 것.재귀함수(Recursive Function)을 구현할 때 탈출 조건(기저 조건)을 정의해놓지 않으면 콜 스택(Call Stack)에 스택 프레임(Stack Frame)이 무제한으로 쌓이게 되어 사용이 불가능함.Stack Overflow: Call Stack이 메모리의 잉여 용량을 초과하여 프로세스가 OS에 의해 강제 종료되는 현상.재귀함수를 사용할 때 쉽게 해결 가능한 문제: Factorial(n)재귀함수를 사용할 때 쉽게 해결 가능한 문제: 깊이 우선 탐색(Depth-First Search; DFS)(참고: 1, 2, 3)Operating System 프로세스 간 / 프로세스 내 통신프로세스 간 통신(Inter-process Communication; IPC) (참고: 1, 2, 3)개요운영체제가 주체가 되어 프로세스 간 통신​ 프로세스들끼리 서로 데이터를 주고받는 것.기본적으로 각 프로세스는 독립적이기에 명시적으로 통신 매개체를 만들어주지 않으면 통신이 불가능함.파일, 파이프, 메세지, 네트워크 등 다양한 매개체를 통해 통신하는 다양한 방식이 있음.여러 프로세스가 공유 자원에 접근한다면 동기화 문제가 생길 수 있으므로 해결이 필요함.정보 공유,계산 가속화,모듈성,편의성 등을 도모하기 위해 활용되는 기술임.통신 방식에 따른 분류공유 메모리(Shared Memory) 방식 (참고: 1, 2, 3)개요여러 프로세스가 공동으로 사용할 수 있는 가상 메모리 영역을 활용해 통신하는 방식.모든 IPC 방식 중 가장 통신 속도가 빠르다는 장점과 동기화 문제가 생기기 쉽다는 단점이 있음.대표적인 활용 예시로 복붙이 있음(예: 워드의 텍스트를 인터넷 창에 가져오기).일반적인 순서UNIX 계열부모 프로세스 생성 및 가상메모리 영역 할당.부모 프로세스가 자신에게 할당된 메모리 영역 중 일부를 공유 메모리로 사용하겠다고 커널에 요청.커널이 프로세스가 접근 가능한 고정 길이의 공유 메모리 영역을 생성 및 할당해 줌.고정 길이라는 점을 왜 강조하신 걸까? -> 왜 용량 할당 기준이 다른 걸까?(참고) 메모리 할당 방식과 동기화 문제 발생 가능성의 차이 때문임.fork() 함수로 자식 프로세스 복제(이때 공유 메모리 주소도 복사됨).프로세스 동기화(Process Synchronization) (※ 병형 제어(Concurrency Control)라고 부르기도 함) (참고: 1, 2, 3)정의 및 특징프로세스 접근 순서 및 방식을 OS의 동기화 메커니즘을 사용하여 조정하는 것.각 프로세스가 공유 자원에 접근하는 순서는 시분할 CPU 스케줄링을 하는 OS만 알고 있으므로, OS 단위로 해결할 수밖에 없음.대부분의 프로세스 동기화 방법은 상호 배제(Mutual Exclusion) 메커니즘의 일부 또는 전부에 기반함.공유 메모리 방식에서 가장 발생하기 쉬운 문제지만, 다른 방식에서도 얼마든지 발생할 수 있는 문제.동기화 문제 해결 방법 (Deadlock 해결 방법은 Day 07 참조)Race Condition 해결 방법뮤텍스(Mutex) (참고: 1, 2, 3)추가 예정.세마포어(Semaphore) (참고: 1, 2, 3)개요 및 특징멀티프로그래밍 환경에서 Critical Section에 동시에 접근할 수 있는 프로세스의 최대 개수를 제한하기 위해 사용되는 정수형 변수(링크 내 정의를 참고해 보강함).뮤텍스와 달리 Critical Section에 접근 가능한 프로세스 개수를 2개 이상으로 지정할 수 있다는 게 차이점!뮤텍스=열쇠(잠긴 동안 누구도 못 감), 세마포어=미리 발급된 n개의 출입증(다 떨어진 순간 못 들어감)이 더 좋은 비유라고 생각함.사용법 자체는 쉽지만 wait() 함수와 signal() 함수를 잘못 사용하면 꼬일 수 있음(참고).활용 방법wait() 함수로 세마포어의 수를 1 줄여 프로세스 하나가 Critical Section에 들어갔음을 OS에 전달함.이때 이미 세마포어가 0이라면 이후 코드는 실행되지 않음.코드를 진행하다 signal() 함수를 만나면 세마포어의 수를 1 늘려 프로세스 하나가 Critical Section에서 나갔음을 OS에 전달함.모니터(Monitor) (참고: 1, 2, 3)개요 및 특징공유 자원에 대한 동시 접근을 안전하게 제어하기 위해 상호 배제와 조건 변수를 결합한 고수준의 동기화 기법(by ChatGPT o3-mini-high)프로그래밍 언어 차원에서 여러 프로세스에서 동시에 실행될 수 없는 함수를 만드는 방식으로 구현함.파이프(Pipe) 방식개요OS가 각 프로세스와 연결된 단방향 통신용 메모리 공간(=Circular Buffer)을 생성해 데이터를 전달함.기본적으로는 바이트스트림(Bytestream) 데이터만 전달 가능하며(참고: 1, 2, 3), 다른 데이터타입을 전달하려면 직렬화(Serialization)해야 함. Anonymous Pipe부모-자식, 형제 등 통신 대상이 정해진 두 프로세스가 단방향 통신(Half Duplex)할 때 사용함(예: fork()).양방향 통신(Full duplex)을 위해선 익명 파이프가 두 개 필요한데, 이는 구현이 복잡함.Named PipeAnonymous Pipe가 확장된 형태로, 파일 시스템에 이름이 부여된 파이프를 말함.FIFO라는 통신을 위한 파일을 만들고, 그걸 통해 양방향 통신(Full duplex)이 가능함.메세지 큐(Message Queue)네트워크 방식소켓RPC스레드 간 통신(Inter-thread Communication; ITC)데이터 영역에 있는 전역 변수(=공유 메모리)나 힙을 이용해 통신함."전역 변수보단 공유 메모리라는 명칭을 선호한다." - 곰책으로 쉽게 배우는 최소한의 운영체제론  [Day 07]Algorithm Recursive Thinking재귀라는 테크닉을 제대로 활용하려면 하향식(Top-down) 계산식으로 문제를 변형할 수 있어야 함.하향식 계산 활용 1: 배열 각 원소의 총합 구하기하위 문제: arr.length === n-1인 배열 각 원소의 총합 구하기 + 마지막 원소하향식 계산 활용 2: 문자열 길이 계산하기하위 문제: str.length === n-1인 문자열의 갯수 구하기 + 1하향식 계산 활용 3: 지수함수 계산하기하위 문제: n^m-1 * nOperating System교착 상태 제어(Deadlock Control)Deadlock: 두 개 이상의 프로세스가 서로가 가진 자원의 해제를 기다리며 무한 대기하는 상태.Deadlock의 필요조건 (넷 중 하나라도 빠지면 Deadlock이 발생·유지되지 못함)상호 배제(Mutual Exclusion), 비선점(No Pre-emption),점유와 대기(Hold and Wait),원형 대기(Circular Wait)Deadlock 해결 방안 (참고: 1, 2, 3)Deadlock Prevention (참고: 1, 2, 3)교착상태가 애초에 일어나지 않도록 Deadlock 필요조건 중 하나를 제거하는 것.이론적으로만 가능하고 현실적으로 불가능하거나(상호 배제 및 비선점), 유저 사용성과 시스템 유연성을 해치게 되므로(점유와 대기,원형 대기) 현실적으로 적용 불가함.Deadlock AvoidenceOS가 시스템 자원과 프로세스들의 현재 할당 자원 및 최대 요구 자원을 종합적으로 고려해 시스템이 되도록 안정 상태(Safe State)를 유지할 수 있는 만큼만 시스템 자원을 할당하는 것.각 메모리의 최대 요구 CPU 리소스는 어떻게 아는 걸까?(참고) 추정치가 아니라 상한선이다!비용이 비싸고, 비효율적이라는 단점교착상태 검출가벼운 교착상태 검출프로세스가 정해진 시간 동안 작업을 진행하지 않는다면 OS가 이를 교착상태로 판단함.교착상태가 되면 가장 최근의 Checkpoint로 프로세스 상태를 되돌림.오버헤드가 적지만 멀쩡한 프로세스를 롤백해버릴 수 있음.무거운 교착상태 검출OS가 자원 할당 그래프를 지속적으로 관찰하다가 원형 대기 상태를 발견하면 이를 교착상태로 판단함.교착상태가 되면 가장 최근의 Checkpoint로 프로세스 상태를 되돌림.멀쩡한 프로세스를 롤백할 일이 없지만 오버헤드가 큼. [Day 08]Algorithm 하노이의 탑(The Tower of Hanoi) 1883년 프랑스의 수학자 Édouard Lucas가 처음으로 발표한 게임으로, 재귀함수 예제로 활용됨.하향식(Top-down) 접근가장 큰 원반을 기둥 3으로 옮기기 -> 나머지 원반을 기둥 2로 옮겨야 함그보다 작은 원반을 기둥 3으로 옮기기 -> 더 작은 나머지 원반을 기둥 2로 옮겨야 함 (이게 하위문제!)구현하기첫 번째 구현: 강의 보며 구현 (Done) 두 번째 구현: 강의 안 보고 구현하다 기억 안 나면 과거에 내가 짠 코드 확인하며 구현 (Done) 세 번째 구현: 리팩토링 (원반 이동 횟수 출력, 원반 이동 On/Off 기능 추가) (Done) 마지막 구현: 익숙한 파이썬으로 구현(+리팩토링) (Done) Operating System컴파일과 프로세스Compile: 소스코드가 실행파일(=프로그램)이 되는 과정 (※ 아래 과정은 C 기준) (참고: 1, 2)Preprocessing,Compile, Assembly, Linking 순으로 진행하여 .exe 파일, 즉 실행 파일이 생성됨.코드 영역과 데이터 영역으로 이루어진 .exe 파일 실행 시 프로세스 생성됨. [Day 09]Algorithm정렬 알고리즘(Sorting Algorithm)개요데이터셋이 주어졌을 때, 이를 사용자가 지정한 기준에 맞게 정렬하여 출력하는 알고리즘.참고: 정렬 알고리즘은 왜 배워야 할까?대표적인 정렬 알고리즘버블 정렬(Bubble Sort) (※ Sinking Sort라고도 함)배열의 정렬되지 않은 영역에서 서로 인접한 두 원소 크기가 순서대로 되어 있지 않으면 서로 교환하는 방식으로 모든 원소를 정렬하는 알고리즘.최악의 경우, O(n^2)의 시간복잡도를 가짐.구현하기첫 번째 구현: 강의 보며 구현 (Done)두 번째 구현: 강의 안 보고 구현하다 기억 안 나면 강의 확인하며 구현 세 번째 구현: 강의 안 보고 구현하다 기억 안 나면 과거에 내가 짠 코드 확인하며 구현 네 번째 구현: 아무것도 안 보고 구현 마지막 구현: 익숙한 파이썬으로 구현(+ 리팩토링) 선택 정렬(Selection Sort)배열의 정렬되지 않은 영역의 첫 번째 원소를 시작으로 마지막 원소까지 비교 후 가장 작은 값을 첫 번째 원소로 가져오는 알고리즘.최악의 경우, O(n^2)의 시간복잡도를 가짐.구현하기첫 번째 구현: 강의 보며 구현 (Done)두 번째 구현: 강의 안 보고 구현하다 기억 안 나면 강의 확인하며 구현 세 번째 구현: 강의 안 보고 구현하다 기억 안 나면 과거에 내가 짠 코드 확인하며 구현 네 번째 구현: 아무것도 안 보고 구현 마지막 구현: 익숙한 파이썬으로 구현(+ 리팩토링) Operating System메모리의 종류휘발성 메모리(Volatile Memory)종류 및 특징Register (참고: 1, 2, 3)개요 및 특징CPU 내부에서 처리할 명령어나 연산의 중간 결과값 등을 일시 저장하는 임시 기억장치.CPU 내부에는 다양한 종류의 레지스터가 있음(각 레지스터의 종류와 특징은 후술).CPU가 연산해야 할 데이터를 RAM에서 가져와 여기에 저장한 후에 연산을 시작함.Register의 크기가 32bit인지 64bit인지에 따라 CPU 종류가 달라짐.종류와 특징재배치 레지스터(Relocation Register)논리 주소를 물리 주소로 변환하는 데 사용되는 레지스터.프로그램을 다른 메모리 위치로 이동해도 주소 수정 없이 실행 가능함.Cache Memory (참고: 1, 2, 3)CPU와 메인 메모리 간 데이터 접근 속도의 차이를 최소화하기 위해 사용되는 CPU 내 고속 임시 저장소(by ChatGPT-o3-mini-high).속도와 용량에 따라 Level 1, Level 2, Level 3 Cache로 세분화되어 탑재되어 있음(시스템마다 다름).CPU가 자주 사용할 만한 데이터를 RAM에서 미리 가져와놓고(=Caching), CPU가 필요할 때 RAM보다 우선적으로 접근함.Cache Hit이 많으면 시스템의 성능이 올라가겠지만 Cache Miss가 많으면 추가 Latency가 발생해 오히려 Cache Memory가 없는 시스템보다도 시스템의 성능이 떨어질 수 있음.따라서 Cache Hit Ratio를 향상시키는 게 중요함(향상 기법 설명).RAM(Random Access Memory) (참고: 1, 2, 3, 4)개요 및 특징CPU가 즉각적으로 접근할 수 있으며, 프로그램 실행과 데이터 처리를 위해 일시적으로 명령어나 데이터를 저장하는 휘발성 메모리 장치(by ChatGPT 4.5).Stack, Heap, Code, Data 영역으로 구성되어 있어 각 영역이 가상 메모리(Virtual Memory)를 통해 각 프로세스에 할당됨.CPU에서 직접 접근이 가능한 유일한 저장 장치임.RAM의 종류RAM의 구성요소OS의 RAM 관리 방법메모리의 주소 공간(Address Space) (참고: 1, 2, 3, 4)관리의 최소 단위를 주소(Address)라 하며, 1 byte(8 bits)의 크기를 가짐.1 byte 단위마다 지정된 각 주소는 편의상 0x??????(16진수)로 표시됨(참고).RAM에서는 논리(가상) 주소와 물리(절대) 주소로 주소 공간을 분리하여 관리함.왜 이렇게 구분? OS 영역 침범 방지 + 메모리 관리의 편의성물리 주소(Physical Address) (※ 절대 주소(Absolute Address)라고도 함) (참고)CPU 관점에서 바라 본 실제 HW상 주소 공간으로, CPU 속 MMU가 논리 주소를 물리 주소로 변환하여 접근함(참고).경계 레지스터(Boundary Register)가 유저 프로세스가 RAM의 커널 영역을 침범하는지 감시하다가, 침범했다면 강제 Shutdown시킴(참고).논리 주소(Logical Address) (※ 가상 주소(Virtual Address)라고도 함)각 유저 프로세스 관점에서 바라 본 주소 공간으로, 각 주소마다 0x0부터 시작함.각 프로세스마다 새로 할당되므로 시스템 전체(OS) 관점에서 보면 같은 주소가 여러 개 존재할 수 있음.OS 영역과 유저 영역으로 구분되어 있음.OS는 프로세스 생성 및 메모리 할당 시 가상 주소-물리 주소쌍이 담긴 페이지 테이블(Page Table)을 만들어 RAM에 저장함(참고).프로세스 실행 시 CPU는 P.T의 맵핑 정보를 참고하여 명령어나 데이터를 참조함.상대 주소(Relative Address)는 프로세스 내에서 특정 주소 기준으로 얼마 떨어진 주소를 가리킬 때 사용하는 개념으로, 강의에서의 설명과는 소폭 다름(참고).메모리 할당 방식 (참고: 1, 2, 3)개요RAM의 빈 물리 주소 공간에 각 프로세스의 가상 주소 공간을 할당·관리하는 방법.연속적인 Swapping, Context Switching 상황에서도 최소한의 빈 공간과 Overhead를 유지하는 것이 메모리 할당 방식 연구의 목표.메모리 오버레이(Memory Overlay) (참고: 혼공컴운 391p., 2, 3, 4, 5)프로그램을 여러 개의 독립된 모듈로 나누고, 한 번에 필요한 모듈만 메모리에 적재하여 실행하는 방식(참고).Manual Overlay에서 Dynamic Loading과 Dynamic Linking으로 발전함.위 기술들은종류가변 분할각 프로세스에 메모리를 프로세스 크기만큼 연속 할당하는 방식.외부 단편화로 인한 Overhead 발생고정 분할각 프로세스에 메모리를 특정 크기만큼 연속 할당하는 방식.구현이 쉽고 오버헤드가 적다 vs. 내부 단편화 발생버디 시스템짬뽕비휘발성 메모리(Non-volatile Memory)Secondary Memory (참고: 1, 2, 3)  [Day 10]데이터 지향 설계(Data-Oriented Design) (참고: 1, 2, 3)소프트웨어를 설계할 때 데이터 자체와 그 흐름에 초점을 맞추어, 프로그램의 성능과 메모리 사용 효율을 극대화하는 방법론(by ChatGPT-o3-mini-high).프로세서 캐시(cache) 효율을 높이고, 불필요한 메모리 접근 오버헤드를 줄이며, 데이터 처리 속도를 극대화하는 것이 목표.데이터를 배열에 담아 특정 인덱스 데이터를 호출하면 Cache Locality에 따라 해당 인덱스와 인접한 데이터들이 캐시 메모리에 올라감.CS를 공부하면 새로운 라이브러리/프레임워크를 배우기 쉽다.https://dev.epicgames.com/community/fortnite/getting-started/uefn [Week Review]일주일 동안 공부하면서 배우고 느낀 점감자님의 운영체제 강의는 너무 좋다. 눈에 쏙 들어오고 이해도 잘 된다. 하지만 엉성하게 감이 잡힌 상태에서 그 이상을 궁금해하기 시작하면 지옥이 펼쳐진다....예를 들어 (이후에 나오는지는 모르겠지만) IPC는 강의에서 주로 다룬 공유 메모리 방식 말고도 파이프 방식도 있는데, 이에 대해 검색하니 뭐 데이터스트림이라느니 Message Passing 방식이라느니 알 수 없는 내용들이 쏟아진다.이 강의(워밍업 클럽)로 큰 줄기를 그린 다음 오랜 기간에 걸쳐 꾸준히 학습하며 디테일을 채워 나가야겠다. 나는 비전공자인데다, 머리도 나쁘고, 근육병에, 기초수급자에다, 남들은 당분간 알아주지 않을 길을 오래 걸어가야 하니까.자료구조 및 알고리즘을 공부하니 프로그램 설계 능력 향상에도 도움이 되는 것 같다.잡식으로 필요한 것 혹은 필요해 보이는 기술 같은 것들만 공부하며 버텨온 시간들을 뒤로 하고 내실을 다지고자 별 기대 없이 시작한 워밍업 클럽인데, 의외로 소프트웨어 설계에 큰 도움이 되는 듯하다.이번 주 중간점검 때는 질문할 게 별로 없었다. 궁금한 게 없어서가 아니라 뭐부터 질문해야 할지 모를 정도로 머릿속이 혼란스러운 게 첫째, 궁금한 것들이 대부분 감자님 강의에 없는 내용들이라는 점이다.어제 중간점검 때 감자님께서 "강의 내용 정도면 컴공 전공자들이 배우는 지식과 크게 다르지 않다."고 말씀하셨는데, 내가 전공자가 되어보진 않았어도 "그건 아니다."라고 단언할 수 있다. 내 목표가 전공ㅈ어려웠던 점(참고) IPC 부분을 조금 깊이 파고들다 보니 강의에 설명되지 않은 부분이 정말 많아서 혼란이 심했다.특히 Process Synchronization 문제와 그 해결 방식들에 대해 공부한 후에, "그래서 저 수많은 IPC 방법들 중 Process Synchronization 문제는 어떤 방법을 쓸 때 발생하는 거지?"가 헷갈렸다.감자님 답변으로 "어떤 방법을 쓰는가보다는 공유자원의 존재 유무로 동기화 이슈가 발생할 수 있다"는 걸로 대강 이해했다.(참고) 동기화 부분을 정리하면서 강사님께서 말씀하시는 동기화 문제가 공유 메모리 방식에서 주로 발생하는 것 같다고 이해했다. 근데 다른 강사님의 강의에서 "파일 기반 IPC는 OS가 필요한 용량을 할당해줄 때 기준이 느슨한데, 메모리 기반 IPC는 OS가 필요한 용량을 할당해줄 때 기준이 엄청 깐깐하다."는 말이 나왔고, 왜 그런 차이가 나는지 궁금해져서 질문을 올렸다.답변에 틀린 부분은 없었지만 뭔가 명쾌한 느낌도 아니었다. 그래서 챗지피티에게 물어보니 메모리 할당 방식과 동기화 문제 발생 가능성을 이유로 설명했다. 이 답변을 바탕으로 정리에 두었더니 훨씬 명확해졌다.IPC를 공부할 때 통신 과정을 순서대로 정리해두니 확 이해도 되고 머릿속에 남는 것 같다!앞으로 개선할 점아무리 열심히 공부하기 위한 목적이라지만... 이거 공부 및 정리에 너무 많은 시간을 쓰고 있다. 기본적인 걸 무조건 끝내놓고 남는 시간에 내용 보충을 해야겠다. 기타 잡담강의 보면서 웃겼던 부분ㅋㅋㅋㅋㅋㅋ 빌린 돈도 안 갚아놓고 더 빌려 달라니 뭔 심보여

알고리즘 · 자료구조알고리즘운영체제

찬우 이

인프런 워밍업 클럽 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 < n - 1; i++) { // 전체 반복 횟수 for (let j = 0; j < n - 1 - i; j++) { // 점점 줄어드는 비교 범위 if (arr[j] > 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 < n - 1; i++) { let minIndex = i; // 현재 정렬된 부분 이후에서 가장 작은 값의 인덱스 저장 for (let j = i + 1; j < n; j++) { // i 이후 요소들과 비교 if (arr[j] < arr[minIndex]) { minIndex = j; // 더 작은 값이 발견되면 minIndex 갱신 } } // 최소값을 현재 위치(i)와 교환 (swap) if (minIndex !== i) { [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]; } } return arr; } let arr = [5, 3, 8, 4, 2]; console.log(selectionSort(arr)); // [2, 3, 4, 5, 8] 배열영역의 첫 번째 원소를 시작으로 마지막 원소까지 비교 후 가장 작은 값을 첫 번째 원소로 가져온다.버블정렬과 같은 경우로 구현하기는 쉽지만 성능면(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

강동훈

[인프런 워밍업 클럽 3기 - CS] - 2주차 미션 (자료구조와 알고리즘)

재귀함수에서 기저조건을 만들지 않거나 잘못 설정했을 때 어떤 문제가 발생할 수 있나요?재귀함수는 함수 내부에서 자기 자신을 다시 호출하여 작업을 수행하는 함수를 의미한다. 즉, 자기 자신을 무한대로 호출하여 작업하기 때문에 함수 종료 조건인 기저조건을 설정하지 않는다면, 해당 함수가 실행됨에 따라 무한대로 콜스택에 메모리가 얹히게 되고 스택 오버플로우가 발생하여 프로그램이 강제 종료된다.// 기저 조건 없는 경우 function factorial(n){ return n * factorial(n - 1) } // RangeError : Maxmum call stack size exceeded // 기저 조건 설정 function factorial(n) { if (n == 0) return 1; return n * factorial(n - 1); }0부터 입력 n까지 홀수의 합을 더하는 재귀 함수를 만들어보세요.하위조건 : n - 1이 홀수인지 확인하고 홀수일 경우 n을 더하고 짝수일 경우 0을 더함기저조건: n이 0 이하일 경우 0을 반환하고 함수 종료function sumOdd(n){ // 재귀 로직 if (n <= 0) return 0; let oddNum = n % 2 === 0 ? 0 : n; return oddNum + sumOdd(n - 1); } console.log(sumOdd(10)) // 25다음 코드는 매개변수로 주어진 파일 경로(.는 현재 디렉토리)에 있는 하위 모든 파일과 디렉토리를 출력하는 코드입니다. 다음 코드를 재귀 함수를 이용하는 코드로 변경해보세요.const fs = require('fs'); // 파일을 이용하는 모듈 const path = require('path'); // 폴더와 파일의 경로를 지정해주는 모듈 function traverseDirectoryRecursive(directory) { const files = fs.readdirSync(directory); // 1. 인자로 받은 폴더 내부 파일들 추출 for (const file of files) { const filePath = path.join(directory, file); // 2. 파일 경로 합치기 const fileStatus = fs.statSync(filePath); // 2. 파일 정보 얻기 if (fileStatus.isDirectory()) { // 3-1. 폴더일 경우 재귀 console.log('디렉토리:', filePath); traverseDirectoryRecursive(filePath); } else { // 3-2. 파일일 경우 출력 console.log('파일:', filePath); } } } traverseDirectoryRecursive('.'); // 현재 경로의 모든 하위 경로의 파일, 디렉토리 출력하위 조건:인자로 받은 Directory의 파일과 폴더를 읽어온다파일 경로를 합치고 파일 정보를 얻어온다폴더일 경우, 재귀함수를 통해 내부 폴더의 파일과 폴더를 읽는다파일일 경우, 파일을 출력한다.기저조건:현재 폴더 내부 모든 파일 수만큼 반복📔 회고알고리즘 문제가 아닌 실전에서 사용할 수 있는 재귀 함수로 응용을 해보니 생각보다 하위조건을 파악하고 기저조건을 설정하는 것이 쉽지 않다는 것을 깨달았다. 처음에는 계속해서 코드를 읽어보면서 익숙하지 않은 fs모듈에 대해서 먼저 파악해보고, 제공되는 메서드들을 익혀보았다. 그렇게 코드의 흐름을 익혀가면서 반복되는 부분을 구분하였고, 재귀적으로 해결할 수 있는 부분은 while 문이라는 것을 파악했다. 기존에 스택을 통해서 파일들을 가져오고 데이터를 쌓아오면서 while 문을 통해 스택에 있는 데이터를 다시 출력하는 코드였다는 것을 파악하였고, 이를 재귀적으로 변경하기 위해서는 스택 자료구조를 사용하지 않고 하나의 함수에 하나의 폴더를 읽어오고 재귀적으로 함수를 다시 호출하면서 폴더 내부의 파일을 찾아가는 형식으로 수정할 수 있다는 것을 파악했다. 그렇게 하위조건을 설정하였고 기저조건을 만들어서 성공적으로 재귀함수로 코드를 수정할 수 있었다.이렇게 알고리즘을 응용하여 실전에서 사용할 수 있다는 것을 크게 깨달았고, 앞으로 알고리즘을 배울 때도 실전에서도 사용될 수 있는 다양한 사례를 함께 찾아보면서 공부하면 더 알고리즘 개념을 탄탄히 가져갈 수 있을 것 같다.

알고리즘 · 자료구조자료구조인프런워밍업

채널톡 아이콘