<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jnghoon_2.log</title>
        <link>https://velog.io/</link>
        <description>천천히 차근차근 꾸준히</description>
        <lastBuildDate>Thu, 12 Feb 2026 06:36:07 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jnghoon_2.log</title>
            <url>https://velog.velcdn.com/images/jnghoon_2/profile/1970da7f-dc61-4da1-bdff-686ecb48aff5/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jnghoon_2.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jnghoon_2" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[CS] 시스템버스란 무엇일까?]]></title>
            <link>https://velog.io/@jnghoon_2/CS-%EC%8B%9C%EC%8A%A4%ED%85%9C%EB%B2%84%EC%8A%A4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@jnghoon_2/CS-%EC%8B%9C%EC%8A%A4%ED%85%9C%EB%B2%84%EC%8A%A4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Thu, 12 Feb 2026 06:36:07 GMT</pubDate>
            <description><![CDATA[<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/cc3970ae-5880-433c-afdc-cc227db7821d/image.png" width=500 height=500>
</p>

<p>우리는 <a href="https://velog.io/@jnghoon_2/CS-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90">컴퓨터 구조가 어떤 요소들로 이루어졌는지</a> 학습했습니다.
이제 각 요소들이 어떤 방식으로 상호작용하는지 알아보겠습니다.</p>
<hr>
<h2 id="메인보드와-시스템-버스">메인보드와 시스템 버스</h2>
<p>CPU, 메모리, 보조기억장치, 입출력장치는 모두 <span style="color: #12B886"><strong>메인보드</strong></span>에 연결됩니다.</p>
<p>메인보드에 연결된 부품들은 서로 정보를 주고 받는데 <span style="color: #12B886"><strong>버스(bus)</strong></span>라는 통로를 사용합니다. 이 버스는 다양한 종류가 있으며, 여러 버스 가운데 컴퓨터의 네 가지 핵심 부품을 연결하는 가장 중요한 버스를 <span style="color: #12B886"><strong>시스템 버스</strong></span>라고 합니다.</p>
<p>시스템 버스는 <code>주소 버스</code>, <code>데이터 버스</code>, <code>제어 버스</code>로 구성되어 있습니다.
각 버스들을 조금 더 자세히 차례대로 알아보도록 하죠.</p>
<h3 id="주소-버스">주소 버스</h3>
<p>CPU가 데이터를 읽거나 쓰기 위해 메모리나 입출력 장치의 <span style="color: #12B886"><strong>위치(주소) 정보를 전달하는 통로</strong></span>입니다.즉, CPU가 &quot;어디에 있는 데이터를 가져올지&quot; 또는 &quot;어디에 데이터를 저장할지&quot;를 지정하는 역할을 수행합니다.</p>
<p><span style="color: #12B886"><strong>단방향성</strong></span>이라는 특징이 있으며, CPU에서 다른 장치로 주소를 보내기만 합니다.</p>
<p>다른 특징으로는 주소 버스의 선(Line) 개수가 많을수록 CPU가 관리할 수 있는 메모리의 주소 범위(최대 용량)가 넓어진다는 특징이 있습니다.</p>
<h3 id="데이터-버스">데이터 버스</h3>
<p>CPU와 메모리, 또는 입출력 장치 간에 <span style="color: #12B886"><strong>실제 데이터가 오고 가는 통로</strong></span>입니다.
CPU가 메모리에서 명령어를 읽어오거나, 연산 결과값을 메모리에 저장하는 등 실질적인 정보 이동을 담당합니다.</p>
<p>주소 버스와 달리 <span style="color: #12B886"><strong>양방향성</strong></span>입니다. 즉, CPU가 데이터를 보낼 수도, 받을 수도 있습니다.</p>
<p>데이터 버스의 폭(한 번에 보낼 수 있는 비트 수)이 넓을수록 한 번에 전송하는 양이 많아지기 때문에 컴퓨터의 전반적인 속도가 빨라집니다.</p>
<h3 id="제어-버스">제어 버스</h3>
<p>CPU가 시스템의 각 장치에 <span style="color: #12B886"><strong>제어 신호를 보내거나</strong></span>, 장치의 상태 <span style="color: #12B886"><strong>정보를 받아오는</strong></span> 통로입니다.</p>
<p>데이터 전송의 &#39;교통 정리&#39;를 담당합니다. &quot;지금 읽어라(Read)&quot;, &quot;지금 써라(Write)&quot;, 혹은 &quot;작업 완료(Interrupt)&quot; 등의 신호를 주고받아 동기화를 맞춥니다.</p>
<p>데이터 버스와 같이 <span style="color: #12B886"><strong>양방향성</strong></span>의 특징을 가집니다.</p>
<hr>
<h2 id="시스템-버스를-통한-상호작용">시스템 버스를 통한 상호작용</h2>
<p>그림과 예를 들어 어떤 방식으로 상호작용하는지 알아봅시다.
다음은 CPU 작동을 위해 메모리의 상호작용을 순서대로 도식화한 그림입니다.
CPU가 메모리 속 명령어를 읽어 들이기 위해 제어장치에 &quot;메모리 읽기&quot; 신호를 보낸다고 가정해봅시다.</p>
<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/ec9848e5-ca99-49b2-b69c-cb6533ecdc9b/image.png" width=500 height=500>
</p>

<ol>
<li>제어 버스로 명령 신호를 보냅니다.</li>
<li>동시에 주소 버스로 읽고자 하는 주소를 내보냅니다.</li>
<li>위 두 정보를 토대로 메모리는 데이터 버스를 통해 주소의 내용을 내보냅니다.</li>
</ol>
<p>이번에는 메모리에 어떤 값을 저장한다고 가정해봅시다.</p>
<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/318b0581-47ba-4120-b0f1-b88aa92856ae/image.png" width=500 height=500>
</p>

<ol>
<li>데이터 버스를 통해 메모리에 저장할 값을 보냅니다.</li>
<li>동시에 주소 버스를 통해 저장할 주소를 보냅니다.</li>
<li>제어 버스를 통해 제어 신호를 보냅니다.</li>
</ol>
<p>위와 같은 예시처럼 컴퓨터는 여러 버스를 복합적으로 활용하여 상호작용하게 됩니다.</p>
<hr>
<p>지금까지 컴퓨터의 핵심 부품들이 시스템 버스라는 통로를 통해 어떻게 유기적으로 대화하는지 알아보았습니다.</p>
<p>결국 컴퓨터의 모든 동작은 &quot;어디로(주소), 무엇을(데이터), 어떻게(제어)&quot; 보낼 것인가에 대한 끊임없는 상호작용인 셈입니다. 개념을 이해하고 나면, 앞으로 학습할 CPU의 명령어 사이클이나 인터럽트 메커니즘을 훨씬 더 깊이 있게 파악하실 수 있을 겁니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] 안드로이드에서의 빌드]]></title>
            <link>https://velog.io/@jnghoon_2/Android-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C%EC%97%90%EC%84%9C%EC%9D%98-%EB%B9%8C%EB%93%9C</link>
            <guid>https://velog.io/@jnghoon_2/Android-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C%EC%97%90%EC%84%9C%EC%9D%98-%EB%B9%8C%EB%93%9C</guid>
            <pubDate>Thu, 12 Feb 2026 04:55:26 GMT</pubDate>
            <description><![CDATA[<p>컴파일에 이어서 빌드에 대해서도 알아보겠습니다.</p>
<p>안드로이드에서 빌드 유형은 크게 두가지로 나뉩니다. <span style="color: #12B886"><strong>APK</strong></span>와 <span style="color: #12B886"><strong>AAB</strong></span> 빌드인데요.
이 두 유형의 빌드가 어떤 과정으로 이루어지는지, 어떤 차이점이 있는지 살펴보겠습니다.</p>
<hr>
<h2 id="apkandroid-application-package">APK(Android Application Package)</h2>
<p>APK는 안드로이드 운영체제에서 앱을 설치하기 위해 사용하는 <span style="color: #12B886"><strong>최종 실행 파일 형식</strong></span>입니다. </p>
<p>컴파일된 소스 코드(.dex), 리소스 파일, 매니페스트 등을 하나의 압축 파일(ZIP 형식)로 묶은 것이며, 기기의 사양(CPU 아키텍처, 해상도 등)과 상관없이 설치에 필요한 모든 리소스를 포함하고 있습니다. 때문에 모든 리소스가 들어있기 때문에 사용자 기기에 최적화되지 않은 데이터까지 다운로드하게 되어 <span style="color: #12B886"><strong>용량이 크다</strong></span>는 특징이 있죠.</p>
<p>구글 플레이 스토어를 통하지 않고도 웹사이트나 USB를 통해 기기에 바로 설치(Sideloading)가 가능합니다.</p>
<h3 id="빌드-및-배포-과정">빌드 및 배포 과정</h3>
<h4 id="1-리소스-컴파일-단계">1. 리소스 컴파일 단계</h4>
<p>AAPT2(Android Asset Packaging Tool) 도구가 XML 레이아웃, 이미지 등 리소스 파일을 컴파일하여 이진 형태의 중간 결과물을 생성합니다. 이 과정에서 리소스에 접근할 수 있는 R.java 파일이 생성됩니다.</p>
<h4 id="2-소스-코드-컴파일-단계">2. 소스 코드 컴파일 단계</h4>
<p>Java 소스 코드는 javac를 통해, Kotlin 소스 코드는 kotlinc를 통해 JVM 바이트코드인 .class 파일로 변환됩니다.</p>
<h4 id="3-바이트코드-최적화-및-변환-단계">3. 바이트코드 최적화 및 변환 단계</h4>
<p>릴리즈 빌드인 경우, R8 도구가 실행되어 사용하지 않는 코드를 제거하고 난독화를 수행합니다. 이후 D8 도구가 여러 개의 .class 파일을 안드로이드 전용 바이트코드인 .dex 파일로 하나로 묶어 변환합니다.</p>
<h4 id="4-최종-패키징-단계">4. 최종 패키징 단계</h4>
<p>컴파일된 리소스, .dex 파일, 그리고 라이브러리 파일들을 하나의 압축 파일 형태인 .apk로 병합합니다.</p>
<h4 id="5-서명-단계">5. 서명 단계</h4>
<p>apksigner 도구를 사용하여 개발자의 개인 키로 APK에 디지털 서명을 진행합니다. 
이 과정이 끝나야 기기에 설치 가능한 상태가 됩니다.</p>
<h4 id="6-배포-및-설치-단계">6. 배포 및 설치 단계</h4>
<p>완성된 하나의 APK를 사용자에게 배포합니다.
해당 파일은 모든 기기 사양을 포함하고 있어 용량이 크며, 사용자는 이 전체 파일을 다운로드하여 설치하게 됩니다.</p>
<hr>
<h2 id="aabandroid-app-bundle">AAB(Android App Bundle)</h2>
<p>AAB는 2018년 구글이 도입한 새로운 게시 형식으로, 현재 구글 플레이 스토어의 <span style="color: #12B886"><strong>표준</strong></span>입니다. 앱의 모든 컴파일된 코드와 리소스를 포함하지만, 설치 파일이 아닌 스토어 <span style="color: #12B886"><strong>업로드용 파일</strong></span>입니다.</p>
<p>사용자가 앱을 다운로드할 때, 구글 플레이 서버가 해당 기기의 사양에 딱 맞는 APK만 생성해서 전달합니다. 때문에 평균적으로 APK 대비 용량이 약 15~20% 정도 줄어들어 설치 전환율이 높아집니다.</p>
<p>APK와 반대로 기기에 직접 설치할 수 없으며, 반드시 구글 플레이와 같은 배포 시스템을 거쳐 APK로 변환되어야 합니다.</p>
<h3 id="빌드-및-배포-과정-1">빌드 및 배포 과정</h3>
<h4 id="1-로컬-빌드-및-번들-생성-단계">1. 로컬 빌드 및 번들 생성 단계</h4>
<p>소스 코드 컴파일과 .dex 변환 과정은 APK와 동일합니다. 
하지만 최종 결과물을 만들 때 설치용 파일이 아닌, 앱의 모든 코드와 리소스를 모듈별로 구분한 .aab 파일을 생성합니다.</p>
<h4 id="2-구글-플레이-업로드-단계">2. 구글 플레이 업로드 단계</h4>
<p>개발자가 서명된 AAB 파일을 구글 플레이 콘솔에 업로드합니다.
AAB 자체는 기기에 직접 설치할 수 없는 상태입니다.</p>
<h4 id="3-구글-플레이-서버의-분석-단계">3. 구글 플레이 서버의 분석 단계</h4>
<p>구글 플레이 서버에 탑재된 bundletool이 업로드된 AAB를 분석하여 지원하는 모든 언어, 화면 밀도(DPI), CPU 아키텍처(ABI)별로 리소스를 쪼개어 관리합니다.</p>
<h4 id="4-기기별-맞춤형-apk-생성-단계">4. 기기별 맞춤형 APK 생성 단계</h4>
<p>특정 사용자가 앱 다운로드를 요청하면, 구글 서버는 해당 사용자의 기기 정보를 확인합니다. 
사용자의 기기에 꼭 필요한 리소스와 코드만 골라내어 최적화된 APK 세트를 실시간으로 조합합니다.</p>
<h4 id="5-서버-재서명-및-배포-단계">5. 서버 재서명 및 배포 단계</h4>
<p>구글이 관리하는 앱 서명 키를 사용하여 조합된 최적화 APK에 서명한 뒤 사용자에게 전달합니다.</p>
<h4 id="6-분할-설치-단계">6. 분할 설치 단계</h4>
<p>사용자의 기기에는 전체 앱의 공통 부분인 base.apk와 해당 기기 사양에 맞는 리소스만 담긴 config.apk들이 나누어져 설치됩니다.</p>
<hr>
<h2 id="apk와-aab의-주요-차이점">APK와 AAB의 주요 차이점</h2>
<p>두 유형의 차이점에 대해 간단하게 정리해보죠.</p>
<h3 id="파일의-성격-차이">파일의 성격 차이</h3>
<p>APK는 그 자체로 실행 가능한 최종 설치 파일이지만, AAB는 구글 플레이가 설치용 APK를 생성하기 위해 사용하는 재료 주머니와 같은 출판 포맷입니다.</p>
<h3 id="용량-효율성-차이">용량 효율성 차이</h3>
<p>APK는 모든 기기 대응 리소스를 품고 있어 무겁지만, AAB 기반 배포는 사용자의 기기 사양에 불필요한 데이터를 제외하므로 다운로드 용량이 훨씬 가볍습니다.</p>
<h3 id="서명-관리-주체-차이">서명 관리 주체 차이</h3>
<p>APK는 개발자가 로컬에서 서명을 완료하여 배포하는 방식이 주를 이루며, AAB는 보안과 최적화를 위해 구글 플레이 서버에서 앱 서명을 관리하는 방식을 권장합니다.</p>
<h3 id="동적-기능-지원-여부">동적 기능 지원 여부</h3>
<p>APK는 앱의 모든 기능을 한 번에 설치해야 하지만, AAB는 특정 기능을 사용자가 원할 때나 특정 조건에서만 추가로 다운로드하게 만드는 동적 기능 배포가 가능합니다.</p>
<hr>
<p>최종적으로 <span style="color: #12B886"><strong>APK는 완성된 단일 패키지, AAB는 조립 설계도</strong></span>라고 이해할 수 있습니다. 로컬 테스트나 직접 배포가 필요할 때는 APK를, 스토어에 정식 출시하여 사용자에게 최적화된 경험을 제공하고 싶을 때는 AAB를 선택하는 것이 안드로이드 개발의 표준이 되었음을 알려드리며 오늘은 여기서 마치도록 하겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] 안드로이드에서의 컴파일]]></title>
            <link>https://velog.io/@jnghoon_2/Android-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C%EC%97%90%EC%84%9C%EC%9D%98-%EC%BB%B4%ED%8C%8C%EC%9D%BC</link>
            <guid>https://velog.io/@jnghoon_2/Android-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C%EC%97%90%EC%84%9C%EC%9D%98-%EC%BB%B4%ED%8C%8C%EC%9D%BC</guid>
            <pubDate>Tue, 10 Feb 2026 03:20:58 GMT</pubDate>
            <description><![CDATA[<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/332ee9d4-ebfe-4156-80c8-861dae221715/image.png" width=500 height=500>
</p>

<p>ART를 공부해보며 대략적인 컴파일 과정은 이해하셨을 것 같습니다.
조금 더 자세하게 컴파일이 어떤 과정을 거쳐 이루어지는 지 알아보겠습니다.</p>
<p>안드로이의 최신 컴파일 방식은 <a href="https://velog.io/@jnghoon_2/Android-ARTAndroid-RunTime%EB%9E%80">ART(Android Runtime)</a>를 기반으로하며, 단순히 한 가지 방식이 아니라 <span style="color: #12B886"><strong>AOT, JIT 그리고 클라우드 프로필</strong></span>이 정교하게 결합된 <span style="color: #12B886"><strong>하이브리드 방식</strong></span>을 사용합니다.</p>
<hr>
<h2 id="art-하이브리드-컴파일-과정">ART 하이브리드 컴파일 과정</h2>
<p>먼저 컴파일 과정을 살펴봅시다.</p>
<h3 id="1-앱-설치-단계">1. 앱 설치 단계</h3>
<p>사용자가 앱을 설치할 때 ART는 전체 코드를 <span style="color: #12B886"><strong>미리 컴파일하지 않습니다.</strong></span>
때문에 설치 속도가 매우 빠르고, 설치 파일이 차지하는 초기 용량도 작게 유지됩니다.</p>
<h3 id="2-앱-최초-실행-및-jit-단계">2. 앱 최초 실행 및 JIT 단계</h3>
<p>앱을 실행하면 인터프리터가 바이트코드를 읽기 시작하며 필요한 부분을 실시간으로 컴파일하는 <span style="color: #12B886"><strong>JIT</strong></span>방식이 작동합니다. 이때 시스템은 앱의 어는 부분이ㅣ 자주 호출되는지 관찰하며 HotCode라 불리는 <span style="color: #12B886"><strong>실행 데이터를 수집</strong></span>합니다.</p>
<h3 id="3-프로파일링-데이터-생성-단계">3. 프로파일링 데이터 생성 단계</h3>
<p>JIT 컴파일러가 실시간으로 코드를 번역하는 동안 기기 내부에 프로파일 정보가 기록됩니다. 이 정보에는 사용자가 앱에서 가장 많이 사용하는 기능과 자주 실행되는 메소드 경로가 담겨 있습니다.</p>
<h3 id="4-유휴-상태-최적화-단계aot-전환">4. 유휴 상태 최적화 단계(AOT 전환)</h3>
<p>스마트폰을 사용하지 않고 충전 중인 <span style="color: #12B886"><strong>유휴 상태</strong></span>가 되면, 시스템은 백그라운드에서 <span style="color: #12B886"><strong>최적화 작업</strong></span>을 시작합니다. 앞서 수집된 프로파일 데이터를 기반으로 자주 사용되는 핵심 코드들만 골라내어 미리 기계어로 번역해 두는 <span style="color: #12B886"><strong>AOT</strong></span>컴파일을 수행합니다.</p>
<h3 id="5-최적화-이후의-실행-단계">5. 최적화 이후의 실행 단계</h3>
<p>이후 사용자가 다시 앱을 켰을 때 자주 사용되는 핵심 기능들은 이미 기계어로 번역된 상태이므로 즉시 실행됩니다. 번역되지 않은 나머지 부분은 여전히 JIT 방식으로 처리하여 성능과 효율의 균형을 맞춥니다.</p>
<hr>
<h2 id="aot와-jit-하이브리드-방식의-장점">AOT와 JIT 하이브리드 방식의 장점</h2>
<p>앞서 설명드린 과정을 근거로 하이브리드 방식의 장점을 나열해보겠습니다.</p>
<h3 id="설치-성능-개선">설치 성능 개선</h3>
<p>설치 시점에 모든 코드를 컴파일하지 않으므로 사용자는 앱 다운로드 후 기다리는 시간 없이 바로 앱을 실행할 수 있습니다.</p>
<h3 id="실행-성능-최적화">실행 성능 최적화</h3>
<p>사용자가 실제로 자주 사용하는 기능 위주로 미리 컴파일되어 있기 때문에 앱의 로딩 속도와 부드러움이 비약적으로 향상됩니다.</p>
<h3 id="시스템-자원-효율성">시스템 자원 효율성</h3>
<p>앱 전체를 무분별하게 미리 번역하지 않으므로 기기의 저장 공간을 절약할 수 있으며, 이미 번역된 코드를 실행할 때는 CPU 사용량이 줄어들어 배터리 소모를 낮춥니다.</p>
<h3 id="적응형-최적화">적응형 최적화</h3>
<p>사용자의 실제 앱 사용 패턴에 맞춰 시간이 지날수록 앱이 해당 사용자에게 가장 최적화된 상태로 변합니다.</p>
<hr>
<h2 id="클라우드-프로필cloud-profiles">클라우드 프로필(Cloud Profiles)</h2>
<p>구글 플레이스토어를 통해 성능을 극대화하는 방식입니다.</p>
<p>수많은 사용자가 앱을 사용하며 생된된 <span style="color: #12B886"><strong>자주 쓰는 코드 데이터(Profile)</strong></span>를 구글 서버에서 수집, 통합하여 새로운 사용자가 앱을 설치할 때, 통합된 <span style="color: #12B886"><strong>클라우드 프로필</strong></span>을 함께 내려받습니다. 이에 앱을 처음 실행할 때부터 이미 최적화된 상태(AOT)로 동작하여 실행 속도가 비약적으로 빨라집니다.</p>
<hr>
<h2 id="베이스라인-프로필baseline-profiles">베이스라인 프로필(Baseline Profiles)</h2>
<p>개발자가 직접 제어할 수 있는 최신 최적화 도구입니다.</p>
<p>개발자가 앱의 핵심 경로(ex. 앱 실행, 목록 스크롤)를 미리 프로파일링하여 APK/AAB에 포함하여 사용자는 앱을 처음 설치하자마자 주요 기능을 최고 성능으로 사용할 수 있습니다.</p>
<hr>
<p>안드로이드의 컴파일 방식은 단순한 &#39;번역&#39;을 넘어, 사용자 기기의 상태와 수많은 유저의 사용 패턴을 학습하며 실시간으로 진화하고 있습니다. 우리가 무심코 사용하는 앱들이 처음보다 쓰면 쓸수록 부드러워지는 데에는 이런 ART의 정교한 노력이 숨어 있었던 것이죠.</p>
<p>결국 베이스라인 프로필 같은 도구를 잘 활용하는 것이 사용자에게 최선의 경험을 제공하는 안드로이드 개발자의 역량이 아닐까 싶습니다.</p>
<p>다음 포스트에서는 안드로이드 <span style="color: #12B886"><strong>빌드(Build)</strong></span>에 대해 비슷한 형식으로 알아보도록 하겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] ART(Android RunTime)란?]]></title>
            <link>https://velog.io/@jnghoon_2/Android-ARTAndroid-RunTime%EB%9E%80</link>
            <guid>https://velog.io/@jnghoon_2/Android-ARTAndroid-RunTime%EB%9E%80</guid>
            <pubDate>Tue, 10 Feb 2026 02:40:19 GMT</pubDate>
            <description><![CDATA[<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/0463b335-8b95-48aa-8e17-44d4d188c90c/image.png" width=500 height=500>
</p>

<p>저번에 우리는 Android의 구조에 대해 알아보았습니다.
그 중 ART에 대해서는 ~이런게 있다. 정도로만 알고 넘어갔는데요.
오늘은 그 내용을 자세히 알아보도록 하겠습니다.</p>
<p>우선 정의부터 살펴봅시다.</p>
<blockquote>
<p>Android Runtime, ART
Linux Kernel과 HAL의 상위 계층에 위치하여 운영체제를 활용하여 Java 애플리케이션 실행에 대한 중추 역할을 수행하는 VM(Virtual Machine)</p>
</blockquote>
<p>즉, ART는 물리적인 하드웨어(CPU, RAM 등)를 소프트웨어로 에뮬레이션하여, 어떤 기기에서든 동일한 코드가 실행될 수 있도록 돕는 역할 <span style="color: #12B886"><strong>가상머신</strong></span>입니다. </p>
<p>ART의 등장 배경 및 역할을 이해하기 위해서는 JVM에 대해 이해하고 넘어갈 필요가 있습니다.</p>
<hr>
<h2 id="왜-jvm-대신-art를-선택했을까">왜 JVM 대신 ART를 선택했을까?</h2>
<p>바로 위에서 우리는 ART가 가상머신인 것을 알았습니다.
가상머신하면 보통 떠오르는 단어가 있죠? 바로 <span style="color: #12B886"><strong>JVM(Java Virtual Machine)</strong></span>입니다.</p>
<p>안드로이드는 얼마전까지(2018년까지) Java를 공식언어로 채택해왔습니다. 
때문에 High-Level Language인 Java를 컴퓨터로 이해할 수 있도록 변환해주는 과정인 <span style="color: #12B886"><strong>컴파일 과정(.java -&gt; .class)</strong></span>을 거쳐야하죠. 일반적인 컴파일 언어는 다이텍트로 기계어로 변환하지만, 자바 컴파일러는 기계어가 아닌 JVM이 이해할 수 있는 <span style="color: #12B886"><strong>바이트코드(.class)</strong></span>로 변환합니다.덕분에 자바 바이트 코드는 JVM만 설치되어 있으면 어떤 운영체제에서라도 실행될 수 있습니다.</p>
<p><span style="color: #12B886"><strong>현재는 Android에서는 JVM을 사용하지 않습니다.</strong></span>
위에서 언급하였듯이 기본 언어로 Java를 채택했기 때문에 JVM이 필수적이였으나, 라이센스 및 효율 문제로 인해 안드로이드 운영체제 구조에 맞춰 구동할 수 있는 가상머신이 필요해졌습니다.</p>
<p>이러한 배경으로 Dalvik VM과 ART가 등장하게 됩니다. 이제 본적적으로 이 둘에 대해 알아보도록 하죠.</p>
<hr>
<h2 id="dalvik">Dalvik</h2>
<p>먼저 달빅 가상머신에 대해 알아봅시다.</p>
<p><span style="color: #12B886"><strong>컴파일러를 통해서 생성되는 바이트 코드(.class)는 기계어가 아닙니다.</strong></span>
바이트 코드는 특정 플랫폼에 종속된 것이 아닌 VM을 위한 코드을 뿐이죠.
따라서 인터프리터를 이용해서 기계어로 해석하는 과정이 필요합니다.</p>
<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/13122d4c-785d-42eb-9f38-e61b9e4a635b/image.png" width=500 height=500>
</p>

<p>위는 컴파일 과정을 도식화 해둔 그림입니다.
보시다시피, 컴파일러를 통해 우선적으로 바이트코드로 변환되고 그 이후 각 가상머신에 따라 한번 더 변환되죠. Dalvik VM을 사용하는 경우 <span style="color: #12B886"><strong>달빅코드(.dex)</strong></span>로 변환되는 것을 확인할 수 있습니다.</p>
<p>우리는 그럼에서 <span style="color: #12B886"><strong>JIT(Just-In-Time) 컴파일</strong></span>이라는 부분에 초점을 둘 필요가 있습니다.
JIT 컴파일 방식은 프로그램 실행 시 자주 사용되는 바이트코드(Hotspot)에 대해서 미리 기계어로 해석 해놓는 방식(Caching)입니다. 때문에 바이트코드가 사용될 때 재해석할 필요가 없어 속도가 빠릅니다.</p>
<p>JIT의 특징은 다음과 같습니다.</p>
<h3 id="jit">JIT</h3>
<ul>
<li>앱 <span style="color: #12B886"><strong>실행</strong></span> 시 컴파일</li>
<li>설치 시 컴파일을 하지 않기 때문에 AOT에 비해 설치 속도 빠름</li>
<li>실행 시 컴파일을 하기 때문에 AOT에 비해 실행 속도 느림</li>
<li>용량 작음</li>
</ul>
<h3 id="trace-jit">Trace JIT</h3>
<p>DVM에서의 JIT은 임계값을 초과하면 바이트코드를 기계어로 해석하는 방식입니다.
즉, 어떤 구간이 특정 횟수 이상 반복되면 컴파일하는 Trace JIT인 것이죠.</p>
<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/f7315e0a-b5fc-4dee-9158-0234d5b55fa2/image.png" width=500 height=500>
</p>

<p>컴파일은 별도의 컴파일 스레드에 의해 진행되며, 컴파일이 완료되면 Traslastion Cache에 저장합니다. 초기 DVM에는 JIT이 없었고 Android 2.2에서 적용되었습니다. 이전까지는 애플리케이션 구동 시 실시간으로 CPU에 맞춰 코드를 변환했죠. JIT 도입 후 코드의 일정 부분을 RAM에 올려두고 작업할 수 있기에 비약적인 성능 향상이 일어났으나, 다음과 같은 문제가 발생했습니다.</p>
<ul>
<li>컴파일러가 돌아가는 동안 배터리 및 하드웨어의 부하 발생</li>
<li>애플리케이션 프로세스 전체를 RAM에 올려두고 사용해야함.</li>
</ul>
<p>해당 문제를 해결하기 위해 AOT 컴파일 방식을 기반으로 만들어진 VM이 바로 ART입니다.</p>
<hr>
<h2 id="art">ART</h2>
<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/e68261cd-7700-470c-b5d7-757c3952a62a/image.png" width=500 height=500>
</p>

<p>ART는 <span style="color: #12B886"><strong>AOT(Ahead-Of-Time) 컴파일</strong></span> 방식을 사용합니다.
도식화를 확인하면 알 수 있듯이 앱 설치 시 컴파일을 진행하게 됩니다.</p>
<p>AOT의 특징은 다음과 같습니다.</p>
<h3 id="aot">AOT</h3>
<ul>
<li>앱 <span style="color: #12B886"><strong>설치</strong></span> 시 컴파일</li>
<li>설치 시 컴파일을 완료하기 때문에 JIT에 비해 설치 속도 느림</li>
<li>실행 시 컴파일을 하지 않기 때문에 JIT에 비해 실행 속도 빠름</li>
<li>용량 큼(미리 컴파일하여 가지고 있기 때문)</li>
</ul>
<hr>
<h2 id="상호보완">상호보완</h2>
<p>위 Dalvik 파트와 ART 파트를 정독하셨다면 알고 계실겁니다.
Dalvik과 ART의 가장 큰 차이는 컴파일 방식이고, <span style="color: #12B886"><strong>서로 상반된 장단점</strong></span>을 가지고 있습니다.</p>
<p>Android 7.0 부터는 앱 설치시간을 단축하기 위해 최초 설치 시에는 JIT 컴파일 방식을 사용하고, 기기를 사용하지 않는 시간에 일부분 컴파일 작업을 실시하여 점진적으로 AOT 컴파일 방식으로 바꿔 나가도록 되어 있음. 즉, <span style="color: #12B886"><strong>DVM과 ART의 장점을 합치고 단점을 해결하는 방식</strong></span>으로 문제를 해결했습니다.</p>
<p>조금 더 자세히 알아볼까요?</p>
<p>AOT 컴파일러는 APK(Android Application Package)를 설치할 때 Dalvik에서 사용하는 dex 파일를 활용하여 기계어로 해석합니다.</p>
<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/bba3c07d-f872-43bc-b6a3-8b8dc657833c/image.png" width=500 height=500>
</p>

<p>Dalvik은 dexopt라는 툴을 통해서 dex파일을 최적화한 odex(optimized dex)라는 파일을 생성합니다. odex는 특정 기기의 시스템에 최적화된 코드이기 때문에 다른 기기에서 사용할 수 없으며 DVM은 odex 파일을 앱 실행 시 기계어로 해석하죠.</p>
<p>ART는 AOT 컴파일 시 dex2oat라는 툴을 사용해서 dex파일을 odex로 변경한 후에 oat 파일로 변경합니다. oat 파일은 elf(executable file) 파일 형식의 기계어를 포함하는 파일이구요.</p>
<p>아직까지는 잘 이해하시지 못할 수 있습니다.</p>
<p>다음 포스팅인 안드로이드 컴파일 과정을 참고하여 보신다면 조금 더 이해하기 수월하실 수 있을 겁니다.</p>
<hr>
<p>결과적으로 안드로이드 런타임은 <span style="color: #12B886"><strong>성능과 효율</strong></span> 사이에서 최적의 균형을 찾기 위해 끊임없이 진화해 왔습니다. 처음엔 JVM의 철학을 빌려왔지만, 모바일이라는 특수한 환경(제한된 배터리, 메모리)에 최적화하기 위해 Dalvik을 거쳐 현재의 ART에 이르게 된 것이죠.</p>
<p>우리가 작성한 코드가 사용자 기기에서 어떻게 컴파일되고 최적화되는지 이해한다면, 단순히 코드를 짜는 것을 넘어 <span style="color: #12B886"><strong>성능최적화</strong></span>에 대한 더 깊은 고민을 할 수 있는 안드로이드 개발자가 될 수 있지 않을까 생각합니다.</p>
<p>다음 포스팅에서는 우리가 작성한 소스 코드가 어떤 단계를 거쳐 기계가 이해할 수 있는 언어로 변환되는지, <span style="color: #12B886"><strong>안드로이드의 컴파일 과정(Compile Process)</strong></span>에 대해 다루어 보겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Android OS에 대해 알아보자]]></title>
            <link>https://velog.io/@jnghoon_2/Android-Android-OS%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@jnghoon_2/Android-Android-OS%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Fri, 06 Feb 2026 08:07:24 GMT</pubDate>
            <description><![CDATA[<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/63a3d03f-31d0-424e-af37-36d4ed25f08e/image.png" width=500 height=500>
</p>

<p>안녕하세요? 개발자 Tuan입니다.
2010년대에 들어서면서 스마트폰이라는 개념이 탄생하게 됩니다.
현재 우리에게 있어서 꼭 필수적인 물건이 되었지요.</p>
<p>이런 스마트폰의 운영체제는 크게 <code>Android</code>와 <code>iOS</code>로 나뉩니다.
(물론 Tizen OS 등 다양한 운영체제가 있지만 대부분은 Android 또는 iOS입니다.)</p>
<p>우리는 오늘 둘 중 하나인 <span style="color: #12B886"><strong>Android OS</strong></span>에 대해서 알아보겠습니다.</p>
<hr>
<h2 id="어떻게-개발되었을까">어떻게 개발되었을까?</h2>
<p>Android는 구글 주도로 개발된 리눅스 커널 기반의 <span style="color: #12B886"><strong>오픈소스 모바일 운영체제</strong></span>입니다.
전 세계에서 가장 많이 사용되는 모바일 OS로, 스마트폰 뿐만 아니라 태블릿, TV, 자동차(Android Auto), 웨어러블 기기(Wear OS) 등 다양한 분야에 적용되고 있죠.</p>
<p>안드로이드의 첫 시작은 모바일 운영체제가 아니였습니다. 
앤디 루빈(Andy Rubin)이 설립한 Android Inc는 원래 디지털 카메라용 OS를 목적으로 개발하려했지만,디지털 카메라 시장의 정체로 인해 노선을 틀게 됩니다. 안드로이드는 구글이 인수하며 모바일 시장에 본격적으로 진출하게 됩니다. 구글을 중심으로 삼성, LG, Intel 등 이 참여하여 OHA(Open Handset Alliance)를 결성하였으며 이를 바탕으로 안드로이드의 소스코드가 세상의 빛을 보게 되었습니다.</p>
<p>덕분에 모바일 개발자라면 한번쯤은 들어봤을 단어인 <span style="color: #12B886"><strong>AOSP(Android Open Source Project)</strong></span>가 탄생하게 되었으며, 오랜 기간동안 사람의 손으로 꾸준하게 관리되고 있는 중입니다.</p>
<blockquote>
<p>안드로이드는 삼성전자 본사를 방문해 투자, 인수를 제안했으나, 당시 임원들로부터 회의적인 반응과 함께 거절당했다는 유명한 일화가 있습니다. 만약 삼성이 안드로이드를 투자,인수 했다면 지금의 안드로이드는 어땠을까요?</p>
</blockquote>
<hr>
<h2 id="안드로이드의-특징">안드로이드의 특징</h2>
<p>그럼 이제 안드로이드의 특징에 대해 알아봅시다.
안드로이드의 특징은 크게 4가지로 볼 수 있을 것 같네요.</p>
<h3 id="오픈소스">오픈소스</h3>
<p>안드로이드는 <span style="color: #12B886"><strong>오픈소스</strong></span>입니다. 제조사는 AOSP를 기반으로 자신들만의 UI/UX(One UI, MIUI 등)를 구축할 수 있습니다. 오픈소스 특성상 취약점이 발견되면 전 세계 커뮤니티와 구글이 빠르게 대응하며, 프로젝트 트레블(Projet Treble)을 통해 파편화된 기기들의 OS업데이트 속도를 개선하고 있습니다.</p>
<h3 id="리눅스-커널-기반">리눅스 커널 기반</h3>
<p>안드로이드는 리눅스 커널 위에 <span style="color: #12B886"><strong>HAL</strong></span>을 두어 상위 프레임워크가 하드웨어의 구체적인 구현에 상관없이 동일한 API로 동작하게 합니다. 또한 모바일 환경은 배터리 관리가 중요합니다. 모바일 환경에 촤적화된 저전력 메모리 관리(Low Memory Killer)나 전원 관리(WakeLocks) 기능을 리눅스 커널 수준에서 변형하여 적용했습니다.</p>
<h3 id="유연한-폼팩터">유연한 폼팩터</h3>
<p>해상도, 화면 비율, 입력 방식이 제각각인 기기를 지원하기 위해 밀도 독집적 단위(dp)를 사용합니다. 또한 스마트폰 뿐만 아닌 다양한 기기까지 동일한 핵심 아키텍처를 공유하여 확장됩니다. 최근에는 <span style="color: #12B886"><strong>동적 모듈화 기술</strong></span>을 통해 기기 사양에 맞는 최적화된 코드와 리소스만 설치되도록하여 저장 공간을 절약합니다.</p>
<h3 id="앱-생태계">앱 생태계</h3>
<p>구글은 2019년부터 <span style="color: #12B886"><strong>코틀린(Kotlin)</strong></span>을 공식 언어로 선언했습니다. 자바의 고질적인 문제를 해결하고 코드의 생산성을 획기적으로 높였죠. 또한 Jetpack 라이브러리를 통해 개발자가 아키텍처 설계를 쉽게 할 수 있도록 도와 앱의 품질을 표준화 시켰습니다.</p>
<hr>
<h2 id="아키텍처">아키텍처</h2>
<p>자, 지금부터는 안드로이드 플랫폼 아키텍처에 대해 설명드리겠습니다.</p>
<p>앞서 설명드렸다시피, 안드로이드는 다양한 기기와 폼팩터에 사용할 수 있도록 제작된 리눅스 기반의 오픈소스입니다. 동시에 스프트웨어 스택이기도 하죠. 즉, 계층적(Layer System)으로 구성되어 있습니다.</p>
<blockquote>
<h3 id="layer-system이란">Layer System이란?</h3>
<p>하위 계층의 서비스를 상위 계층에게 제공함으로써, 상위 계층이 하위 계층의 서비스를 사용하는 방식으로 시스템을 구축하는 것입니다. 하위 계층의 기능 구현 사항을 상위 계층이 모르게 하며, 상위 계층은 하위 계층이 제공하는 인터페이스를 통해 사용합니다.</p>
</blockquote>
<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/4765ea25-ad79-48d2-a39f-d7b75a5e8c68/image.png" width=500 height=500>
</p>

<p>위 이미지는 안드로이드 아키텍처를 도식화 해둔 이미지입니다. 공식 문서에서 확인할 수 있고, 안드로이드 개발자라면 반드시 한번은 봤을 이미지이죠. 그럼 이제 계층별로 하나씩 살펴봅시다.</p>
<h3 id="linux-kernel">Linux Kernel</h3>
<p>커널은 운영체제의 핵심이 되는 프로그램입니다. 시스템을 완전히 통제하죠. 운영체제의 다른 부분 및 응용 프로그램 수행이 필요한 여러 가지 서비스를 제공하며 이를 통해 주요 보안 기능을 활용할 수 있고, 제조사에서 커널용 하드웨어 드라이버를 개발 할 수 있습니다.
즉, 하드웨어와 OS를 연결하는 <span style="color: #12B886"><strong>매개존재</strong></span>로써, OS에 있어 핵심입니다.</p>
<p><code>Power Management</code>, <code>Hardware Driver</code>, <code>Abstraction</code>, <code>Resource Management</code>, <code>Security</code> 등으로 구성되어 있습니다.</p>
<h3 id="hardware-abstraction-layerhal">Hardware Abstraction Layer(HAL)</h3>
<p>복잡한 하드웨어 내부를 감추고, 일관성 있는 인터페이스를 제공하기 위해 같은 종류의 하드웨어에 대한 공통 명령어 집합으로 묶는 과정을 수행하는 계층입니다.</p>
<p>상위 계층인 Java API Framework 계층에 하드웨어 기능을 제공하는 <span style="color: #12B886"><strong>표준 인터페이스를 제공</strong></span>하며, 하드웨어에 액세스하기 위해 호출을 수행하면 Android 시스템이 해당 하드웨어 구성 요소에 대한 라이브러리 모듈을 로드해주기도 하죠.</p>
<p>또한 하드웨어 공급업체에서 구현해야 하는 표준 인터페이스를 정의하며 안드로이드에서 하위 드라이버 구현을 고려하지 않아도 되게 해주는 시스템입니다.</p>
<h3 id="android-runtimeart">Android RunTime(ART)</h3>
<p>리눅스 커널과 HAL의 상위 계층에 위치하여 운영체제를 활용해 Java 애플리케이션 실행에 중추 역할을 수행하는 <span style="color: #12B886"><strong>VM(Virtual Machine)</strong></span>입니다.</p>
<p>ART의 역할을 이해하기 위해서는 JVM에 대해 이해하고 넘어갈 필요가 있습니다.
ART에 관련된 자세한 내용은 추후 따로 작성해보겠습니다.</p>
<h3 id="native-cc-libraries">Native C/C++ Libraries</h3>
<p>기본적으로 운영체제에 <span style="color: #12B886"><strong>내장된 라이브러리</strong></span>들이 존재하는 계층입니다.
모바일 기기는 하드웨어 성능이 PC에 비해 제한적이기에 효율적인 구동을 위해 low-level에 가까운 C/C++로 작성되어 있습니다. 때문에 개발자가 해당 네이티브 라이브러리에 접근할 때는 <span style="color: #12B886"><strong>Android NDK(Native Development Kit)</strong></span>을 사용함.</p>
<blockquote>
<p>ART 및 HAL 등의 많은 핵심 Android 시스템 구성 요소 및 서비스가 C/C++ 네이티브 코드로 빌드되어 있으며, Java Framework API를 제공하여 이러한 일부 네이티브 라이브러리의 기능을 앱에 제공합니다.</p>
</blockquote>
<h3 id="java-api-framework">Java API Framework</h3>
<p><span style="color: #12B886"><strong>Android Framework</strong></span>를 의미하며 안드로이드 전체 기능은 Java로 작성된 API를 통해서 접근이 가능합니다.</p>
<p>개발자는 이를 통해 안드로이드 시스템 애플리케이션이 사용하는 것과 동일한 프레임워크 API에 대한 전체 접근 권한을 가지며 이를 바탕으로 다양한 기능을 개발할 수 있죠.</p>
<p>개발자가 코드를 작성하는 애플리케이션 계층과 하위 계층들과 소통할 수 있도록 하는 브릿지 역할을 하며 액티비티 생명주기 및 언어 설정 등 프레임워크 수준의 기능을 담당하기도 한답니다?</p>
<h3 id="system-application">System Application</h3>
<p>마지막 최상위 계층입니다.
일반 사용자들이 접하는 계층으로, 안드로이드 기본 제공 앱 및 스토어에서 다운받은 앱들이 해당 계층에 속합니다.</p>
<hr>
<p>이렇게 안드로이드 OS에 대해 짧게 나마 알아보았습니다.
하지만 안드로이드 개발을 위해서는 더 많은 내용을 알 필요가 있습니다.
오늘 공부한 내용 만으로는 안드로이드를 전부 이해했다고 할 순 없죠.</p>
<p>안드로이드에서 컴파일은 어떤 과정을 거쳐 이루어지는지, 빌드는 어떤 과정을 거치는지 등 앞으로 우리가 안드로이드에 대해 공부할 내용은 많습니다.</p>
<p>천천히 차근차근 꾸준히 관련 글을 작성해보겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] 컴퓨터 구조에 대해 알아보자]]></title>
            <link>https://velog.io/@jnghoon_2/CS-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@jnghoon_2/CS-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Wed, 04 Feb 2026 22:33:17 GMT</pubDate>
            <description><![CDATA[<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/4e35ffe6-2760-4144-b554-b7f6f70562e2/image.png" width=500 height=500>
</p>


<p>우리는 앞서서 우리가 <a href="https://velog.io/@jnghoon_2/CS-%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0%EB%A5%BC-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0">왜 컴퓨터 구조를 알고 있어야 하는지</a> 알아보았습니다.
이제는 본격적으로 컴퓨터 구조에 대해 알아볼 차례입니다.
우선, 컴퓨터 구조의 큰 그림에 대해 알아보도록 하죠.</p>
<hr>
<h2 id="컴퓨터-구조의-구성">컴퓨터 구조의 구성</h2>
<p>들어가기전, 우리가 어떤 지식들을 공부하는지 짚고 넘어갑시다.</p>
<p>컴퓨터 구조 지식은 크게 두가지로 나뉠 수 있습니다.
하나는 <span style="color: #12B886"><strong>컴퓨터가 이해하는 정보</strong></span>이고, 다른 하나는 <span style="color: #12B886"><strong>컴퓨터의 네 가지 핵심 부품</strong></span>입니다.</p>
<p>여기서 또 세분화 됩니다. 
컴퓨터가 이해하는 정보에는 크게 <span style="color: #12B886"><strong>데이터</strong></span>와 <span style="color: #12B886"><strong>명령어</strong></span>로 나뉘며, 컴퓨터의 네 가지 핵심 부품은 <span style="color: #12B886"><strong>CPU</strong></span>, <span style="color: #12B886"><strong>메모리</strong></span>, <span style="color: #12B886"><strong>보조기억장치</strong></span>, <span style="color: #12B886"><strong>입출력장치</strong></span>로 나뉩니다.</p>
<p>이를 정리 해보면 다음과 같습니다.</p>
<ul>
<li>컴퓨터 구조<ul>
<li>이해하는 정보<ul>
<li>데이터</li>
<li>명령어</li>
</ul>
</li>
<li>핵심 부품<ul>
<li>CPU</li>
<li>메모리</li>
<li>보조기억장치</li>
<li>입출력장치</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="컴퓨터가-이해하는-정보">컴퓨터가 이해하는 정보</h2>
<p>먼저 컴퓨터가 이해하는 정보를 살펴봅시다.</p>
<p>컴퓨터는 <code>0</code>과 <code>1</code>로 표현된 정보만 이해할 수 있습니다. 그리고 이렇게 표현되는 정보에는 크게 두 종료가 있는데, 
그것이 바로 <span style="color: #12B886"><strong>데이터</strong></span>와 <span style="color: #12B886"><strong>명령어</strong></span>입니다.</p>
<p>명령어는 컴퓨터를 작동시키는 정보이고, 데이터는 명령어를 위해 존재하는 일종의 재료입니다.
이런 점에서 프로그램은 <span style="color: #12B886"><strong>명령어들의 모음</strong></span>으로 정의되기도 합니다.</p>
<h3 id="데이터data">데이터(Data)</h3>
<p>데이터, 컴퓨터가 이해할 수 있는 숫자, 문자, 이미지, 동영상과 같은 <span style="color: #12B886"><strong>정적인 정보</strong></span>.
흔히 우리는 컴퓨터와 주고받는 정보나 저장된 정보를 가리킬 때 데이터라고 통칭합니다.
이러한 데이터를 설명하기에는 글이 너무 길어지니 추후 개별적으로 따로 작성해보겠습니다.</p>
<h3 id="명령어instruction">명령어(Instruction)</h3>
<p>명령어는 데이터를 움직이고 <span style="color: #12B886"><strong>컴퓨터를 작동</strong></span>시키는 정보입니다.
데이터와 마찬가지로 개별적인 글로 추후 설명해보겠습니다.</p>
<hr>
<h2 id="4가지-핵심-부품">4가지 핵심 부품</h2>
<p>요즘에는 다양한 형태, 종류로 컴퓨터가 존재합니다. 사용되는 용도와 제약 때문이겠지요.
하지만 외관과 용도를 막론하고 컴퓨터를 이루는 핵심 부품은 크게 다르지 않습니다.</p>
<h3 id="cpucentral-processing-unit">CPU(Central Processing Unit)</h3>
<p>산술논리연산장치, 제어장치, 레지스터로 구성되어 있는 장치입니다.
인터럽트에 의해 메모리에 존재하는 명령어를 해석해서 실행하는 장치이지요.</p>
<p>정리하진 않았지만, 커널이라는 존재가 프로그램을 메모리에 올려 프로세스를 생성하고, 이를 CPU가 처리하게 됩니다.</p>
<p>한마디로 정의하자면 CPU는 컴퓨터의 <span style="color: #12B886"><strong>두뇌</strong></span>입니다.
메모리에 저장된 명령어를 읽어 들이고, 읽어 들인 명령어를 해석, 실행하는 부품입니다.</p>
<p>조금 더 자세히 알아볼까요?</p>
<h4 id="산술논리연산장치arithmetic-logic-unit-alu">산술논리연산장치(Arithmetic Logic Unit, ALU)</h4>
<p>산술 연산과 논리 연산을 계산하는 디지털 회로입니다.
쉽게 말하면 <span style="color: #12B886"><strong>계산기</strong></span>입니다.</p>
<p>오로지 계산만을 위해 존재하는 부품입니다. 컴퓨터 내부에서 수행되는 대부분의 계산은 ALU가 도맡아 수행합니다.</p>
<h4 id="제어장치control-unit-cu">제어장치(Control Unit, CU)</h4>
<p>프로세스 조작을 지시하는 장치입니다.
입출력장치 간 통신을 제어하고 명령어들을 읽고 해석하며, 데이터 처리를 위한 순서를 결정합니다.</p>
<p>컴퓨터 부품들을 관리하고 작동시키기 위한 일종의 전기 신호인 <span style="color: #12B886"><strong>제어 신호(Control Signal)</strong></span>를 내보내어 제어하게 됩니다.</p>
<h4 id="레지스터registor">레지스터(Registor)</h4>
<p>CPU 내부에 위치하는 매우 빠른 임시기억장치입니다.
직접적으로 연결되어 있기에 연산속도가 메모리보다 빠르다는 특징이 있습니다.
CPU는 자체적으로 데이터를 저장할 수 없기에 레지스터를 거쳐 데이터를 전달하게 됩니다.</p>
<h3 id="메모리memory">메모리(Memory)</h3>
<p>앞서 컴퓨터가 이해하는 정보는 명령어와 데이터임을 학습했습니다.
메모리는 현재 실행되는 프로그램의 명령어와 데이터를 <span style="color: #12B886"><strong>저장</strong></span>하는 부품입니다.
즉, 프로그램이 실행되려면 반드시 메모리에 올라가 있어야합니다.</p>
<p>저장된 명령어와 데이터의 위치는 정돈되어 있어야 합니다. 
때문에 메모리에는 저장된 값에 빠르고 효율적으로 접근하기 위해 <span style="color: #12B886"><strong>주소(Address)</strong></span>라는 개념이 사용됩니다.
마치 현실에서 우리가 주소만 있으면 원하는 장소로 이동할 수 있는 것처럼 말이죠.</p>
<p>메모리에는 가장 큰 특징이 있습니다.
바로 <span style="color: #12B886"><strong>휘발성</strong></span>이라는 특징입니다.
전워이 꺼지면 저장된 내용을 잃는다는 것이지요.</p>
<h3 id="보조기억장치">보조기억장치</h3>
<p>때문에 전원이 종료되어도 저장된 내용을 잃지 않는 저장 장치가 필요하게 되었는데, 
이 저장 장치가 바로 보조기억장치입니다.</p>
<p>HDD, SSD, USB, DVD, CD 등이 보조기억장치의 일종입니다.</p>
<h3 id="입출력장치">입출력장치</h3>
<p>컴퓨터 내부와 정보를 교환하는 장치입니다.
키보드, 마우스, 마이크, 스피커 등이 여기에 해당하죠.</p>
<hr>
<p>이렇게 컴퓨터 구조의 큰 그림을 살펴봤습니다.</p>
<p>이 글에서 서술한 내용을 컴퓨터 구조의 전부는 아닙니다.
<code>DMA 컨트롤러</code>, <code>타이머</code>, <code>디바이스 컨트롤러</code> 등 다양한 요소들도 있으며,
글을 작성하며 나왔던 <code>인터럽트</code>나 <code>프로세스</code> 등 중요한 개념 또함 포함되어 있습니다. 
이에 대한 세부 사항은 차근차근 천천히 추후 서술해 볼 예정입니다.</p>
<p>다음에는 각 요소들이 어떻게 상호작용하는지 <span style="color: #12B886"><strong>시스템 버스</strong></span>를 통해 알아보겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] 개발자가 컴퓨터 구조를 알아야하는 이유]]></title>
            <link>https://velog.io/@jnghoon_2/CS-%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0%EB%A5%BC-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@jnghoon_2/CS-%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B5%AC%EC%A1%B0%EB%A5%BC-%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Wed, 04 Feb 2026 01:41:42 GMT</pubDate>
            <description><![CDATA[<p align="center">
<img src="https://velog.velcdn.com/images/jnghoon_2/post/edee5cb0-d561-4552-9a08-d5529c74a44d/image.png" width=500 height=500>
</p>

<p>안녕하세요? 개발자 Tuan입니다.
오늘은 개발자가 왜 <span style="color: #12B886"><strong>컴퓨터 구조</strong></span>에 대해 잘 숙지하고 있어야하는지 알아보겠습니다.</p>
<hr>
<h2 id="개발자에게-기본-소양인가">개발자에게 기본 소양인가?</h2>
<p>사실 컴퓨터의 구성 요소와 작동 원리를 알지 못해도 우리는 프로그래밍을 할 수 있습니다.</p>
<p>프로그래밍 언어의 간단한 문법을 익히고 프로그램을 실행하는 것은 책이나 구글링을 통해 나오는 스탭을 그대로 따라가기만 하면 문제 없이 실행 가능합니다. 최근에는 AI의 발전으로 <span style="color: #12B886"><strong>바이브 코딩</strong></span>을 통해 개발하는 개발자, 비개발자도 존재합니다.</p>
<p>즉, 컴퓨터 구조를 알지 못해도 개발은 할 수 있습니다만...
<span style="color: #12B886"><strong>실력 있는 개발자</strong></span>가 되기 위해서는 컴퓨터 구조를 기본 소양으로 가지고 있을 필요가 있습니다.
이제 그 이유를 알아보도록 합시다.</p>
<hr>
<h2 id="문제-해결">문제 해결</h2>
<p>우리가 개발한 프로그램은 항상 완벽할 수 없습니다. 당장이 아니더라도 언젠가 문제가 생길 수 밖에 없죠. 즉, 우리는 <span style="color: #12B886"><strong>문제 해결</strong></span>을 위해 컴퓨터 구조를 숙지하고 있을 필요가 있습니다. </p>
<p>구글링이나 AI 프롬프트 작성 등 문제 해결 능력이 좋다면 컴퓨터 구조를 알지 못해도 문제 자체는 해결할 수 있을 것입니다. 하지만 문제가 발생한 이유. 즉, 왜 문제가 일어났는지 파악하지 못한다면, 본질을 이해하지 못한다면 이는 추후 나에게 문제를 넘기는 _폭탄돌리기_가 되거나, _비효율_을 유발하게 될 수도 있다고 생각합니다.</p>
<p>컴퓨터 구조를 이해하고 있다면 빠르게 문제를 진단할 수 있고, 다양한 방법으로 문제를 해결해나갈 수 있습니다. 알고 있는 지식이 많다면 <span style="color: #12B886"><strong>분석</strong></span>할 수 있는 수단과 방법이 필연적으로 많아질테니까요.</p>
<p>조금 현실적인 부분으로 생각해봅시다.
문제 해결 능력, 컴퓨터에 대한 이해는 하나의 역량으로 업무 수행에 자격 조건으로 적용됩니다.
당장 우리가 기술 면접에서 컴퓨터 구조에 대한 소양을 검증받는 이유가 이 때문이죠.</p>
<hr>
<h2 id="효율적인-설계">효율적인 설계</h2>
<p>컴퓨터 구조를 숙지하고 있으면 효율적인 설계가 가능합니다.
효율적인 설계라고 함은 <code>&quot;주어진 조건 안에서 최고의 성능을 발휘할 수 있도록 설계하는 것&quot;</code> 정도로 알아주시면 좋을 것 같습니다.</p>
<p>내가 지금 작성하는 코드가 </p>
<ul>
<li>해결하려는 문제에 적합한 코드인지? </li>
<li>해당 코드가 컴퓨팅적으로 어떤 작업을 수행하는지? </li>
<li>협업하는 동료 개발자가 쉽게 이해하고 추가 작업을 수행할 수 있는지?</li>
</ul>
<p>등을 고려하기 위해서는 아무래도 <span style="color: #12B886"><strong>컴퓨터의 본질</strong></span>을 알아야된다고 생각합니다.</p>
<hr>
<h2 id="trade-off를-고려한-하드웨어-spec-선정">Trade-Off를 고려한 하드웨어 Spec 선정</h2>
<p>프로그램을 기본적으로 하드웨어 위해서 동작합니다.</p>
<p>무작정 저렴한 하드웨어를 선택하게 된다면 프로그램이 정상작동하지 않거나 프로그램 실행 자체가 느려 정상적인 개발, 서비스 운용이 힘들 수 있습니다. 반대로 가장 성능이 좋은 최신 하드웨어를 선택하게 된다면 수백, 수천만 원까지 비용이 늘어날 수 있습니다.</p>
<p>직접적으로 하드웨어를 사용하지 않는 <span style="color: #12B886"><strong>클라우드</strong></span> 환경 또한 마찬가지입니다. 어떤 CPU를 사용할 지, 어떤 메모리와 스토리지를 사용할 지에 따라 <code>성능</code>, <code>용량</code>, <code>비용</code>이 달라지기 때문입니다. </p>
<p>즉, 현재 내게 <span style="color: #12B886"><strong>주어진 비용 안에서 최적의 성능, 용량을 확보</strong></span>하기 위해서는 컴퓨터 구조를 알아야합니다.</p>
<hr>
<p>위와 같은 이유로 우리는 컴퓨터 구조를 기본 소양으로 숙지하고 있어야 한다 생각합니다.
제가 작성한 이유 외에도 여러가지 이유가 있을 수도 있겠죠.</p>
<p>개발, 컴퓨터 엔지니어링에 가장 기초가 되는 컴퓨터 구조는 대학 1학년에 배우는 이유가 다 있습니다. <span style="color: #12B886"><strong>기초가 탄탄해야 앞으로 쌓아올릴 탑도 탄탄히 유지</strong></span>될 수 있으니까요.</p>
<p>필자는 기초가 부족하여 다시 공부하는 케이스입니다. 
처음 접하시는 분들은 저와 같은 실수를 하지 않길 바라며, 저와 같은 상황이신 분들은 같이 힘낼 수 있도록 이 글을 작성합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 데이터 타입 기본]]></title>
            <link>https://velog.io/@jnghoon_2/Swift-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-%EA%B8%B0%EB%B3%B8</link>
            <guid>https://velog.io/@jnghoon_2/Swift-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-%EA%B8%B0%EB%B3%B8</guid>
            <pubDate>Fri, 20 Jan 2023 09:02:25 GMT</pubDate>
            <description><![CDATA[<h1 id="테이터-타입이란">테이터 타입이란?</h1>
<p>데이터 타입은 프로그램 내에서 다뤄지는 데이터의 종류를 뜻한다.
스위프트의 기본 데이터 타입은 구조체를 타입의 기반으로 삼아 스위프트의 다양한 기능(익스텐션, 제네릭 등)을 두루 사용하여 구현되어 있다. 여기서 핵심적인 것은 스위프트의 기본 데이터 타입이 모두 <strong>구조체 기반</strong> 이라는 것이다. 
스위프트의 모든 데이터 타입은 대문자 카멜케이스를 사용한다.</p>
<h1 id="int와-uint">Int와 UInt</h1>
<p>Int와 UInt는 정수 타입을 나타낸다.
Int의 경우 +,- 부호를 포함한 정수를 뜻하며 이 중 - 부호를 포함하지 않고 0을 포함한 양의 정수는 UInt로 표현한다. 이들은 각각 8, 16, 32, 64비트의 형태가 존재하며 시스템 아키텍처에 따라 타입이 달라진다.</p>
<pre><code>var integer : Int = -100
let unsignedInteger : UInt = 50 // UInt 타입에는 음수값을 할당할 수 없다.

print(&quot;integer 값 : \(integer), unsignedInteger 값 : \(unsignedInteger)&quot;)
// integer 값 : -100, unsignedInteger 값 : 50
print(&quot;Int의 최댓값: \(Int.max), 최솟값: \(Int.min)&quot;)
// Int의 최댓값: 9223372036854775807, 최솟값: -9223372036854775808
print(&quot;UInt의 최댓값: \(UInt.max), 최솟값: \(UInt.min)&quot;)
// UInt의 최댓값: 18446744073709551615, 최솟값: 0

let largerInteger : Int64 = Int64.max
let smallUnsinedInteger : UInt8 = UInt8.max

print(&quot;Int64의 최댓값 : \(largerInteger), UInt8의 최댓값: \(smallUnsinedInteger)&quot;)
// Int64의 최댓값 : 9223372036854775807, UInt8의 최댓값: 255

//let tooLarge : Int = Int.max + 1 // 표현 범위를 초과하므로 오류
//let cannotbeNative : UInt = -1 // UInt는 음수값을 가질 수 없으므로 오류

//integer = unsignedInteger // Int와 UInt는 비슷하지만 엄연히 다른 타입!
integer = Int(unsignedInteger) // 형변환을 해줄 수 있다.</code></pre><p>정수표현은 다음과 값이 진수 별로 표현할 수 있다.</p>
<ul>
<li>10진수 : 평소에 사용하는 숫자를 사용</li>
<li>2진수 : 접두어 0b를 사용하여 표현</li>
<li>8진수 : 접두어 0o를 사용하여 표현</li>
<li>16진수 : 접두어 0x를 사용하여 표현</li>
</ul>
<pre><code>let decimalInteger : Int = 28
let binaryInteger : Int = 0b11100
let octalInteger : Int = 0o34
let hexadecimalInteger : Int = 0x1C

print(&quot;\(decimalInteger), \(binaryInteger), \(octalInteger), \(hexadecimalInteger)&quot;)
// 28, 28, 28, 28</code></pre><h1 id="bool">Bool</h1>
<p>Bool은 불리언 타입이다. 참(true) 또는 거짓(false)만 값을 가진다.</p>
<pre><code>var boolean : Bool = true
boolean.toggle() // true - false 반전
let iLoveYou : Bool = true
let isTimeUnlimited : Bool = false

print(&quot;boolean의 값 : \(boolean)&quot;)
// boolean의 값 : false
print(&quot;iLoveYou의 값 : \(iLoveYou)&quot;)
// iLoveYou의 값 : true
print(&quot;isTimeUnlimited의 값 : \(isTimeUnlimited)&quot;)
// isTimeUnlimited의 값 : false
</code></pre><h1 id="float와-double">Float와 Double</h1>
<p>Float와 Double은 부동소수점을 사용하는 실수며 부동소수 타입이라고한다.
부동소수 타입은 정수 타입보다 훨씬 넓은 범위의 수를 표현할 수 있다. 
Double의 경우 64비트의 부동소수를 표현하며, Float의 경우 32비트의 부동소수를 표현한다.</p>
<p>64비트 환경에서 Double은 최소 15자리의 십진수를 표현할 수 있다. 반면에 Float의 경우 6자리의 숫자까지만 표현이 가능하다.</p>
<pre><code>// Float이 수용할 수 있는 범위를 넘어섭니다.
// Float이 표현할 수 있는 범위까지만 표현합니다.
var floatValue : Float = 1234567890.1

// 같은 수지만 Double은 수용가능합니다.
var doubleValue : Double = 1234567890.1

print(&quot;floatValue : \(floatValue)&quot;)
// floatValue : 1.234568e+09
print(&quot;doubleValue : \(doubleValue)&quot;)
// doubleValue : 1234567890.1

// Float이 수용할 수 있는 범위로 변경해줍니다.
floatValue = 123456.1

print(floatValue)
// 123456.1</code></pre><blockquote>
<p>Tip : 임의의 수 만들기
스위프트 4.2 버전부터 임의의 수를 만드는 random(int:) 메서드를 사용할 수 있다.
Int.random(int: -100, 100)
UInt = UInt.random(in: 0...30)
Float = Float.random(in: 1.5...4.3)
Double = Double.random(in: -0.5...1.5)</p>
</blockquote>
<h1 id="character">character</h1>
<p>character는 말 그대로 &#39;문저&#39;를 의미한다. 
단어, 문장처럼 문자의 집합이 아닌 단 하나의 문자를 의미하며 스위프트에서는 유니코드 9 문자를 사용하므로 영어는 물론, 유니코드에서 지원하는 모든 언어 및 특수기호 등을 사용할 수 있다. 문자를 표현하기 위해서는 값의 앞뒤에 큰따옴표를 사용하여 표현한다.</p>
<pre><code>let alphabetA : Character = &quot;A&quot;
print(alphabetA)
// A

// character 값에는 유니코드 문자를 사용할 수 있다.
let commandCharacter : Character = &quot;❤️&quot;
print(commandCharacter)
// ❤️

// 한글도 유니코드 문자에 속하므로 변수이르으로 사용가능하다.
let 한글변수이름 : Character = &quot;ㄱ&quot;
print(&quot;한글의 첫번째 자음 : \(한글변수이름)&quot;)
// ㄱ
</code></pre><h1 id="string">String</h1>
<p>String은 문자의 나열, 즉 문자열이다.
String은 Character와 마찬가지로 유니코드 9를 사용할 수 있으며, 값의 앞뒤에 큰따옴표를 사용하여 표현한다</p>
<h2 id="appand">appand()</h2>
<ul>
<li>기존 문자열에 새로운 문자열을 이어붙인다.</li>
<li>appand와 동일하게 + 연산자룰 통해서 문자열을 이어붙일 수 있다.<pre><code>let name : String = &quot;nick&quot; 
</code></pre></li>
</ul>
<p>// 이니셜라이저를 사용한 빈 문자열 생성
var introduce : String = String() // var 키워드를 사용했기 때문에 수정 가능</p>
<p>// appand()
introduce.append(&quot;제 이름은&quot;)</p>
<p>// + 연산자를 통한 이어붙이기
introduce = introduce + &quot; &quot; + name + &quot;입니다.&quot;
print(introduce)
// 제 이름은 nick입니다.</p>
<pre><code>## count
 - 문자열의 수를 계산한다.(프로퍼티)</code></pre><p>// count를 통해 문자열의 수를 확인할 수 있다.
print(&quot;name의 문자열 수 : (name.count)&quot;)</p>
<pre><code>## isEmpty
 - 빈 문자열인지 확인한다.(프로퍼티)</code></pre><p>// isEmpty를 통해 빈 문자열인지 확인 가능
print(&quot;introduce가 빈 문자열인가요? (introduce.isEmpty)&quot;)</p>
<pre><code>
## hasPrefix() &amp; has Suffix()
 - hasPrefix는 문자열의 접두어를 확인한다.
 - hasSuffix는 문자열의 접미어를 확인한다.
 - 특정 문자열을 포함하는지 확인하는 것이 아니다.</code></pre><p>let something : String = &quot;somethigWord&quot;</p>
<p>print(something.hasPrefix(&quot;some&quot;)) // true
print(something.hasPrefix(&quot;eth&quot;))  // false
print(something.hasSuffix(&quot;Word&quot;)) // true
print(something.hasPrefix(&quot;word&quot;)) // false</p>
<pre><code>
## uppercased() &amp; lowercased()
 - upeercased는 문자열 내의 모든 문자를 대문자로 변환한다.
 - lowercased는 문자열 내의 모든 문자를 소문자로 변환한다.</code></pre><p>let hello : String = &quot;Hello&quot;</p>
<p>print(hello.uppercased()) // HELLO
print(hello.lowercased()) // hello</p>
<pre><code>
&gt; Tip : 코드상에서 여러 줄의 문자열을 직접쓰고 싶을 때
큰따옴표 세 개를 사용한다.</code></pre><p>let word : String = &quot;&quot;&quot;
this
is
swift
&quot;&quot;&quot;</p>
<pre><code>
## 특수문자
 - 문자열 내에서 일정 기능을 하는 특수문자가 존재한다.
 - 특수문자를 표현하고 싶은경우 백슬래시와 조합하여 사용한다.
 - \n : 줄바꿈 문자
 - \\ : 문자열 내에서 백슬래시(\)를 표현하고자 할 때 사용
 - \&quot; : 문자열 내에서 큰따옴표(&quot;)를 표현하고자 할 때 사용
 - \t : 탭 문자, 키보드의 탭키를 눌렀을 때와 같은 효과
 - \0 : 문자열이 끝났음을 알리는 null 문자


# Any, AnyObject와 nill
## Any
Any는 스위프트의 모든 데이터 타입을 사용할 수 있다는 뜻이다.
변수 또는 상수의 데이터 타입이 Any로 지정되어 있다면 그 변수 또는 상수에는 모든 타입이 할당 가능하다.</code></pre><p>var anyVar : Any = &quot;String&quot;
anyVar = 50 // 아무 타입이나 할당 가능하기 때문에 오류 없음.
anyVar = 1.23 // 아무 타입이나 할당 가능하기 때문에 오류 없음.</p>
<pre><code>
## AnyObject
Any 보다는 조금 한정된 의미로 클래스의 인스턴스만 할당 가능하다.

## nil
&#39;없음&#39;을 나타내는 스위프트의 키워드
변수 또는 상수에 값이 들어있지 않고 비어있음을 나타내는 데 사용한다.
다른 언어, 특히 C++, Java, Python에서 사용되는 Null 키워드와 동일하다고 보면된다.

## Any와 AnyObject는 가능하면 사용하지 말자.
Any와 AnyObject는 될 수 있으면 사용하지 안흔 편이 좋다. 타입에 엄격한 스위프트의 특성상 Any 또는 AnyObject로 선언된 변수의 값을 가져다 쓰려면 매번 타입 확인 및 변환을 해줘야 하는 불편함이 있을뿐더러 예기치 못한 오류의 위험을 증가시키기 때문이다. 될 수 있으면 항상 타입을 명시하는 것이 좋다.
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 변수와 상수]]></title>
            <link>https://velog.io/@jnghoon_2/Swift-%EB%B3%80%EC%88%98%EC%99%80-%EC%83%81%EC%88%98</link>
            <guid>https://velog.io/@jnghoon_2/Swift-%EB%B3%80%EC%88%98%EC%99%80-%EC%83%81%EC%88%98</guid>
            <pubDate>Sat, 07 Jan 2023 20:07:39 GMT</pubDate>
            <description><![CDATA[<p>프로그램 작성 시, 우리는 변수나 상수를 이용해 프로그램에서 사용되는 데이터를 메모리에 임시로 저장한다. 이때 변수와 상수는 특정 데이터 타입에 해당하는 값의 이름이다.
변수와 상수의 차이는 다음과 같다.</p>
<ul>
<li>변수 : 생성 후 데이터값이 변경될 수 있다.</li>
<li>상수 : 한번 값을 설정하면 추루에 변경할 수 없다.</li>
</ul>
<h1 id="변수">변수</h1>
<p>스위프트에서 변수를 생성하려면 <em><strong>var</strong></em> 키워드를 사용해야한다.
변수 선언은 다음과 같은 방식으로 선언한다.</p>
<blockquote>
<p>var [변수명]: [데이터 타입] = [값]</p>
</blockquote>
<p>변수를 생성할 때 테이터 타입은 생략할 수 있다. 이는 컴파일러가 변숫값의 타입을 추론하여 타입을 지정하는 <strong><em>타입 추론</em></strong> 을 진행하기 때문에 가능한 일이다. 타입 추론을 할 경우, 오류 발생 시 오류를 찾는 데 상당한 시간이 걸릴 수도 있으며, 컴파일 시간이 증가할 수 있다. 때문에 타입 지정을 하는 것이 좋다고 볼 수 있다.</p>
<pre><code>var name: String = &quot;nick&quot;
var age: Int = 100
var job = &quot;iOS Developer&quot; // 문자열 타입에 타입 추론 사용
var height = 199.9              // 실수 타입에 타입 추론 사용
var weight: Int = 99

age = 99        // 변수는 값을 변경 가능
job = &quot;writer&quot;  // 단, 값은 타입으로 할당해야함.

print(&quot;\(type(of: job))&quot;)    // String
print(&quot;\(type(of: height))&quot;) // Double

print(&quot;name : \(name), age : \(age), job : \(job), 
       height : \(height), weight : \(weight)&quot;)

// name : nick, age : 99, job : writer, height : 199.9, weight : 99</code></pre><h1 id="상수">상수</h1>
<p>스위프트에서는 <em><strong>let</strong></em> 키워드를 사용해서 상수를 생성한다.
선언 방식은 다음이 변수 선언과 비슷하다.</p>
<blockquote>
<p>let [상수명]: [데이터 타입] = [값]</p>
</blockquote>
<p>상수 선언도 변수 선언과 마찬가지로 데이터 타입을 생략할 수 있다.</p>
<pre><code>let name: String = &quot;nick&quot;
var age: Int = 99

name = &quot;alex&quot; // 오류 발생
age = 88

print(&quot;name : \(name), age : \(age)&quot;)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 규칙]]></title>
            <link>https://velog.io/@jnghoon_2/Swift-%EA%B7%9C%EC%B9%99</link>
            <guid>https://velog.io/@jnghoon_2/Swift-%EA%B7%9C%EC%B9%99</guid>
            <pubDate>Sat, 07 Jan 2023 19:20:18 GMT</pubDate>
            <description><![CDATA[<h1 id="기본-명명-규칙">기본 명명 규칙</h1>
<p>기본적인 규칙은 다음 가이드 라인을 준수한다.</p>
<ul>
<li>스위프트 공식 문서
<a href="https://jusung.gitbook.io/the-swift-language-guide/">https://jusung.gitbook.io/the-swift-language-guide/</a></li>
<li>스위트프 API 디자인 가이드라인
<a href="https://www.swift.org/documentation/api-design-guidelines/">https://www.swift.org/documentation/api-design-guidelines/</a></li>
<li>코코아를 위한 코딩 가이드라인
<a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html">https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html</a></li>
</ul>
<p>가이드라인 중에서 꼭 알아야할 기본 명명 규칙</p>
<ul>
<li>변수, 상수, 함수, 메서드, 타입 등의 이름은 유니코드에서 지원하는 어떤 문자라도 사용할 수 있다. 단, 다음과 같은 경우는 제외한다.<ul>
<li>스위프트에서 미리 정한 예약어 또는 키워드</li>
<li>코드 범위 내에서 사용되는 기존이름과 동일한 이름</li>
<li>연산자로 사용될 수 있는 기호</li>
<li>숫자로 시작하는 이름</li>
<li>공백이 포함된 이름</li>
</ul>
</li>
<li>함수, 메서드, 인스턴스 이름은 소문자 카멜케이스를 사용한다.</li>
<li>클래스, 구조체, 익스텐션, 프로토콜, 열거형 이름은 대문자 카멜케이스를 사용한다.</li>
<li>대소문자를 구별한다.</li>
</ul>
<blockquote>
<p>예약어
예약어는 프로그래밍 언어에서 미리 사용하기로 약속한 단어로, 식별자로 사용할 수 없다. 단, 일부 예약어는 <em>강세표(backquote, &#39;)</em> 를 사용하여 이름으로 사용할 수 있다.</p>
</blockquote>
<blockquote>
<p>키워드
키워드는 프로그래밍 언어 문법의 일부로, 특별한 의미가 있는 단어를 뜻한다.
스위프트의 키워드는 대부분 예약어이다.</p>
</blockquote>
<h1 id="콘솔-로그">콘솔 로그</h1>
<p>로그(log)는 애플리케이션의 상태 또는 애플리케이션 내부 로직의 흐름을 관찰할 수 있도록 출력한 정보를 의미한다. 콘솔 로그는 디버깅 중 콘솔창에 출력할 로그를 뜻한다. 스위프트에서는 다음과 같은 함수를 사용해 로그를 출력할 수 있다.</p>
<h2 id="print">print()</h2>
<pre><code>print(&quot;Hello Swift!!&quot;)</code></pre><p>스위프트에서 콘솔 로그를 남기는 요도로 print() 함수를 사용한다.
기본 원형은 다음과 같이 정의되어 있다.</p>
<pre><code>public func print(items: Any..., 
                  separator: String = defualt,
                  terminator: String = defualt)</code></pre><p>print() 함수는 로그 출력 후, 줄 바꿈을 해주기 위해 줄바꿈 문자(\n)를 자동을 삽입한다.</p>
<h2 id="dump">dump()</h2>
<pre><code>struct BasicInformation{
    let name: String
    var age: Int
}

var tuanInfo: BasicInformation = BasicInformation(name: &quot;Tuan&quot;, age: 99)

class Person{
    var height: Float = 0.0
    var weight: Float = 0.0
}

let tuan: Person = Person()
tuan.height = 999
tuan.weight = 888

dump(tuanInfo)
/*
▿ __lldb_expr_1.BasicInformation
  - name: &quot;Tuan&quot;
  - age: 99
*/

dump(tuan)
/*
▿ __lldb_expr_1.Person #0
  - height: 999.0
  - weight: 888.0
*/</code></pre><p>dump() 함수는 print()보다 조금 더 자세한 정보를 출력한다.
print() 함수는 출력하려는 인스턴스의 description 프로퍼티에 해당하는 내용을 출력 해주는 방면, dump() 함수는 출력하려는 인스턴스의 자세한 내부 콘텐츠까지 출력한다. </p>
<h2 id="문자열-보간법">문자열 보간법</h2>
<p>문자열 보간법(String InterPolation)은 변수 또는 상수 등의 값을 문자열 내에 나타내고 싶을 때 사용한다. 문자열 내에 \(변수 또는 상수)의 형태로 표기하면 문자열로 치환해서 넣는다. 문자열 보간법을 이용해 원하는 문자열로 치환하려면 변수나 상수 타입을 CustomStringConertible 프로토콜을 준수라는 description 프로퍼티로 구현해야한다.</p>
<pre><code>let name: String = &quot;Tuan&quot;
print(&quot;My name is \(name)&quot;)

// My name is Tuan</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 개요]]></title>
            <link>https://velog.io/@jnghoon_2/Swift-%EA%B0%9C%EC%9A%94</link>
            <guid>https://velog.io/@jnghoon_2/Swift-%EA%B0%9C%EC%9A%94</guid>
            <pubDate>Fri, 06 Jan 2023 18:01:04 GMT</pubDate>
            <description><![CDATA[<h1 id="스위프트란">스위프트란?</h1>
<ul>
<li>애플에서 자사의 제품 개발에 활용하고자 제작한 프로그래밍 언어</li>
<li>안전을 우선으로 하는 프로그래밍 패턴을 지향</li>
<li>옵셔널, 제네릭, 프로토콜, 튜플, 익스텐션 등 지원</li>
<li>ARC(Automatic Reference Counting, 자동 참조 횟수 계산) 지원
  → 메모리를 쉽게 관리할 수 있음.</li>
<li>소괄호(<strong>()</strong>), 세미콜론(<strong>;</strong>) 생략 가능 but, 중괄호(<strong>{}</strong>) 생략 불가</li>
</ul>
<h1 id="스위프트의-언어적-특성">스위프트의 언어적 특성</h1>
<h2 id="안전성safe">안전성(Safe)</h2>
<ul>
<li>스위프트는 안전한 프로그래밍을 지향</li>
<li>엄격한 문법을 적용해 실수를 미연에 방지</li>
<li>옵셔널, guard 구문, 오류처리, 강력한 타입 통제 등을 사용</li>
</ul>
<h2 id="신속성fast">신속성(Fast)</h2>
<ul>
<li>C 언어 수준의 동등한 성능을 일정한 수준으로 유지하는데 초점을 맞춰 개발</li>
<li>실행 속도 최적화 및 컴파일러의 지속적 개량</li>
</ul>
<h2 id="더-나은-표현성expressive">더 나은 표현성(Expressive)</h2>
<ul>
<li>현대적이고 세련된 문법 구사 가능</li>
<li>계속된 업데이트를 통해 발전할 예정</li>
</ul>
<h1 id="프로그래밍-패러다임">프로그래밍 패러다임</h1>
<p>스위프트는 여러 가지 프로그래밍 패러다임을 차용한 다중 패러다임 프로그래밍 언어이다. 스위프트가 채용한 프로그래밍 패러다임은 다음과 같다.</p>
<ul>
<li>명령형 프로그래밍 패러다임</li>
<li>객체지향 프로그래밍 패러다임</li>
<li>함수형 프로그래밍 패러다임</li>
<li>프로토콜 프로그래밍 지향 패러다임</li>
</ul>
<p>정확히는 <strong>(명령형 + 객체지향) 기반의 함수형 + 프로토콜 지향</strong> 이다.</p>
<p>애플은 특히 함수형 프로그래밍 패러다임을 강조한다. 이는 애플의 프레임워크를 벗어나 다른 영역에서 스위프트를 사용했을 때 순수하게 함수형 프로그래밍 패러다임만으로 프로그램을 작성할 수 있기 때문이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[순환(재귀)]]></title>
            <link>https://velog.io/@jnghoon_2/%EC%88%9C%ED%99%98%EC%9E%AC%EA%B7%80</link>
            <guid>https://velog.io/@jnghoon_2/%EC%88%9C%ED%99%98%EC%9E%AC%EA%B7%80</guid>
            <pubDate>Wed, 12 Oct 2022 02:03:13 GMT</pubDate>
            <description><![CDATA[<p>순환을 알아 보기에 앞서서 순환과 반복은 다르다는 것을 알아두자!</p>
<p>순환 : 알고리즘이나 함수가 수행 도중에 자기 자신을 다시 호출하여 문제를 해결하는 기법
반복 : 말그대로 반복하여 문제를 해결하는 기법
<img src="https://velog.velcdn.com/images/jnghoon_2/post/68d91c4e-2832-443f-9e08-690c1b785087/image.png" alt=""></p>
<h1 id="순환">순환</h1>
<p>순환(recursion)이란 어떤 알고리즘이나 함수가 자기 자신을 호출하여 문제를 해결하는 프로그래밍 기법이다.</p>
<p>순환은 많은 문제들을 해결하는데 독특한 개념적인 프레임 워크를 제공한다.
본질적으로 순환적인 문제나 그러한 자료구조를 다루는 프로그램에 적합하다.</p>
<p>팩토리얼 문제가 가장 잘 알려진 순환 문제이다. 다음 코드를 살펴보자.</p>
<pre><code>int factorial(int n)
{
      if(n == 1) return 1;
      else return (n * factorial(n - 1));
}</code></pre><p>위 함수를 살펴보면 함수 내부에서 자기 자신을 불러온다는 것을 알 수 있다.
이처럼 자기 자신을 불러오는 함수를 <strong>재귀함수(recursive function)</strong>이라고 한다.
더 나아가서 위 함수가 진행되는 순서를 살펴보자</p>
<pre><code>int factorial(3)
{
      if(n == 1) return 1;
      else return (3 * factorial(3 - 1));
}
//-&gt; factorial(2)를 호출한다.
int factorial(2)
{
      if(n == 1) return 1;
      else return (2 * factorial(2 - 1));
}
//-&gt; factorial(1)을 호출한다.
int factorial(1)
{
      if(n == 1) return 1; // 조건문이 참이므로 1을 return한다.
      else return (n * factorial(n - 1)); 
}</code></pre><p>이와 같이 factorial(3)에서 시작하여 factorial(2), factorial(1)을 순차적으로 호출하는 것을 알 수 있다</p>
<h1 id="순환-호출의-내부적인-구현">순환 호출의 내부적인 구현</h1>
<p>main()에서 factorial(3)을 호출했을 때 시스템 스택을 확인해보면</p>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/beb26253-fa43-48cb-9827-d0242a8de733/image.png" alt="">
다음과 같이 순환의 호출이 중첩될수록 시스템 스택에 활성 레코드들이 쌓이게 된다.
· 활성 레코드: 함수를 위한 시스템 스택에서의 공간</p>
<h1 id="순환의-알고리즘">순환의 알고리즘</h1>
<p>recursive 함수는 자기 자신을 순환적으로 호출하는 함수이다.
만약 함수 내에 순환호출을 멈추는 부분이 없다면 시스템 스택을 다 사용할 때까지 순환적으로 호출되다가 결국 에러를 내면서 멈출 것이다. → 순환을 break 시켜주는 코드가 반드시 필요하다.</p>
<h1 id="순환-↔-반복">순환 ↔ 반복</h1>
<p>반복문을 사용하면 일정한 횟수 동안 반복을 시키거나 어떤 조건에 만족될 때까지 걔속해서 반복시킬 수 있다. 많은 경우 이러한 반복 구조는 문제를 간결하고 효율적으로 해결할 수 있으며 우리가 익숙한 방식이다. 하지만 어떠한 경우에는 반복을 사용하면 할 수록 문제가 복잡해지는 경우가 있다. 이런 경우 순환이 매우 좋은 해결책이 될 수 있다. </p>
<p>다시 한번 말하지만 순환과 반복은 다른 개념이다.</p>
<h1 id="순환의-원리">순환의 원리</h1>
<p>순환은 분할 정복(divide and conquer)을 사용한다. 
· 분할 정복(divide and conquer): 주어진 문제를 저 작은 동일한 문제들로 분해하여 해결하는 방법
※ 순환 호출이 일어날 수록 문제의 크기가 작아진다</p>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/7381d1ba-05ff-4c0f-b504-80239c340109/image.png" alt=""></p>
<p>순환은 문제를 나누어 해결하는 분할 정복 방법을 사용한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리스트]]></title>
            <link>https://velog.io/@jnghoon_2/%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@jnghoon_2/%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Wed, 12 Oct 2022 01:47:44 GMT</pubDate>
            <description><![CDATA[<h1 id="리스트란">리스트란?</h1>
<p>리스트(list) 또는 선형 리스트(linear list)는 자료를 정리하는 방법 중의 하나이다.
리스트에는 보통 항목들이 차례대로 정리되어 있다, 리스트의 항목들은 순서 또는 위치를 가진다. 리스트는 집합과는 다르다. 집합은 각 항목 간에 순서의 개념이 없지만 리스트에 들어 있는 항목들 사이에는 순서가 있다. 
<img src="https://velog.velcdn.com/images/jnghoon_2/post/6fd8b83a-3f1e-42cb-acec-83b2f5557264/image.png" alt=""></p>
<p>리스트는 스택, 큐, 덱과 같은 선형 자료구조이다.</p>
<p>이 때 선형이란 항목들이 일렬로 순서대로 들어 있는 것을 의미한다. 리스트와 이들 자료구조의 차이는 항목에 대한 접근 방법이다.</p>
<p>스택, 큐, 덱에서 자료의 접근은 전단(front)와 후단(rear)에 제한 되어 있다.
→ 세로운 항목에 대한 삽입이나 삭제 연산이 맨 앞이나 맨 뒤로 제한 되어있다.
→ 중간에 새로운 객체를 삽입하거나 삭제할 수 없다.</p>
<p>리스트는 위의 제한이 없다. 즉, 임의의 위치에 있는 항목에 대한 연산을 허용한다는 것이다. → 선형 자료구조들 중에서 가장 많이 활용되는 이유</p>
<h1 id="리스트의-추상-자료형">리스트의 추상 자료형</h1>
<p>리스트에는 다음과 같은 연산들이 필요할 것이다.</p>
<ul>
<li>리스트의 어떤 위치에 새로운 요소를 삽입한다.</li>
<li>리스트의 어떤 위치에 있는 요소를 삭제한다.</li>
<li>리스트의 어떤 위치에 있는 요소를 반환한다.</li>
<li>리스트가 비어 있는지를 검사한다.</li>
<li>리스트가 가득 차있는지를 검사한다.</li>
<li>리스트에 어떤 요소가 있는지를 검사한다.</li>
<li>리스트의 어떤위치에 있는 요소를 새로운 요소로 대치한다.</li>
<li>리스트 안의 요소의 개수를 센다.</li>
<li>리스트 안의 모든 요소를 출력한다.</li>
</ul>
<p>이 외에도 많은 추가적인 연산을 만들 수 있다.</p>
<table>
<thead>
<tr>
<th>객체</th>
<th>임의의 접근 방법을 제공하는 같은 타입 요소들의 순서 있는 모임</th>
</tr>
</thead>
<tbody><tr>
<td>연산</td>
<td>insert(pos, item): 리스트의 pos 위치에 새로운 요소 item을 삽입한다.</td>
</tr>
<tr>
<td></td>
<td>delete(pos): 리스트의 pos 위치에 있는 요소를 삭제한다.</td>
</tr>
<tr>
<td></td>
<td>getEntry(pos): 리스트의 pos 위치에 있는 요소를 반환한다.</td>
</tr>
<tr>
<td></td>
<td>isEmpty(): 리스트가 비어 있는지를 검사한다.</td>
</tr>
<tr>
<td></td>
<td>isFull(): 리스트가 가득 차 있는지를 검사한다.</td>
</tr>
<tr>
<td></td>
<td>find(item): 리스트에 요소 item이 있는지를 살핀다.</td>
</tr>
<tr>
<td></td>
<td>replace(pos item): 리스트의 pos 위치에 있는 요소를 새로운 요소 item으로 교체한다.</td>
</tr>
<tr>
<td></td>
<td>size(): 리스트 안의 요소의 개수를 반환한다.</td>
</tr>
<tr>
<td></td>
<td>display(): 리스트 안의 모든 요소들을 출력한다.</td>
</tr>
</tbody></table>
<h1 id="배열로-구현한-리스트">배열로 구현한 리스트</h1>
<h2 id="1-삽입-연산">1. 삽입 연산</h2>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/fcd7543d-fa31-47da-897c-6b58039f11f3/image.png" alt=""></p>
<h2 id="2-삭제-연산">2. 삭제 연산</h2>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/a6294e6a-d4d0-45cc-a48e-26dd169277d4/image.png" alt=""></p>
<h1 id="연결-리스트로-구현된-리스트">연결 리스트로 구현된 리스트</h1>
<h2 id="1-삽입-연산-1">1. 삽입 연산</h2>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/599d43be-0cbe-458b-b92a-1ff6b6ed0465/image.png" alt=""></p>
<h2 id="2-삭제-연산-1">2. 삭제 연산</h2>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/2a630bdf-5523-4481-b955-ea365f04a56b/image.png" alt=""></p>
<p>※주의
노드를 삭제하기 위해서는 삭제할 노드가 아니라 삭제할 노드의 선행 노드를 알아야 한다.</p>
<p>시작 노드 표현 방법: 헤드 포인터와 헤드 노드
배열로 리스트를 구현하는 것과 달리 연결 리스트에서는 시작 노드의 주소만을 관리한다.
시작 노드의 주소(헤드 포인터)를 멤버 변수로 선언하는 방법(헤드 포인터 방식)이 아닌 다름 방법으로 표현할 수 있다.</p>
<pre><code>class LinkedList { // 단순 연결 리스트 클래스
   Node org;       // 헤드 노드 org를 멤버로 가지는 경우
...                // 실제 헤드 포인터는 org.link가 된다.
}</code></pre><p>이 방법은 시작 노드를 가리킬 포인터 변수가 아니라 노드 객체를 리스트의 데이터 멤버로 갖는다. 이와 같은 노드를 <strong>헤드 노드(Head Node)</strong>라 부른다.</p>
<p>헤드노드는 의미 있는 데이터를 가지지 않고 단지 삽입, 삭제 코드를 간단하게 할 목적으로 리스트 클래스에 하나의 노드 객체를 선언하여 사용하는 것이다. 실질적인 연결 리스트의 시작 노드는 헤드 노드의 링크 필드가 가리키고 있다. </p>
<h1 id="단순-연결-리스트를-통한-구현">단순 연결 리스트를 통한 구현</h1>
<p>Node.h</p>
<pre><code>#pragma once
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#define MAX_STACK_SIZE    100

inline void error( char* str ) {
    fprintf(stderr, &quot;%s\n&quot;, str);
    exit(1);
};

class Node
{
    Node*    link;
    int        data;

public:
    Node( int val=0) : data(val), link(NULL) { }
    Node* getLink()        { return link; }
    void setLink(Node* next)    { link = next; }
    void display()         { printf(&quot; &lt;%2d&gt;&quot;, data); }
    bool hasData(int val)     { return data == val; }

    void insertNext( Node *n ) {
        if( n != NULL ) {
            n-&gt;link = link;
            link = n;        
        }
    }

    Node* removeNext( ) {
        Node* removed = link;
        if( removed != NULL )
            link = removed-&gt;link;
        return removed;
    }
};</code></pre><p>LinkedList.h</p>
<pre><code>#pragma once

#include &quot;Node.h&quot;
class LinkedList
{
    Node    org;    // 헤드 노드 (헤드 포인터가 아님)

public:
    LinkedList(): org(0) { }    
    ~LinkedList() { clear(); }    

    void clear()  { while(!isEmpty()) delete remove(0); }
    Node* getHead()        { return org.getLink(); }
    bool isEmpty( )        { return getHead()==NULL; }

    Node* getEntry(int pos) {
        Node* n = &amp;org;
        for(int i=-1 ; i&lt;pos ; i++, n=n-&gt;getLink())
            if( n == NULL ) break;
        return n;
    }

    void insert(int pos, Node *n) {
        Node* prev = getEntry(pos-1);
        if( prev != NULL )
            prev-&gt;insertNext( n );
    }

    Node* remove(int pos) {
        Node* prev = getEntry(pos-1);
        return prev-&gt;removeNext();
    }

    Node* find(int val) {
        for( Node *p = getHead() ; p != NULL ; p=p-&gt;getLink() )
            if( p-&gt;hasData( val ) ) return p;
        return NULL;
    }

    void replace(int pos, Node *n) {
        Node* prev = getEntry(pos-1);
        if( prev != NULL ) {
            delete prev-&gt;removeNext( );
            prev-&gt;insertNext( n );
        }
    }

    int size( ){
        int count = 0;
        for( Node *p = getHead() ; p != NULL ; p=p-&gt;getLink() )
            count++;
        return count;
    }

    void display( ) {
        printf( &quot;[단순연결리스트 항목 수 = %2d] : &quot;, size());
        for( Node *p = getHead() ; p != NULL ; p=p-&gt;getLink() )
            p-&gt;display();
        printf( &quot;\n&quot;);
    }

    void reverse() {
        for (Node *p = getHead(); p != NULL; p = p-&gt;getLink())
        {
            int cnt = 0;
            for (int i = 0; i &lt; size(); i++) {
                Node *p = remove(size() - 1);
                insert(cnt++, p);
            }
        }
    }

    void Arrageinsert(Node *n) {
        Node *low = 0;
        Node *high = 0;
        Node *std = getEntry(0);
        if (std != NULL)
        {
            if (n &gt;= low)
                low = n;
            else if (n &lt;= high)
                high = n;

            if (n &lt;= low)
            {
                n-&gt;getLink = high-&gt;getLink;
                high-&gt;getLink = n;
            }
            else if (high &lt;= n)
            {
                std-&gt;insertNext(n);
            }
        }
    }
};</code></pre><h1 id="다양한-형태의-연결-리스트">다양한 형태의 연결 리스트</h1>
<h2 id="1-원형-연결-리스트circular-linked-list">1. 원형 연결 리스트(circular linked list)</h2>
<p>원형 연결 리스트는 리스트의 마지막 노드의 링크가 첫 번째 노드를 가리키는 연결 리스트를 말한다. → 마지막 노드의 링크가 NULL이 아닌 첫 번째 노드의 주소</p>
<p>원형 연결 리스트는 한 노드에서 다른 모든 노드로의 접근이 가능하다는 점이 있다.</p>
<h2 id="2-이중-연결-리스트double-linked-list">2. 이중 연결 리스트(double linked list)</h2>
<p>단순 연결 리스트는 어떤 노드에서 후속 노드를 찾기는 쉽지만 선행 노드를 찾기는 매우 어려운 구조이다. 즉, 헤드 포인터부터 시작해서 리스트 항목에 대한 탐색이 필요하다.
이중 연결 리스트는 하나의 노드가 선행 노드와 후속 노드에 대한 두개의 링크를 가지는 리스트이다.</p>
<p>링크가 양방향이므로 양방향 검색이 가능해진다. 단점으로는 공간을 많이 차지하고 코드가 복잡해진다는 것이 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[연결 리스트]]></title>
            <link>https://velog.io/@jnghoon_2/%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@jnghoon_2/%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Wed, 12 Oct 2022 01:09:52 GMT</pubDate>
            <description><![CDATA[<h1 id="연결리스트란">연결리스트란?</h1>
<p>스택과 큐 등의 자료구조를 배열을 이용하여 구현하면 구현이 간단하고 빠르다는 장점이 있지만 크기가 고정된다는 단점이 있다.</p>
<p>즉, 배열은 처음에 설정한 공간이 가득 차면 더 이상 데이터를 추가할 수 없다.
연결된 표현(linked representation)을 사용하면 이러한 문제를 해결할 수 있다.</p>
<p>연결된 표현은 데이터와 링크로 구성되어있고 링크가 노드들을 연결하는 역할을 한다.</p>
<p>연결된 표현의 특징</p>
<ul>
<li>데이터를 한군데 모아두는 것을 포기한다.</li>
<li>데이터들은 메인 메모리상의 어디에나 흩어져서 존재할 수 있다.</li>
<li>순서를 유지하기 위해 각각의 데이터는 다음 데이터를 가리키는 줄을 가진다.</li>
<li>첫 데이터에서부터 순서대로 줄을 따라가면 모든 데이터를 방문할 수 있다.
<img src="https://velog.velcdn.com/images/jnghoon_2/post/fe776e13-bbe2-4b54-ad15-3ffed032c113/image.png" alt=""></li>
</ul>
<p>이와 같이 물리적으로 흩어져 있는 자료들을 서로 연결하여 하나로 묶는 방법을 <strong>연결 리스트(linked list)</strong>라고 한다.</p>
<p>일반적으로 자료들을 연결하는 줄을 포인터로 구현한다. 포인터를 사용하면 하나의 자료에서 다음 자료로 쉽게 이동할 수 있다.</p>
<p>연결리스트는 배열과 대응되는 의미로 다음과 같은 장점들이 있다.</p>
<ul>
<li>크기가 고정되지 않는다.</li>
<li>중간에 자료를 삽입하는 것이 가능하며 용이하다.</li>
<li>중간에 있는 자료를 삭제하는 것이 가능하며 용이하다.</li>
<li>데이터 저장을 위한 메모리를 공간이 필요할 때마다 동적으로 만들어 쉽게 추가할 수 있다.</li>
</ul>
<p>이러한 장점들이 있지만 구현이 어렵고 오류가 나기 쉽다는 단점이 있다.</p>
<h1 id="연결-리스트의-구조">연결 리스트의 구조</h1>
<h2 id="노드node">노드(Node)</h2>
<p>위 그림의 상자를 노드라고 한다. 연결 리스트는 노드들의 집합이며 이들은 데이터를 저장하고 서로 연결되어 있다.</p>
<p>일반적인 노드는 데이터 필드(data field)와 링크 필드(link field)로 구성되어 있다.
데이터 필드에는 우리가 저장하고 싶은 자료가 저장되고, 링크 필드에는 다른 노드의 주소를 저장하는 포인터 변수가 저장된다.
→ 링크 필드의 주소를 통해 현재 노드에 연결된 다음 노드를 알 수 있다.</p>
<h2 id="헤드-포인터head-pointer">헤드 포인터(Head Pointer)</h2>
<p>연결 리스트는 첫 번 째 노드를 알면 링크로 연결되 있는 전체 노드에 모두 접근할 수 있다. 따라서 연결리스트에서는 첫 번째 노드를 가리키는 포인터가 필요한데 이 포인터를 헤드 포인터라고 한다.
연결리스트의 마지막 노드는 더 이상 연결할 노드가 없는데, 링크 필드 값을 NULL로 설정함으로서 이 노드가 마지막 노드임을 표현한다.</p>
<h1 id="연결-리스트의-종류">연결 리스트의 종류</h1>
<p>연결 리스트에는 세가지 종류가 있다.
첫 번째로 단순 연결 리스트(singly linked list)는 하나의 방향으로만 연결되어 있으며,
마지막 노드의 링크 필드는 NULL 값을 가진다.
<img src="https://velog.velcdn.com/images/jnghoon_2/post/1c80d47c-4a19-4d42-8b52-8e5772c4f0b0/image.png" alt=""></p>
<p>두 번째로 원형 연결 리스트(circular linked list)는 단순 연결 리스트와 같지만 마지막 노드의 링크 값이 다시 첫 번째 노드를 가리킨다.
<img src="https://velog.velcdn.com/images/jnghoon_2/post/6a05d9da-3900-463a-95df-bcadaf49679f/image.png" alt=""></p>
<p>마지막으로 이중 연결 리스트(doubly linked list)는 각 노드마다 링크 필드가 2개씩 존재하며 각각의 노드는 선행 노드와 후속 노드를 모두 가리킬 수 있다.
 <img src="https://velog.velcdn.com/images/jnghoon_2/post/39411f60-bee2-42f4-92f8-610d4f680d6d/image.png" alt=""></p>
<h1 id="연결리스트로-구현한-스택의-구조">연결리스트로 구현한 스택의 구조</h1>
<p>배열을 이용한 스택과는 다르게 연결된 스택에서는 각 요소들을 한거번에 할당하지 않고 필요할 때마다 하나씩 동적으로 할당한다. 연결된 스택에서는 스택에 저장할 요소(데이터 필드)와 함께 다음 노드를 가리키기 위한 포인터(링크 필드)를 데이터 멤버로 가지는 노드 클래스를 추가로 정의한다.</p>
<p>배열로 구현된 스택에서 배열의 인덱스를 나타내던 top은 이제 포인터 변수가 되야한다.
→ 배열로 구현된 스택에서의 top이 연결 리스트로 구현된 스택에서는 헤드 포인터이다.</p>
<p>마지막 노드의 링크 필드는 마지막임을 나타내기 위해 값이 NULL이 된다.</p>
<h1 id="연결된-스택의-동작">연결된 스택의 동작</h1>
<h2 id="삽입-연산">삽입 연산</h2>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/1aa2aef0-6b38-42a8-beda-581d84d9ac0e/image.png" alt="">
(1) 노드 D의 링크 필드가 노드 C를 가리키도록 한다. p-&gt;link = top;
(2) 헤드 포인트 top이 노드 D를 가리키도록 한다. top = p; </p>
<h2 id="삭제-연산">삭제 연산</h2>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/d4240644-0b6d-4d02-a6ff-24e28db52b7b/image.png" alt="">
(1) 포인터 변수 p 가 노드 C를 가리키도록 한다. p = top;
(2) 헤드 포인터가 노드 B를 가리키도록 한다. top = p-&gt;Next; == top = top-&gt;link;
(3) 포인터 p를 반환 한다. return p;</p>
<p>연결된 스택에서의 공백상태는 헤드 포인터 top의 값이 NULL일 경우이다. 
포화 상태는 동적 메모리 할당을 하기 때문에 없는 것이나 마찬가지다. </p>
<h1 id="연결-리스트로-구현한-큐의-구조">연결 리스트로 구현한 큐의 구조</h1>
<p>스택과 마찬가지로 큐도 연결리스트를 이용해 구현할 수 있다.
연결된 큐도 메모리 공간에서 물리적으로 흩어져 있는 노드들로 이루어진다. 원형 큐에서 front와 rear가 배열의 인덱스를 나타내는 반면에 연결된 큐에서는 이들은 포인터 변수가 된다. front는 큐에 가장 먼저 삽입된 노드를, rear는 가장 최근에 삽입된 노드를 가리킨다.
각 노드들은 다음 노드를 가리키는 링크 필드를 가지며, 마지막 노트의 링크 필드는 NULL이 되어 더 이상 연결된 요소가 없음을 나타낸다.</p>
<h1 id="연결된-큐의-연산">연결된 큐의 연산</h1>
<h2 id="삽입-연산-1">삽입 연산</h2>
<p>연결된 큐가 공백 상태일 경우
<img src="https://velog.velcdn.com/images/jnghoon_2/post/1e5c199f-e0c0-442b-a718-c185366f98c2/image.png" alt="">
연결된 큐가 공백 상태가 아닐 경우
<img src="https://velog.velcdn.com/images/jnghoon_2/post/a60386bd-3e65-4055-a120-bc0705e1bbff/image.png" alt=""></p>
<p>1) rear가 가리키는 노드 C가 노드 temp를 가리키도록한다. rear-&gt;link = temp;
(2) rear가 이제 노드 p를 가이키도록 한다. rear = temp;</p>
<h2 id="삭제-연산-1">삭제 연산</h2>
<p>노드가 둘 이상인 연결된 큐에서의 삭제 연산
<img src="https://velog.velcdn.com/images/jnghoon_2/post/001b42fa-2c0a-4d23-a847-595277b0b52b/image.png" alt=""></p>
<p>노드가 하나 있는 연결된 큐에서의 삭제 연산
<img src="https://velog.velcdn.com/images/jnghoon_2/post/3bfa5d7e-b9eb-4ef7-984a-451836487a5f/image.png" alt=""></p>
<p>(1) front가 가리키는 노드A를 temp가 가리키도록 한다. temp = front;
(2) front가 다음 노드 B를 가리키도록한다. front = temp-&gt;link;
만약 노드가 하나뿐이면 rear도 NULL로 만들어 주어야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[덱]]></title>
            <link>https://velog.io/@jnghoon_2/%EB%8D%B1</link>
            <guid>https://velog.io/@jnghoon_2/%EB%8D%B1</guid>
            <pubDate>Wed, 12 Oct 2022 01:01:39 GMT</pubDate>
            <description><![CDATA[<h1 id="덱deque이란">덱(deque)이란?</h1>
<p>덱(deque)은 double-ended queue의 줄임말로 큐의 front와 rear에서 모두 삽입과 삭제가 가능한 큐를 말한다. 하지만 여전히 중간에서 삽입하거나 삭제하는 것은 허용하지 않는다.</p>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/31909640-564f-4211-ad59-d61421c8173c/image.png" alt=""></p>
<h1 id="덱의-추상-자료형">덱의 추상 자료형</h1>
<table>
<thead>
<tr>
<th>객체</th>
<th>전단과 후단을 통한 접근을 허용하는 요소들의 모음</th>
</tr>
</thead>
<tbody><tr>
<td>연산</td>
<td>addFront(e): 주어진 요소 e를 덱의 맨 앞에 추가한다.</td>
</tr>
<tr>
<td></td>
<td>deleteFront(): 덱이 비어 있지 않으면 맨 앞 요소를 삭제하고 반환한다.</td>
</tr>
<tr>
<td></td>
<td>addRear(e): 주어진 요소 e를 덱의 맨 뒤에 추가한다.</td>
</tr>
<tr>
<td></td>
<td>deleteRear(): 덱이 비어 있지 않으면 맨 뒤 요소를 삭제하고 반환한다.</td>
</tr>
<tr>
<td></td>
<td>isEmpty(): 덱이 비어 있지 않으면 true, 아니면 false를 반환한다.</td>
</tr>
<tr>
<td></td>
<td>getFront(): 덱이 비어 있지 않으면 맨 앞 요소를 삭제하지 않고 반환한다.</td>
</tr>
<tr>
<td></td>
<td>getRear(): 덱이 비어 있지 않으면 맨 뒤 요소를 삭제하지 않고 반환한다.</td>
</tr>
<tr>
<td></td>
<td>isFull(): 덱이 가득 차 있으면 true, 아니면 false를 반환한다.</td>
</tr>
<tr>
<td></td>
<td>display(): 덱의 모든 요소들을 출력한다.</td>
</tr>
</tbody></table>
<h1 id="배열을-이용한-원형-덱의-구현">배열을 이용한 원형 덱의 구현</h1>
<p>배열을 이용한 원형 덱의 동작은 원형 큐와 거의 비슷하다.</p>
<p>앞에서 큐 클래스를 설계하여 구현했으므로 덱을 큐 클래스를 이용해서 설계해보면</p>
<pre><code>#pragma once
#include &quot;CircularQueue.h&quot;

class CircularDeque : public CircularQueue {
public:
    CircularDeque()    { }
    void addRear( int val ) { enqueue(val);} // enqueue() 호출
    int deleteFront( ) { return dequeue(); } // dequeue() 호출
    int getFront( )    { return peek(); }     // peek() 호출
    void addFront( int val ) {        // 전단에 삽입        
        if( isFull() )
            error(&quot;  error: 덱이 포화상태입니다\n&quot;);
        else {
            data[front] = val;
            front = (front-1+MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE;
        }
    }
    int deleteRear( ) {        // 후단에서 삭제
        if( isEmpty() )
            error(&quot;  Error: 덱이 공백상태입니다\n&quot;);
        else {
            int ret = data[rear];
            rear = (rear-1+MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE;
            return ret;
        }
    }
    int getRear( ){            // 후단에서 peek
        if( isEmpty() )
            error(&quot;  Error: 덱이 공백상태입니다\n&quot;);
        else return data[rear];
    }
    void display( ) {        
        printf( &quot;덱의 내용 : &quot;);    
        int maxi = (front &lt; rear) ? rear : rear+MAX_QUEUE_SIZE;
        for( int i = front+1 ; i&lt;=maxi ; i++ )
            printf( &quot;[%2d] &quot;, data[i%MAX_QUEUE_SIZE]);
        printf( &quot;\n&quot;);
    }
};</code></pre><h1 id="연결된-덱">연결된 덱</h1>
<p>스택이나 큐와는 달리 덱은 전단과 후단에서 모두 삽입, 삭제가 가능하기 때문에 하나의 노드에서 알아야할 정보가 더 많다. 구체적으로는 선행노드와 후속노드를 가리키는 포인터 변수를 가져야 하는데, 이러한 구조를 <strong>이중 연결 리스트(double linked list)</strong>라고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[큐]]></title>
            <link>https://velog.io/@jnghoon_2/%ED%81%90</link>
            <guid>https://velog.io/@jnghoon_2/%ED%81%90</guid>
            <pubDate>Wed, 12 Oct 2022 00:56:34 GMT</pubDate>
            <description><![CDATA[<h1 id="큐queue란">큐(Queue)란?</h1>
<p>스택이 나중에 들어온 데이터가 먼저 나가는 구조인데 반해서 큐(Queue)는 먼저 들어온 데이터가 먼저 나가는 자료구조이다.</p>
<p>이러한 특성을 <strong>선입선출(FIFO: First In First Out)</strong>이라고 한다.</p>
<p>큐는 뒤에서 새로운 데이터가 추가되고 앞에서 데이터가 하나씩 삭제되는 구조를 가지고 있다. 구조상으로 큐가 스택과 다른 점은 스택에서 삽입과 삭제가 같은 쪽에서 일어 났지만 큐에서는 다른 쪽에서 일어난다는 것이다. 
<img src="https://velog.velcdn.com/images/jnghoon_2/post/28bffd1c-fc44-4dd2-bf7e-857068075398/image.png" alt=""></p>
<h1 id="큐의-추상-자료형">큐의 추상 자료형</h1>
<p>큐에 저장하는 자료에도 특별한 제한이 없다. 큐의 연산들도 스택과 매우 유사하다.
큐의 추상 자료형을 정의 하면 다음과 같다.</p>
<table>
<thead>
<tr>
<th>객체</th>
<th align="left">선입선출(FIFO)의 접근 방법을 유지하는 요소들의 모임</th>
</tr>
</thead>
<tbody><tr>
<td>연산</td>
<td align="left">enqueue(e): 주어진 요소 e를 큐의 맨 뒤에 추가한다.</td>
</tr>
<tr>
<td></td>
<td align="left">dequeue(): 큐가 비어 있지 않으면 맨 낲의 요소를 삭제하고 반환한다.</td>
</tr>
<tr>
<td></td>
<td align="left">isEmpty(): 큐가 비어 있으면 true, 아니면 false를 반환한다.</td>
</tr>
<tr>
<td></td>
<td align="left">peek(): 큐가 비어 있지 않으면 맨 앞의 요소를 삭제하지 않고 반환한다.</td>
</tr>
<tr>
<td></td>
<td align="left">isFull(): 큐가 가득 차 있으면 true, 아니면 false를 반환한다.</td>
</tr>
<tr>
<td></td>
<td align="left">size(): 큐의 모든 요소들의 개수를 반환한다.</td>
</tr>
<tr>
<td></td>
<td align="left">display(): 큐의 모든 요소들을 출력한다.</td>
</tr>
</tbody></table>
<p>스택에서는 top으로 불리는 변수 하나만을 이용하여 삽입과 삭제 연산의 위치를 알 수 있었지만, 큐에서는 삽입과 삭제가 후단과 전단에서 각각 독립적으로 이루어지므로 양쪽의 위치를 기억해야하고, 따라서 두개의 변수가 필요하다.</p>
<h1 id="큐의-활용">큐의 활용</h1>
<p>일상생활에서 대부분의 일들이 줄서기와 같이 먼저 들어온 순서대로 처이되는 것처럼 컴퓨터에서도 큐는 매우 광범위 하게 사용되고 있다. 컴퓨터 장치들 사이에서 데이터를 주고 받을 때 각 장치들 사이에 존재하는 속도의 차이나 시간 차이를 극복하기 위한 임시 기억 장치로 큐가 사용되는데, 이것을 버퍼(buffer)라고 한다.</p>
<h1 id="큐의-구현">큐의 구현</h1>
<h2 id="1-선형-큐">1. 선형 큐</h2>
<p>배열을 선형으로 사용하여 큐를 구현하는 방식이다. 삽입을 하기 위해서는 요소들을 이동시켜야한다. 하지만 이 방법은 매우 번거롭고 비효율적인 방법이다. 삭제 연산의 시간복잡도는 O(1)인 반면, 삽입연산의 시간 복잡도는 O(n)이다. 따라서 문제점이 많아 이 방법은 잘 사용되지 않는다.
<img src="https://velog.velcdn.com/images/jnghoon_2/post/df8d123f-582a-420b-814c-323e7e0982ac/image.png" alt=""></p>
<h2 id="2-원형-큐">2. 원형 큐</h2>
<p>배열을 선형이 아닌 원형으로 생각하면 위 선형 큐의 문제점이 해결된다.
front와 rear의 값이 배열의 끝에 도달하면 다음에 증가되는 값이 0이되도록 하는 것이다. 즉, 배열이 원형이로 처음과 끝이 연결되 있다고 생각하면 된다. 여기서 주의 해야할 것은 front와 rear의 개념이 약간 변경된다는 것이다.먼저 초기 값은 -1이 아닌 0이다.
<strong>front는 항상 큐의 첫 번째 요소의 하나 앞을, rear는 마지막 요소를 가리킨다.</strong> 다음 그림은 원형 큐에 데이터가 삽입, 삭제될 때 front와 rear의 변화를 보여준다.
<img src="https://velog.velcdn.com/images/jnghoon_2/post/98bef7c0-07ef-43f9-9c8e-90ec429eee76/image.png" alt="">
큐의 공백 강태와 포화 상태를 알아보자.</p>
<ol>
<li>공백 상태는 front와 rear의 값이 같은 상태</li>
<li>포화 상태는 원형 큐에서 하나의 자리를 제외한 나머지가 전부 차있는 상태
→ 전부 차있으면 front와 rear의 값이 같으므로 포화 상태와 공백 상태가 구별되지 않는다.</li>
</ol>
<h3 id="원형-큐의-구현">원형 큐의 구현</h3>
<pre><code>#pragma once
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

inline void error( char* str ) {
    fprintf(stderr, &quot;%s\n&quot;, str);
    exit(1);
};

#define MAX_QUEUE_SIZE    100

class CircularQueue
{
    int front;    // 첫 번째 요소의 앞의 위치                
    int rear;    // 마지막 요소의 위치                
    int data[MAX_QUEUE_SIZE];    // 요소의 배열
public:
    CircularQueue()    { front = rear = 0; }
    ~CircularQueue() { }
    bool isEmpty()    { return front == rear; }
    bool isFull()    { return (rear+1)%MAX_QUEUE_SIZE == front; }

    void enqueue( int val ) { // 큐에 삽입
        if( isFull() )
            error(&quot;  error: 큐가 포화상태입니다\n&quot;);
        else {
            rear = (rear+1) % MAX_QUEUE_SIZE;
            data[rear] = val;
        }
    }
    int dequeue( ) {    // 첫 항목을 큐에서 삭제하고 반환
        if( isEmpty() )
            error(&quot;  Error: 큐가 공백상태입니다\n&quot;);
        else {
            front = (front+1) % MAX_QUEUE_SIZE;
            return data[front];
        }
    }
    int peek( ){        // 첫 번째 항목을 큐를 삭제하지 않고 반환
        if( isEmpty() )
            error(&quot;  Error: 큐가 공백상태입니다\n&quot;);
        else 
            return data[(front+1) % MAX_QUEUE_SIZE];
    }
    void display( ) {    // 큐의 모든 내용을 순서대로 출력
        printf( &quot;큐 내용 : &quot;);
        int maxi = (front &lt; rear) ? rear : rear+MAX_QUEUE_SIZE;
        for( int i = front+1 ; i&lt;=maxi ; i++ )
            printf( &quot;[%2d] &quot;, data[i%MAX_QUEUE_SIZE]);
        printf( &quot;\n&quot;);
    }
};</code></pre><h2 id="연결-리스트로-구현한-큐">연결 리스트로 구현한 큐</h2>
<p>배열을 이용하여 구현한 큐도 스택과 같이 크기가 제한된다. 따라서 이 문제를 해결하기 위해서 연결리스트를 이용한 큐를 구현해야한다.  연결리스트로 큐를 구현할 때는 front와 rear의 두 개의 변수를 사용해야 할 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스택]]></title>
            <link>https://velog.io/@jnghoon_2/%EC%8A%A4%ED%83%9D</link>
            <guid>https://velog.io/@jnghoon_2/%EC%8A%A4%ED%83%9D</guid>
            <pubDate>Tue, 11 Oct 2022 06:21:30 GMT</pubDate>
            <description><![CDATA[<p>일상생활을 하거나 게임을 할때 가끔가다가 &#39;스택을 쌓는다.&#39; 또는 &#39;스택이 쌓였다.&#39;라는 말을 하거나 듣는 경우가 종종 있다.</p>
<p>이 &#39;스택&#39;이라는 것은 무엇으로부터 나왔으며 정확한 개념이 무엇인지 알아보겠다. </p>
<h1 id="스택이란">스택이란?</h1>
<p>스택(stack)은 가장 간단한 형태의 자료구조 중하나로, <strong>후입선출(LIFO: Last In First Out)</strong>의 형태로 일어난다. 스택은 가장 먼저 입력된 데이터가 맨 아래로 쌓이고 가장 최근에 입력된 데이터가 가장 위에 쌓이는 구조를 가지고 있다. 스택에서의 입출력은 맨 위에서만 일어나고 <em>스택의 중간에서는 데이터를 삽입하거나 삭제할 수 없다.</em></p>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/448fea7e-4cf3-452e-bf04-eaf10f5f93ef/image.png" alt=""></p>
<figcaption style="text-align:center; font-size:15px; color:#808080">
    스택의 구조 및 기능
  </figcaption>


<ul>
<li>요소(element): 스택에 저장되는 것</li>
<li>공백(empty)상태: 스택에 요소가 하나도 없는 경우</li>
<li>포화(full)상태: 스택이 꽉 차서 더 이상 요소를 넣을 수 없는 상태
※ 주의 : element가 1이면 top은 0이고, element가 0 이면 top은 -1
→ 배열은 0 부터 시작하기 때문</li>
</ul>
<h1 id="스택의-추상-자료형">스택의 추상 자료형</h1>
<table>
<thead>
<tr>
<th>객체</th>
<th align="left">후입선출(LIFO)의 접근 방법을 유지하는 요소들의 모음</th>
</tr>
</thead>
<tbody><tr>
<td>연산</td>
<td align="left">push(): 주어진 요소 x를 스택의 맨 위에 추가한다.</td>
</tr>
<tr>
<td></td>
<td align="left">pop(): 스택이 비어있지 않으면 맨 위에 있는 요소를 삭제하고 반환한다.</td>
</tr>
<tr>
<td></td>
<td align="left">isEmpty(): 스택이 비어있으면 true, 아니면 false를 반환한다.</td>
</tr>
<tr>
<td></td>
<td align="left">peek(): 스택이 비어 있지 않으면 맨 위에 있는 요소를 삭제하지 않고 반환한다.</td>
</tr>
<tr>
<td></td>
<td align="left">isFull(): 스택이 가득 차 있으면 true, 아니면 false를 반환한다.</td>
</tr>
<tr>
<td></td>
<td align="left">size(): 스택 내의 모든 요소의 개수를 반환한다.</td>
</tr>
<tr>
<td></td>
<td align="left">display(): 스택 내의 모든 요소들을 출력한다.</td>
</tr>
</tbody></table>
<p>스택에서 가장 중요한 연산은 요소를 삽입하는  push와 pop이다.
다음 그림은 초기 공백 스택에 일련의 push와 pop 연산이 진행되는 과정을 보여준다.
<img src="https://velog.velcdn.com/images/jnghoon_2/post/e685dbe9-969b-4b7d-9cd6-120eebac49fb/image.png" alt=""></p>
<figcaption style="text-align:center; font-size:15px; color:#808080">
    스택이 작동하는 원리
  </figcaption>


<p>※ peek연산은 요소를 스택에서 삭제하지 않고 보기만 하는 연산이다. 이에 비해 pop 연산은 스택에서 꺼내오기 때문에 스택에서 요소가 없어진다.</p>
<h1 id="스택의-구현">스택의 구현</h1>
<p>배열은 거의 모든 프로그래밍 언어에서 지원한다. 배열은 순차적인 메모리 공간에 할당된다고 해서 순차적 표현(sequential represention)이라고도 한다. 배열은 같은 자료형의 변수를 여러 개 만드는 경우에 특히 유용하고, 항목을 저장할 수 있는 여러 개의 공간을 제공한다. 각 공간은 정확히 하나의 항목만을 담으며 각 항목들은 인데스 번호를 통해 직접접근할 수 있다. 크기가 고정된 배열은 그 크기만큼의 상자들의 집합과 같다. 상자에는 우리가 저장하고 싶은 항목을 저장할 수 있고, 번호가 붙어 있으며 0 부터 시작한다. 다음은 C++ 배열로 구현한 int 스택 클래스이다.</p>
<pre><code>#pragma once
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#define MAX_STACK_SIZE    100

inline void error( char* str ) {
    fprintf(stderr, &quot;%s\n&quot;, str);
    exit(1);
};

class ArrayStack
{
    int data[MAX_STACK_SIZE];    // 요소의 배열
    int top;            // 요소의 개수

public:
    ArrayStack() { top = -1; }      // 스택 생성자
    ~ArrayStack(){}            // 스택 소멸자    
    bool isEmpty() { return top == -1; }
    bool isFull()  { return top == MAX_STACK_SIZE-1; }

    void push ( int e ) {           // 맨 위에 항목 삽입
        if( isFull() ) error (&quot;스택 포화 에러&quot;);
        data[++top] = e;
    }

    int pop ( ) {                    // 맨 위의 요소를 삭제하고 반환
        if( isEmpty() ) error (&quot;스택 공백 에러&quot;);
        return data[top--];
    }

    int peek ( ){                   // 맨 위의 요소를 삭제하지 않고 반환
        if( isEmpty() ) error (&quot;스택 공백 에러&quot;);
        return data[top];
    }

    void display ( ) {              // 스택 내용을 화면에 출력
        printf(&quot;[스택 항목의 수 = %2d] ==&gt; &quot;, top+1) ;
        for (int i=0 ; i&lt;=top ; i++ )
            printf(&quot;&lt;%2d&gt;&quot;, data[i]);
        printf(&quot;\n&quot;);
    }
};</code></pre><h1 id="연결-리스트를-이용한-스택">연결 리스트를 이용한 스택</h1>
<p>배열을 이용하여 구현한 스택은 구현이 간편하지만 스택의 크기가 제한 된다는 약점이 하나 있다.(동적으로 생성이 불가능하다.)
이 약점을 보완하기 위해서는 연결 리스트를 이용해야 한다. </p>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/899272f6-622a-48fd-a91d-bd6bd218f41f/image.png" alt=""></p>
<figcaption style="text-align:center; font-size:15px; color:#808080">
    배열 스택과 연결리스트 스택의 차이
  </figcaption>


<p>위 그림과 같이 구현한 스택을 연결된 스택(linked stack)또는 연결리스트로 구현한 스택이라고 한다.</p>
<p>연결리스트를 설명하자면 게시글이 너무 길어지기 때문에 나중에 따로 연결리스트에 대해 투고하려한다. 연결리스트를 간단히 설명하자면 복잡한 포인터 연산을 필요로 하는 구현 방법이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배열]]></title>
            <link>https://velog.io/@jnghoon_2/%EB%B0%B0%EC%97%B4</link>
            <guid>https://velog.io/@jnghoon_2/%EB%B0%B0%EC%97%B4</guid>
            <pubDate>Tue, 11 Oct 2022 06:01:04 GMT</pubDate>
            <description><![CDATA[<h1 id="배열의-개념">배열의 개념</h1>
<p><strong>배열(array)</strong>은 거의 모든 프로그래밍 언어에서 기본적으로 지원된다. 배열은 기본이 되는 중요한 자료형으로 많은 고급 자료구조들에서 사용된다. 배열은 주로 여러 개의 동일한 자료형의 데이터를 한꺼번에 만들 때 사용된다.</p>
<pre><code>int a1, a2, a3, a4, a5; // 6개의 정수형 변수를 각각 선언 
int A[5]; // 5개의 정수형 변수를 선언</code></pre><p>여러 개의 변수를 사용하는 것은 각각을 다른 이름으로 접근해야 하므로 연산이나 자료의 교환 등에서 많은 불편함이 따른다. 이런 경우에 배열을 사용하면 편리하다.
배열은 동일한 이름을 사용하고 <em>인덱스(index)</em> 번호로 각 항목을 접근할 수 있다. 특히 반복문을 활용하여 코드의 길이를 크게 줄일 수 있다.</p>
<p>배열의 가장 기본적인 특징은** &lt;인덱스, 요소&gt; **쌍의 집합이라는 것이다. 즉, 인덱스가 주어지면 해당하는 요소가 대응되는 자료구조이다. 배열에서는 모든 요소가 동일한 자료형이며, 인덱스를 사용하여 요소를 직접 접근(direct access)할 수 있다.
배열과 대응되는 개념으로는 순차 접근(sequential access) 방식인 연결 리스트가 있다.</p>
<h1 id="배열의-추상-자료형">배열의 추상 자료형</h1>
<table>
<thead>
<tr>
<th>객체</th>
<th align="left">&lt;인텍스, 요소&gt;쌍의 집합</th>
</tr>
</thead>
<tbody><tr>
<td>연산</td>
<td align="left">create(n): n개의 요소를 가진 배열을 생성한다.</td>
</tr>
<tr>
<td></td>
<td align="left">retrieve(i): 배열의 i번째 요소를 return한다.</td>
</tr>
<tr>
<td></td>
<td align="left">store(i, item): 배열의 i번째 위치에 item을 저장한다.</td>
</tr>
</tbody></table>
<h1 id="1차원-배열">1차원 배열</h1>
<p>1차원 배열을 선언하는 방법은 다음과 같다.</p>
<blockquote>
<p>자료형 배열이름[배열의 크기]; // &lt;주의!&gt; 선언 방법은 언어에 따라 다를 수 있음.</p>
</blockquote>
<ul>
<li>자료형: 배열 요소들의 자료형. 모든 요소들은 같은 자료형으로 만들어진다.</li>
<li>배열이름: 배열의 요소에 접근할 수 있는 유일한 이름.</li>
<li>배열의 크기: 배열 요소의 개수를 나타내는 정수. 배열 요소의 인덱스는 0 부터 배열 크기 - 1이 된다.</li>
</ul>
<p>※ 배열에서의 요소들은 모두 메모리의 연속된 공간에 저장된다</p>
<h1 id="문자열특별한-1차원-배열">문자열(특별한 1차원 배열)</h1>
<p>문자열은 1차원 배열의 한종류로 char 형의 요소를 갖는 배열을 의미한다. 하나의 문자는 작은따옴표를 이용하여 표현한다. 문자열은 모은 단어는 큰 따옴표를 사용하여 나타낸다. 문자열을 저장하기 위해서는 char 형 1차원 배열을 사용한다.</p>
<p>예를 들어 문자 배열을 &quot;I Love You&quot;로 초기화하면</p>
<p>char a[12] = &quot;I Love You&quot;;</p>
<p>이와 같은 문자열 a에 대한 메모리 구조는 다음과 같다.
<img src="https://velog.velcdn.com/images/jnghoon_2/post/629bd8fa-4c4b-489b-ac79-240c3efdb788/image.png" alt=""></p>
<p>끝에는 a[10]과 같이 반드시 문자열의 끝을 나타내는 NULL문자 &#39;＼0&#39;이 있어야 한다.
a[1]과 a[6]는 공백문자 &#39; &#39;를 나타내는데 이것도 문자열의 일부분일 뿐이다. 따라서 a는 NULL 값이 나오기 바로 전까지인 &quot;I Love You&quot;를 나타내는 문자열임을 명심해야한다.</p>
<h1 id="2차원-배열">2차원 배열</h1>
<p>2차원 배열은 1차원 배열이 여러 개 모여서 이루어진다. 2차원 배열에서 가로줄을 행(row), 세로줄을 열(column)이라고 한다. 2차원 배열은 다음과 같이 선언한다.</p>
<blockquote>
<p>자료형 배열이름[행의 크기][열의 크기]; 
// &lt;주의!&gt; 선언 방법은 언어에 따라 다를 수 있음.</p>
</blockquote>
<ul>
<li>배열이름: 2차원 배열의 이름</li>
<li>행의 크기: 2차원 배열의 가로줄의 개수.</li>
<li>열의 크기: 2차원 배열의 세로줄의 개수.</li>
</ul>
<h1 id="함수의-파라미터로서의-배열">함수의 파라미터로서의 배열</h1>
<p>함수 안에서 파라미터로 배열을 받아서 배열의 내용을 수정하면 원래의 배열이 수정된다.
사실 배열의 이름은 포인터 역할을 한다. 즉, 배열의 이름을 전달하면 배열의 포인터(첫 번째 항목의 주소)가 전달되는 것이나 마찬가지이다. 따라서 배열을 함수의 파라미터로 전달 받을 때는 항상 조심해야한다. 다음 프로그램을 참고하자.</p>
<pre><code>#include &lt;iostream&gt; 
using std::cout; 
using std::endl;

#define MAX_SIZE 10 

// 배열을 파라미터로 받는 함수 
void sub(int x, int arr[]) 
{ 
    x = 10; 
        arr[0] = 10; 
} 

// 주 함수
void main() 
{ 
    int var; 
        int list[MAX_SIZE]; 
    var = 0; 
        list[0] = 0; 
    sub(var, list); 
    cout &lt;&lt; &quot;var= &quot; &lt;&lt; var &lt;&lt; &quot;list[0]= &quot; &lt;&lt; list[0] &lt;&lt; endl; 
}</code></pre><p>위 프로그램의 출력은 var= 0, list[0]= 10 이다.
값에 의한 호출(call - by - call)을 참고 및 이해한다면 쉽게 연산될  것이다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[추상 자료형]]></title>
            <link>https://velog.io/@jnghoon_2/%EC%B6%94%EC%83%81-%EC%9E%90%EB%A3%8C%ED%98%95</link>
            <guid>https://velog.io/@jnghoon_2/%EC%B6%94%EC%83%81-%EC%9E%90%EB%A3%8C%ED%98%95</guid>
            <pubDate>Tue, 11 Oct 2022 05:36:48 GMT</pubDate>
            <description><![CDATA[<p>소프트웨어의 개발과 유지보수에 있어서 가장 중요한 문제는 _&quot;어떻게 소프트웨어 시스템의 복잡성을 관리할 것인가&quot;_이다. 이러한 복잡성에 대처하기 위하 새로운 아이디어들이 등장하였고 이들을 구체화한 프로그래밍 방법론과 언어들이 개발되었다. 이러한 방법론이나 언어의 핵심이 <strong>추상화(abstruction)</strong>이다.</p>
<p>추상화란 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념이나 기능을 간추려 내는 것을 말한다. 즉, 어떤 시스템의 간략화 된 기술 또는 명세로서 시스템의 정말 핵심적인 구조나 동작에만 집중하는 것이다.
<img src="https://velog.velcdn.com/images/jnghoon_2/post/548ad5a1-8ce3-4132-9e60-589ee376066c/image.png" alt=""></p>
<p><strong>추상 자료형(Abstruct Data Type: ADT)</strong>은 추상화한 자료형, 즉 추상적으로 정의한 자료형을 의미한다. 구체적으로는 자료의 집합과 자료에 가해지는 연산들의 집합에 대한 수학적 명세이다. 이러한 추상 자료형은 그 자료형의 구현으로 부터 분리된 자료형을 의미하는데, <em>자료나 연산이 무엇(what)인가는 정의_되지만 이들을 컴퓨터에서 어떤 프로그래밍 언어를 이용해 _어떻게(how) 구현할 것인지는 정의 하지 않는다.</em></p>
<p>추상 자료형을 표현할 때는 먼저 객체를 정의하고, 다음으로 연산들을 정의한다. 객체는 주로 집합의 개념을 사용하여 표현하고, 연산의 정의에는 연산의 이름, 매개변수, 연산의 결과, 연산이 수행하는 기능 들을 기술한다.</p>
<p>추상 자료형을 컴퓨터 프로그램으로 구현할 때는 보통 구현에 관한 세부사항들은 외부에서 모르게 하고 외부에는 간단한 <strong>인터페이스(interface)</strong>만을 공개한다. 사용자는 공개된 인터페이스만 사용하고 이것이 어떻게 구현되었는지를 알 필요가 없다 추후에 구현 방법이 변경될 수 있지만, 인터페이스만 정확하게 지켜진다면 사용자는 변경된 내용을 알 수도 없고 사용하는데도 전혀 문제가 없다.</p>
<p>이것이 정보은닉의 기본 개념이다. 즉, &quot;구현으로부터 명세의 분리&quot;가 추상 자료형의 중심 아이디어이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자료구조와 알고리즘]]></title>
            <link>https://velog.io/@jnghoon_2/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@jnghoon_2/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Tue, 11 Oct 2022 05:32:24 GMT</pubDate>
            <description><![CDATA[<h1 id="알고리즘이란">알고리즘이란?</h1>
<p>어떤 문제를 해결하는  절차를 알고리즘(algorithm)이라고 한다.</p>
<p>알고리즘에 관해 자세한 정보를 알고 싶다면 알고리즘 시리즈를 참고해보기 바란다.</p>
<h1 id="프로그램--자료구조--알고리즘">프로그램 = 자료구조 + 알고리즘</h1>
<p>대부분의 프로그램은 데이터를 처리하고 있고 이들 자료는 자료구조를 사용하여 표현되고 저장된다. 또한 주어진 문제를 처리하는 정차, 즉 알고리즘이 필요하다. 따라서 프로그램은 자료구조와 알고리즘으로 구성되어 있다고 볼 수 있다.</p>
<p>자료구조와 알고리즘은 밀접한 관계가 있어서 자료구조가 결정되면 그 자료구조에서 사용할 수 있는 알고리즘이 결정된다. 컴퓨터가 복잡한 자료들을 빠르게 저장, 분석, 전송, 갱신하기 위해서는 자료구조가 효율적으로 조작화되어 있어야 한다. 또한 응용 프로그램에 가장 적합한 자료구조와 알고리즘을 선택해야한다.</p>
<p>알고리즘은 컴퓨터가 주어진 상태에서 문제를 해결하는 방법을 장치가 이해할 수 있는 언어로 정밀하게 기술한 것이다. 따라서 알고리즘은 특정한 일을 수행하는 명령어들의 집합이다. 여기서 명령어란 컴퓨터에서 수행되는 문장들을 의미한다. 그렇다고 모든 명령어들의 집합이 알고리즘이 되는 것은 아니다.</p>
<p><em>알고리즘은 다음과 같은 조건들을 만족해야한다.</em></p>
<p>·  입력  : 0개 이상의 입력이 존재하여야 한다.
·  출력  : 1개 이상의 출력이 존재하여야 한다.
· 명확성 : 각 명령어의 의미는 모호하지 않고 명확해야 한다.
· 유한성 : 한정된 수의 단계 후에는 반드시 종료되어야 한다.
· 유효성 : 각 명령어들은 실행 가능한 연산이어야 한다.</p>
<h1 id="알고리즘-기술-방법">알고리즘 기술 방법</h1>
<p>알고리즘을 기술하는 방법은 다음과 같이 4가지가 있다.</p>
<h2 id="1-영어나-한국어와-같은-자연어">1. 영어나 한국어와 같은 자연어</h2>
<p>이 방법은 자연어를 사용하므로 기술이 편리하지만 모호성을 제거하기 위하여 명령어로 쓰이는 단어들을 명백하게 해야만 알고리즘이 될 수 있다.</p>
<blockquote>
<p>ArrayMax(A, n)</p>
</blockquote>
<ol>
<li>배열 A의 첫 번째 요소를 변수 tmp에 복사한다.</li>
<li>요소들을 차례대로 tmp와 비교 후, 더 크면 그 값을 tmp로 복사한다.</li>
<li>배열 A으 모든 요소를 비교 했으면 tmp를 반환한다.</li>
</ol>
<h2 id="2-흐름도flowchart">2. 흐름도(flowchart)</h2>
<p><strong>흐름도(flowchart)</strong>는 명확하게 표현할 수 있다는 잠점이 있어 특허 명세서 등에서 많이 사용된다. 그러나 알고리즘이 조금만 복잡해져도 흐름도가 매우 복잡하게 표시되는 단점이 있다.</p>
<p><img src="https://velog.velcdn.com/images/jnghoon_2/post/73691a37-68d1-4691-becf-a9c131e196ca/image.png" alt=""></p>
<h2 id="3-유사-코드pseudo-code">3. 유사 코드(pseudo-code)</h2>
<p><strong>유사 코드(pseudo-code)</strong>는 자연어 보다는 더 쳬계적이지만 프로그래밍 언어보다는 덜 엄격한 언어로서 알고리즘의 표현에 흔히 사용되는 방법이다. 유사 코드의 문법은 보통 실제 프로그래밍 언어와 비슷하여 쉽게 이해가 가능하면서도 특정 프로그래밍 언어로 구현할 때의 여러 가지 문제들을 감출 수 있고, 알고리즘의 핵심적인 내용에 대한 집중할 수 있어 알고리즘의 기술에 많이 사용되고 있다.</p>
<pre><code>ArrayMax(A, n)
tmp &lt;- A[0];
for i&lt;-1 to n-1 do
   if tmp &lt; A[i] then
      tmp &lt;- A[i];
return tmp;</code></pre><h2 id="4-특정한-프로그래밍-언어">4. 특정한 프로그래밍 언어</h2>
<p>이 방법은 특정한 프로그래밍 언어를 사용하여 알고리즘을 기술하는 방법이다. 이것은 알고리즘의 가장 정확한 표현이지만, 구현을 위해 구제적인 사항들을 표함하고 있어 알고리즘의 핵심적인 내용 이해를 방해할 수 있다.</p>
<pre><code>int ArrayMax(int score[], int n)
{
   int tmp = score[0];
   for(int i = 1 ; i &lt; n ; i++)
   {
      if(score[i] &gt; tmp)
      {
         tmp = score[i];
      }
   }
   return tmp;
}</code></pre>]]></description>
        </item>
    </channel>
</rss>