<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발기록장</title>
    <link>https://devvvyang.tistory.com/</link>
    <description>뼈문과생의 개발 삽질 기행</description>
    <language>ko</language>
    <pubDate>Sat, 9 May 2026 13:08:00 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>yangahh</managingEditor>
    <item>
      <title>[Java] Mac에 Homebrew를 이용하여 Java 설치 방법</title>
      <link>https://devvvyang.tistory.com/69</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. openjdk 저장소 추가&lt;/p&gt;
&lt;pre id=&quot;code_1691316163893&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ brew tap adoptopenjdk/openjdk&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 설치 가능한 jdk 패키지 확인&lt;/p&gt;
&lt;pre id=&quot;code_1691316205399&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ brew search jdk&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1770&quot; data-origin-height=&quot;1124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vzhY5/btsp9p8mkkn/yQ9gwpht0fbFZJycg4kv10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vzhY5/btsp9p8mkkn/yQ9gwpht0fbFZJycg4kv10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vzhY5/btsp9p8mkkn/yQ9gwpht0fbFZJycg4kv10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvzhY5%2Fbtsp9p8mkkn%2FyQ9gwpht0fbFZJycg4kv10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1770&quot; height=&quot;1124&quot; data-origin-width=&quot;1770&quot; data-origin-height=&quot;1124&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 원하는 버전의 jdk를 선택하여 설치&lt;/p&gt;
&lt;pre id=&quot;code_1691316227971&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ brew install --cask adoptopenjdk8&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 설치 확인&lt;/p&gt;
&lt;pre id=&quot;code_1691316424493&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ java -version&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n9QEB/btsp645djJI/2ntWXfa3QkMrhmERScohC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n9QEB/btsp645djJI/2ntWXfa3QkMrhmERScohC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n9QEB/btsp645djJI/2ntWXfa3QkMrhmERScohC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn9QEB%2Fbtsp645djJI%2F2ntWXfa3QkMrhmERScohC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;101&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;❗️ java -version&lt;/b&gt;을 입력했을 때, 방금 설치한 버전과 다른 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 과거에 다른 버전의 JDK를 설치했을 경우 이런 경우가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 따라서 환경변수 설정을 통해 원하는 버전으로 사용할 수 있게 해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 다음 단계를 수행&lt;/p&gt;
&lt;pre id=&quot;code_1691316842277&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cd /Library/Java/JavaVirtualMachines

$ ls -l                                                                                                          ─╯
total 0
drwxr-xr-x  3 root  wheel    96B  4 21  2021 adoptopenjdk-7.jdk
drwxr-xr-x  3 root  wheel    96B  4 21  2021 adoptopenjdk-8.jdk

$ cd adoptopenjdk-8.jdk   # 원하는 버전의 디렉토리로 이동
$ cd Contents/Home
$ pwd
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home   # &amp;lt;&amp;lt; 전체 복사&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 환경 변수를 관리하는 파일인 &lt;b&gt;~/.zshrc&lt;/b&gt; 파일을 열어서 아래 내용 추가&lt;/p&gt;
&lt;pre id=&quot;code_1691317163345&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export JAVA_HOME=/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home  # 위에서 복사한 경로를 붙여넣기
export PATH=${PATH}:$JAVA_HOME/bin&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 저장 후 나와서 프로필 파일 적용&lt;/p&gt;
&lt;pre id=&quot;code_1691317246790&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ source ~/.zshrc&lt;/code&gt;&lt;/pre&gt;</description>
      <category>TIL/Java</category>
      <author>yangahh</author>
      <guid isPermaLink="true">https://devvvyang.tistory.com/69</guid>
      <comments>https://devvvyang.tistory.com/69#entry69comment</comments>
      <pubDate>Sun, 6 Aug 2023 19:22:31 +0900</pubDate>
    </item>
    <item>
      <title>[Hyperledger Fabric] 하이퍼레저 패브릭 실습 - Building Your First Network (1)</title>
      <link>https://devvvyang.tistory.com/66</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;84&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUgHxM/btrZ7qxWFfA/lIviKdk5ucqxHIw7NkWXik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUgHxM/btrZ7qxWFfA/lIviKdk5ucqxHIw7NkWXik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUgHxM/btrZ7qxWFfA/lIviKdk5ucqxHIw7NkWXik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUgHxM%2FbtrZ7qxWFfA%2FlIviKdk5ucqxHIw7NkWXik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;84&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;84&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** &lt;span&gt;참고한 공식 문서 -&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://hyperledger-fabric.readthedocs.io/en/release-1.4/build_network.html&quot;&gt;Building Your First Network&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사전 준비&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 실습 서버&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; &amp;nbsp;1.1 VMWare에 Ubuntu 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;** 작업환경: intel Mac&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - VirtualBox에 Ubuntu 18.04 버전 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; -&lt;s&gt; Mac M1용 VMware 설치 -&amp;gt; &lt;a href=&quot;https://customerconnect.vmware.com/downloads/info/slug/desktop_end_user_computing/vmware_fusion/13_0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;s&gt; - Ubuntu 디스크 이미지(facal-desktop-amd64.iso)) 다운로드 -&amp;gt; &lt;a href=&quot;https://cdimage.ubuntu.com/focal/daily-live/current/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크&lt;/a&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - 추가 셋팅은 disk만 35GB로 바꿔줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - 화면에 부팅 모드가 뜨면 Install Ubuntu 선택. 이후 Install 과정에서의 설정은 모두 Default 설정으로 설치함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 필요한 프로그램 설치&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 2.0 apt 혹은 apt-get update 하고 시작하기&lt;/p&gt;
&lt;pre id=&quot;code_1676878387893&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt update
sudo apt upgrate

sudo apt-get update
sudo apt-get upgrade&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 2.1 사전에 필요한 라이브러리 설치&lt;/p&gt;
&lt;pre id=&quot;code_1676877623504&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get install curl
sudo apt-get install python3-pip
sudo apt-get install git
sudo apt-get install libltdl-dev
sudo apt-get install tree
sudo apt-get install openssh-server
sudo apt-get install net-tools&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp; 2.2 Install Docker and Docker compose&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - &lt;span style=&quot;background-color: #fcfcfc; color: #010101;&quot;&gt;Docker version 17.06.2-ce or greater is required.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #010101;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;** 참고) Docker 최신버전 스크립트를 가져와서 설치하기&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1676878147060&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1676878205671&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get install python3-pip
sudo apt-get install python3-setuptools
pip3 install --upgrade pip3

pip3 install docker-compose&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;2.3 Install Go Language&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;a style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; href=&quot;https://golang.org/dl/&quot;&gt;Go&lt;/a&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;version 1.12.x is required.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; ** 나는 1.12.13 버전으로 설치&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1676879401303&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 필요한 버전의 Go 다운로드
wget https://golang.org/dl/go1.12.13.linux-amd64.tar.gz

# 압축 풀기
sudo tar -xvf go1.12.13.linux-amd64.tar.gz
## **보통은 압축 풀 때 path를  `-C /usr/local` 로 지정하는데 참고하는 공식문서에서는 $HOME을 path로 잡고있어서 $HOME에 설치함&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; - GOPATH 변수 설정(필수!!) -&amp;gt; &lt;a href=&quot;https://hyperledger-fabric.readthedocs.io/en/release-1.4/prereqs.html#go-programming-language&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;링크 참고&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1948&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdwXUL/btrZ5i8miWZ/i9Zue7zKNeSPwKhrD3d3lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdwXUL/btrZ5i8miWZ/i9Zue7zKNeSPwKhrD3d3lk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdwXUL/btrZ5i8miWZ/i9Zue7zKNeSPwKhrD3d3lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdwXUL%2FbtrZ5i8miWZ%2Fi9Zue7zKNeSPwKhrD3d3lk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;823&quot; height=&quot;89&quot; data-origin-width=&quot;1948&quot; data-origin-height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - ** 영구 설정을 위해 환경변수 파일에 추가&lt;/p&gt;
&lt;pre id=&quot;code_1676880608611&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# vi /etc/profile

export GOPATH=$HOME/go
PATH=$PATH:$GOPATH/bin&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2.4 Node.js Runtime and NPM&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - Node.js용 Hyperledger Fabric SDK를 활용하여 Hyperledger Fabric용 애플리케이션을 개발하는 경우&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; Node.js 버전 8은 8.9.4 이상, 버전 10은 10.15.3 이상에서 지원된다.&lt;/p&gt;
&lt;pre id=&quot;code_1676882341230&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 필요한 node 버전 지정하여 설치 (나는 12.x버전으로 설치)

# PPA 설치
curl -sL https://deb.nodesource.com/setup_12.x -o nodesource_setup.sh

# sudo 권한으로 PPA 를 추가하고 업데이트
sudo bash nodesource_setup.sh
sudo apt-get install nodejs

# PPA 를 통해 Node.js 를 설치하면 npm 까지 같이 설치된다.
# npm이 제대로 동작하기 위해 build-essential 패키지를 설치해야 한다.
sudo apt-get install build-essential&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL/BlockChain</category>
      <author>yangahh</author>
      <guid isPermaLink="true">https://devvvyang.tistory.com/66</guid>
      <comments>https://devvvyang.tistory.com/66#entry66comment</comments>
      <pubDate>Mon, 20 Feb 2023 17:54:45 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 웹 브라우저 요청 흐름 (www.google.com을 치면 어떤 일이 일어나는가)</title>
      <link>https://devvvyang.tistory.com/65</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 브라우저에 &lt;b&gt;&lt;a href=&quot;https://www.google.com/search?q=hello&amp;amp;hl=ko&quot;&gt;https://www.google.com/search?q=hello&amp;amp;hl=ko&lt;/a&gt;&lt;/b&gt;를 치면 어떤 일이 일어날까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1. DNS 서버를 조회하여 구글 서버의 IP를 찾아낸다(포트는 https이기때문에 생략한 경우 443)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 웹브라우저는 http 요청 메세지 생성한다. http 요청 메세지는 아래 사진과 같이 구성되어 있다(매우 간략 버전..)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpAbLh/btrXoCV7cfA/KjhyNnK5c5KG3TTIIWghxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpAbLh/btrXoCV7cfA/KjhyNnK5c5KG3TTIIWghxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpAbLh/btrXoCV7cfA/KjhyNnK5c5KG3TTIIWghxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpAbLh%2FbtrXoCV7cfA%2FKjhyNnK5c5KG3TTIIWghxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;288&quot; height=&quot;496&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.&amp;nbsp; Socket 라이브러리를 통해서 HTTP 요청 메세지를 OS에다가 전달&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. TCP/IP 패킷 생성(HTTP 메세지 포함)&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1130&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d3xw1P/btrXnKAl1TH/Rw6HjtCPwlNxgEr1CBml10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d3xw1P/btrXnKAl1TH/Rw6HjtCPwlNxgEr1CBml10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d3xw1P/btrXnKAl1TH/Rw6HjtCPwlNxgEr1CBml10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd3xw1P%2FbtrXnKAl1TH%2FRw6HjtCPwlNxgEr1CBml10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;373&quot; height=&quot;608&quot; data-origin-width=&quot;1130&quot; data-origin-height=&quot;608&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 만들어진 패킷을 인터넷 망으로 전송&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 구글 서버에서 요청 패킷을 전송받으면 TCP/IP패킷을 까서 버리고 http 메세지를 해석해서 알맞은 리소스를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 구글 서버는 찾은 리소스를 가지고 응답 메세지를 만든다. http 응답 메세지는 아래 사진과 같이 구성되어있다(매우 간략 버전..)&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1086&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/narzB/btrXn7B3aGb/x9q3mB9hPqY6TXojFlaNvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/narzB/btrXn7B3aGb/x9q3mB9hPqY6TXojFlaNvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/narzB/btrXn7B3aGb/x9q3mB9hPqY6TXojFlaNvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnarzB%2FbtrXn7B3aGb%2Fx9q3mB9hPqY6TXojFlaNvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;172&quot; data-origin-width=&quot;1086&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. 구글 서버에서도 마찬가지로 http 응답 메세지를 담은 TCP/IP 패킷을 만들어서 클라이언트 (웹 브라우저)에게 전달한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. 웹 브라우저는 http 응답 메세지의 html을 렌더링해서 화면에 보여준다.&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL/Web</category>
      <category>웹브라우저</category>
      <author>yangahh</author>
      <guid isPermaLink="true">https://devvvyang.tistory.com/65</guid>
      <comments>https://devvvyang.tistory.com/65#entry65comment</comments>
      <pubDate>Sun, 29 Jan 2023 21:24:11 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 기본적인 인터넷 네트워크 개념</title>
      <link>https://devvvyang.tistory.com/64</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;IP (인터넷 프로토콜)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IP의 역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지정한 IP주소에 데이터 전달&lt;/li&gt;
&lt;li&gt;패킷(packet)이라는 통신 단위로 데이터 전달&lt;br /&gt;** 패킷이란? 패키지(package)와 덩어리(bucket)을 합성어로 말 그대로 데이터를 담은 택배 박스 개념이다.&lt;/li&gt;
&lt;li&gt;클라이언트에서 출발지 IP, 목적지 IP, 데이터를 담은 패킷을 전송하면 서버에서 이를 받고, 서버에서도 받았다는 내용(OK)의 패킷을 클라이언트에게 전송한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1706&quot; data-origin-height=&quot;932&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5xdej/btrXo45NPFM/i5prEkk5ra5Cd4RCVqkGg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5xdej/btrXo45NPFM/i5prEkk5ra5Cd4RCVqkGg1/img.png&quot; data-alt=&quot;인터넷 망 안에서 노드들끼리 이 목적지 IP를 받을 수 있는 서버가 어디있는지 찾아가며 목적지까지 패킷을 전송&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5xdej/btrXo45NPFM/i5prEkk5ra5Cd4RCVqkGg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5xdej%2FbtrXo45NPFM%2Fi5prEkk5ra5Cd4RCVqkGg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;582&quot; height=&quot;318&quot; data-origin-width=&quot;1706&quot; data-origin-height=&quot;932&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인터넷 망 안에서 노드들끼리 이 목적지 IP를 받을 수 있는 서버가 어디있는지 찾아가며 목적지까지 패킷을 전송&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IP 프로토콜의 한계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비연결성
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;패킷을 받을 대상이 없거나 서비스 불능 상태여도 패킷은 전송된다.&amp;nbsp; 대상 서버가 패킷을 받을 수 있는 상태인지 아닌지 모르기 때문.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비신뢰성
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;중간에 패킷이 사라질 수 있다. &lt;br /&gt;인터넷 망이라는게 결국은 여러 서버들을 거처서 전달을 한다는 건데, 중간에 한 서버에 문제가 있다면 패킷이 유실된다. 근데 이렇게 유실이 된다고해도 서버는 유신된줄도 모른다.&lt;/li&gt;
&lt;li&gt;패킷이 순서대로 안 올 수 있다.&lt;br /&gt;전송할 데이터의 양이 클 경우(보통 1500바이터가 넘으면), 데이터를 나눠서 여러개의 패킷으로 보내게 되는데,&amp;nbsp; 이럴 경우 아래의 그림 설명과 같은 이유로 도착하는 패킷들이 전송할 때의 순서와 달라질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;966&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBypjs/btrXrT3NNbu/GfqfoywMk5qHHAzrOHVbCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBypjs/btrXrT3NNbu/GfqfoywMk5qHHAzrOHVbCk/img.png&quot; data-alt=&quot;1번 패킷과 2번 패킷이 반드시 같은 경로로 보내진다고 보장할 수 없기 때문에 도착할때도 같은 순서로 온다고 보장할 수 없다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBypjs/btrXrT3NNbu/GfqfoywMk5qHHAzrOHVbCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBypjs%2FbtrXrT3NNbu%2FGfqfoywMk5qHHAzrOHVbCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;655&quot; height=&quot;352&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;966&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1번 패킷과 2번 패킷이 반드시 같은 경로로 보내진다고 보장할 수 없기 때문에 도착할때도 같은 순서로 온다고 보장할 수 없다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램 구분
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;같은 IP를 사용하는 서버에서 통신하고있는 어플리케이션이 여러개라면 패킷은 오직 IP만 알고있기 때문에 이를 구분할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TCP (Transmission Control Protocol&amp;nbsp; 전송 제어 프로토콜)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP는 위에서 설명한 IP 프로토콜의 한계들을 해결해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP를 설명하기 전에 쉬운 이해를 위해 채팅 프로그램으로 hello world 라는 메세지를 보낸다고 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터넷 프로토콜은 다음과 같은 계층으로 이루어져있고, 각 계층별로 사용되는 프로토콜이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;968&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u5chh/btrXt9rLc9m/T9NwWfSNDnx6xlsUFKPVR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u5chh/btrXt9rLc9m/T9NwWfSNDnx6xlsUFKPVR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u5chh/btrXt9rLc9m/T9NwWfSNDnx6xlsUFKPVR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu5chh%2FbtrXt9rLc9m%2FT9NwWfSNDnx6xlsUFKPVR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;673&quot; height=&quot;400&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;968&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;맨 먼저 채팅 프로그램은 소켓 라이브러리를 통해 OS 계층으로 'hello world'라는 메세지를 넘긴다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;OS계층에서는 TCP가 이 메세지에다가 TCP 정보를 붙인다(위 사진에서 초록색 부분이 TCP 정보이다). 이를 TCP 세그먼트라고 한다.&lt;/li&gt;
&lt;li&gt;TCP밑에 IP계층이 있는데, 여기에서는 TCP 세그먼터에다가 IP 관련 정보를 붙인다. 이렇게 만들어진게 IP 패킷이고 TCP 정보와 IP정보가 다 붙은 덩어리를 TCP/IP 패킷이라고 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;926&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dyJ4rP/btrXwihFYfH/1oXpJrInHGKgOx2bPzhq81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dyJ4rP/btrXwihFYfH/1oXpJrInHGKgOx2bPzhq81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dyJ4rP/btrXwihFYfH/1oXpJrInHGKgOx2bPzhq81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdyJ4rP%2FbtrXwihFYfH%2F1oXpJrInHGKgOx2bPzhq81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;470&quot; height=&quot;278&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;926&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 4. 이 덩어리는 네트워크 인터페이스에서 LAN 카드 등을 통해 나가는데 이때 이더넷 프레임이라는 것도 포함되어서 나간다. &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 이더넷 프레임은 랜카드에 등록 된&amp;nbsp; mac 주소같은 물리적인 정보를 담고 있다(여기서는 그냥 이정도로 간단하게만 알고 있자)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TCP 특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연결 지향 - TCP 3 way handshake(가상 연결)&lt;br /&gt;출발지와 목적지가 서로&amp;nbsp; 연결이 되었는지 확인을 하고 메세지를 보내는 방식.&lt;br /&gt;1) 먼저 클라이언트쪽에서 서버에 연결 요청의 의미인 SYN이라는 메세지를 보낸다.&lt;br /&gt;2) 서버에서 알았다는 뜻으로 ACK라는 메세지와 나도 연결해줘 라는 의미의 SYN 메세지를 함께 클라이언트로 보낸다.&lt;br /&gt;3) 클라이언트도 SYN에 대한 응답으로 ACK를 보낸다.&lt;br /&gt;4) 이 3단계의 과정으로 서로 연결되었음을 인식한 후에 데이터를 전송한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1558&quot; data-origin-height=&quot;972&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AQTdI/btrXqtEjcJU/GFBpR1hSEUYPvxjdFeEa41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AQTdI/btrXqtEjcJU/GFBpR1hSEUYPvxjdFeEa41/img.png&quot; data-alt=&quot;**요즘에는 최적화 되어서 3번 단계에서 데이터 전 송을 한꺼번에 처리하기도 한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AQTdI/btrXqtEjcJU/GFBpR1hSEUYPvxjdFeEa41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAQTdI%2FbtrXqtEjcJU%2FGFBpR1hSEUYPvxjdFeEa41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;528&quot; height=&quot;329&quot; data-origin-width=&quot;1558&quot; data-origin-height=&quot;972&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;**요즘에는 최적화 되어서 3번 단계에서 데이터 전 송을 한꺼번에 처리하기도 한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 전달 보증&lt;br /&gt;클라이언트에서 데이터를 전송하고 서버가 이를 받으면 데이터를 잘 받았다고 클라이언트에게 응답을 해준다&lt;/li&gt;
&lt;li&gt;순서 보장&lt;br /&gt;서버에서 순서에 맞지 않은 패킷들을 받으면, 클라이언트에게 잘못된 패킷부터 다시 전달하라고 보낸다&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;438&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2qoV3/btrXnj33rQ9/LFML49mZKx3vFKoK2Sv5Q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2qoV3/btrXnj33rQ9/LFML49mZKx3vFKoK2Sv5Q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2qoV3/btrXnj33rQ9/LFML49mZKx3vFKoK2Sv5Q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2qoV3%2FbtrXnj33rQ9%2FLFML49mZKx3vFKoK2Sv5Q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;493&quot; height=&quot;438&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;438&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로는 훨씬 많은 특징이 있다. 위 3가지 특징으로 TCP는 신뢰할 수 있는 프로토콜이라 여겨지고 현재는 대부분 애플리케이션에서 TCP를 사용하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;UDP (User Datagram Protocol)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UDP 특징&amp;nbsp;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UDP는 TCP와 같이 OS 계층에서 IP 계층위에 있는 프로토콜&lt;/li&gt;
&lt;li&gt;보통 하얀 도화지에 비유(기능이 거의 없기 때문)&lt;/li&gt;
&lt;li&gt;&amp;nbsp;3-way-handshake X, 데이터 전달 보증 X, 순서 보장 X&lt;/li&gt;
&lt;li&gt;단순하고 빠름&lt;/li&gt;
&lt;li&gt;그래서 IP와 거의 같지만, 포트, 체크섬 정도만 추가됨.&lt;br /&gt;포트가 있으면 하나의 IP에서 여러 애플리케이션이 실행되고 있을 때 여기로 들어오는 패킷들이 어떤 애플리케이션을 위한 패킷인지 구분할 수 있다. 체크섬은 데이터가 제대로 된건지 검증해주는 용도&amp;nbsp;&lt;/li&gt;
&lt;li&gt;TCP는 신뢰할 수 있는 프로토콜이지만 3-way-handshake로 인해 속도가 느리다. 그래서 최적화를 위해 UDP를 사용. UDP는 도화지 상태이기 때문에 이 위에다가 내가 원하는걸 애플리케이션 레벨에서 만들어 내면 된다.&lt;/li&gt;
&lt;li&gt;Http3에서 UDP프로토콜을 사용해서 최근에 각광받고 있다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PORT&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 IP 내에서 프로세스 구분을 위해 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP/IP 패킷에는 출발지IP + 출발지Port, 도착지IP + 도착지Port가 담겨있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BCh4X/btrXoCPgToD/iDFeVfZfG8KTH3PyL5kyK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BCh4X/btrXoCPgToD/iDFeVfZfG8KTH3PyL5kyK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BCh4X/btrXoCPgToD/iDFeVfZfG8KTH3PyL5kyK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBCh4X%2FbtrXoCPgToD%2FiDFeVfZfG8KTH3PyL5kyK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;531&quot; height=&quot;297&quot; data-origin-width=&quot;1358&quot; data-origin-height=&quot;760&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0 ~ 65535 사이에서 할당 가능한데 0~1023까지는 잘 알려진 포트로 사용하지 않는게 좋다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FTP: 20, 21&lt;/li&gt;
&lt;li&gt;TELNET: 23&lt;/li&gt;
&lt;li&gt;HTTP: 80&lt;/li&gt;
&lt;li&gt;HTTPS: 443&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL/Web</category>
      <category>IP</category>
      <category>tcp</category>
      <category>UDP</category>
      <category>인터넷 네트워크</category>
      <category>포트</category>
      <author>yangahh</author>
      <guid isPermaLink="true">https://devvvyang.tistory.com/64</guid>
      <comments>https://devvvyang.tistory.com/64#entry64comment</comments>
      <pubDate>Sun, 29 Jan 2023 20:43:20 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] 우선순위 큐와 힙</title>
      <link>https://devvvyang.tistory.com/63</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;우선순위 큐&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;우선순위 큐는 일반적인 큐와 다르게 우선 순위가 높은 요소가 먼저 나가는 개념이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;여기서 주의할 점은 우선순위 큐는 자료구조가 아닌 &lt;b&gt;개념&lt;/b&gt;이다.&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;따라서 우선순위 큐를 구현하는 방법은 다양하게 존재할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;그중 &lt;b&gt;힙은 우선순위 큐를 구현하기 위한 가장 적합한 방법&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;힙 (Heap)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;힙은 자료구조이며, 이진 트리 형태이다. &lt;u&gt;우선순위가 높은 요소를 루트에&lt;/u&gt; 두기위해 요소가 삽입, 삭제될 때 바로 정렬되는 특징이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLA1Sy/btrWmmlbEkA/KNEx7PSKfTJFAy45SNWAA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLA1Sy/btrWmmlbEkA/KNEx7PSKfTJFAy45SNWAA1/img.png&quot; data-alt=&quot;위 예시에서는 값이 클수록 우선순위가 높고, 6이 가장크므로 루트에 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLA1Sy/btrWmmlbEkA/KNEx7PSKfTJFAy45SNWAA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLA1Sy%2FbtrWmmlbEkA%2FKNEx7PSKfTJFAy45SNWAA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;375&quot; height=&quot;294&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위 예시에서는 값이 클수록 우선순위가 높고, 6이 가장크므로 루트에 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;힙의 특징&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우선순위가 가장 높은 것을 루투에 두고, 항상 루트가 먼저 나간다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;루트가 가장 큰 값이 되는 &lt;b&gt;최대 힙&lt;/b&gt;과 루트가 가장 작은 값이 되는 &lt;b&gt;최소 힙&lt;/b&gt; 두가지로 나뉜다. (오름차순이냐 내림차순이냐 정도의 차이)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;파이썬에서는 heapq 혹은 PriorityQueue 모듈을 통해서 쉽게 힙을 구현할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;요소 추가 시, 항상 이진 트리의 마지막에 추가되기 때문에 힙은 항상 완전 이진 트리다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;힙 추가 알고리즘&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;1. &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt; 이진 트리의 가장 마지막에 추가한다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;2. 요소가 추가되었다면 부모 정점보다 우선순위가 높은지 체크한다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;3. 만약 추가된 요소가 더 높다면 부모와 바꾼다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;4. 더이상 순서를 바꿀수 없을 때까지 반복하면 결국 가장 우선순위가 높은 정점이 루트가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;5. &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;따라서 높이는 log N이기에 요소 추가 알고리즘은 최악의 경우에도 log N이다.&amp;nbsp; (&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;O(logN) 시간복잡도를 가진다)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;최대 힙 예시&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;1. 45라는 요소 추가 -&amp;gt; 루트에 45 정점이 생김&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rqYt4/btrWnoJWhC2/zykteCMYRklG1XAn91BVs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rqYt4/btrWnoJWhC2/zykteCMYRklG1XAn91BVs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rqYt4/btrWnoJWhC2/zykteCMYRklG1XAn91BVs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrqYt4%2FbtrWnoJWhC2%2FzykteCMYRklG1XAn91BVs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;245&quot; height=&quot;260&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;2. 36 요소를 추가. 이진트리이므로 루트의 왼쪽에 추가된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;682&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbK8ed/btrWg0J0cQN/9nOERHGiztDo9QHL26uuz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbK8ed/btrWg0J0cQN/9nOERHGiztDo9QHL26uuz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbK8ed/btrWg0J0cQN/9nOERHGiztDo9QHL26uuz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbK8ed%2FbtrWg0J0cQN%2F9nOERHGiztDo9QHL26uuz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;248&quot; height=&quot;270&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;682&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 54 요소를 추가. 이진트리이므로 루트의 오른쪽에 추가된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDHWp2/btrWeHYtMIA/1KUSuUU7sP8JnB8cgLHfvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDHWp2/btrWeHYtMIA/1KUSuUU7sP8JnB8cgLHfvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDHWp2/btrWeHYtMIA/1KUSuUU7sP8JnB8cgLHfvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDHWp2%2FbtrWeHYtMIA%2F1KUSuUU7sP8JnB8cgLHfvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;262&quot; height=&quot;284&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;최대 힙에서 45보다 54가 우선순위가 더 높기 때문에 서로 순서를 바꾼다. 마찬가지로 배열도 바뀐다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NyJCg/btrWmmS2eHu/pTyeJMiSrGPZhah4RQsSKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NyJCg/btrWmmS2eHu/pTyeJMiSrGPZhah4RQsSKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NyJCg/btrWmmS2eHu/pTyeJMiSrGPZhah4RQsSKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNyJCg%2FbtrWmmS2eHu%2FpTyeJMiSrGPZhah4RQsSKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;260&quot; height=&quot;288&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;이번엔 27을 추가. 마지막 위치인 36의 왼쪽 정점에 추가된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;704&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXvksB/btrWdHxLbGh/3wXH8C9LLL5uWJEtFNgRK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXvksB/btrWdHxLbGh/3wXH8C9LLL5uWJEtFNgRK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXvksB/btrWdHxLbGh/3wXH8C9LLL5uWJEtFNgRK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXvksB%2FbtrWdHxLbGh%2F3wXH8C9LLL5uWJEtFNgRK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;268&quot; height=&quot;289&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;704&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 다음으로 &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt; 63을 추가. 36의 오른쪽 정점에 추가된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;694&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWRZlJ/btrWjkuxz41/oNAkT13Komf8soy6ZDgTRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWRZlJ/btrWjkuxz41/oNAkT13Komf8soy6ZDgTRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWRZlJ/btrWjkuxz41/oNAkT13Komf8soy6ZDgTRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWRZlJ%2FbtrWjkuxz41%2FoNAkT13Komf8soy6ZDgTRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;273&quot; height=&quot;287&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;694&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 이 상태에서 &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;36보다 63이 우선순위가 더 높기 때문에 바꿔야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFQWOv/btrWkvJt4n3/cDSHxeRkGSCUNCVFuZCWI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFQWOv/btrWkvJt4n3/cDSHxeRkGSCUNCVFuZCWI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFQWOv/btrWkvJt4n3/cDSHxeRkGSCUNCVFuZCWI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFQWOv%2FbtrWkvJt4n3%2FcDSHxeRkGSCUNCVFuZCWI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;286&quot; height=&quot;294&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. 여기서 &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;또 다시 부모 정점과 비교하면 54보다 63이 우선순위가 더 높다. 따라서 둘의 위치를 바꾼다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHilkp/btrWkvQfk9H/EfJmfKMKPT6cXgmkwp33Tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHilkp/btrWkvQfk9H/EfJmfKMKPT6cXgmkwp33Tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHilkp/btrWkvQfk9H/EfJmfKMKPT6cXgmkwp33Tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHilkp%2FbtrWkvQfk9H%2FEfJmfKMKPT6cXgmkwp33Tk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;292&quot; height=&quot;302&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;684&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;루트까지 이동했기 때문에 탐색을 종료한다. 이렇게 최대 힙이 완성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;힙 제거 알고리즘&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;1. &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;먼저 요소를 제거하는건 루트만 가능하다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;2. 루트 정점이 제거되면 &lt;b&gt;그 공백을 가장 마지막 정점이 대체&lt;/b&gt;한다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;3. 이때 추가와는 반대로 루트로부터 점점 정점을 아래로 내려야한다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;4. 루트 정점의 두 자식 정점 중, 더 우선 순위가 높은 정점과 바꾼다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;5. 두 자식의 정점이 더 우선순위가 낮을 때까지 반복한다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;6. 그러면 자연스럽게 우선 순위가 더 높은 정점이 루트 정점이 될 수 있다. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;7. 추가와 마찬가지로 제거도 완전 이진 트리의 높이만큼만 진행되기에 시간복잡도가 &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;O(logN)(==&lt;/span&gt;로그시간)을 가진다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙 제거 예시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 루트정점인 63을 제거&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;692&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOgpST/btrWeGL0ovj/IrH1h4fRiWdaB7CZHOV6Uk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOgpST/btrWeGL0ovj/IrH1h4fRiWdaB7CZHOV6Uk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOgpST/btrWeGL0ovj/IrH1h4fRiWdaB7CZHOV6Uk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOgpST%2FbtrWeGL0ovj%2FIrH1h4fRiWdaB7CZHOV6Uk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;276&quot; height=&quot;292&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;692&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 63이 제거되면 가장&amp;nbsp;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;마지막 정점인 36이 루트에 위치하게됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;674&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yLM5X/btrWdnsEtxL/ss5shMbFykXN7T7ujBg9oK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yLM5X/btrWdnsEtxL/ss5shMbFykXN7T7ujBg9oK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yLM5X/btrWdnsEtxL/ss5shMbFykXN7T7ujBg9oK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyLM5X%2FbtrWdnsEtxL%2Fss5shMbFykXN7T7ujBg9oK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;277&quot; height=&quot;307&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 여기서 36의 자식 정점인 54와 45를 비교&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dIsYqx/btrWdokMvul/IobS838tIsQrjWBSUf7AKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dIsYqx/btrWdokMvul/IobS838tIsQrjWBSUf7AKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dIsYqx/btrWdokMvul/IobS838tIsQrjWBSUf7AKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdIsYqx%2FbtrWdokMvul%2FIobS838tIsQrjWBSUf7AKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;288&quot; height=&quot;296&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 54가 우선순위가 더 높기 때문에 36과 54를 바꾼다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;692&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dj4QEa/btrWmnxElX7/fNkqdphH6HfX7RD5cBsI6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dj4QEa/btrWmnxElX7/fNkqdphH6HfX7RD5cBsI6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dj4QEa/btrWmnxElX7/fNkqdphH6HfX7RD5cBsI6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdj4QEa%2FbtrWmnxElX7%2FfNkqdphH6HfX7RD5cBsI6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;298&quot; height=&quot;301&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;692&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 여기서 36의 자식 정점인 27과 비교한다. 오른쪽 자식은 없기 때문에 27하고만 비교하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baK8Uf/btrWeYeJY58/xYwxjX78PYfGCI1D5Biqn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baK8Uf/btrWeYeJY58/xYwxjX78PYfGCI1D5Biqn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baK8Uf/btrWeYeJY58/xYwxjX78PYfGCI1D5Biqn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaK8Uf%2FbtrWeYeJY58%2FxYwxjX78PYfGCI1D5Biqn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;311&quot; height=&quot;323&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;662&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;7. 자식의 우선 순위가 더 낮기 때문에 바꾸지않고 로직을 마친다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;파이썬에서 힙 구현&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;파이썬에서 가장 쉽게 힙을 구현하는 방법은 heapq 모듈을 이용하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;heapq 모듈은 기존 리스트 객체를 힙 알고리즘을 사용할 수 있도록 도와주는 모듈이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;힙에 요소를 추가할 때는 heappush 함수를 이용하고, 힙에서 요소를 제거할 때는 heappop 함수를 사용하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;아쉬운 점은 heapq는 min heap만 제공한다는 점이다. max heap을 이용하고 싶다면 직접 구현하거나 비 표준 함수를 사용하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1673790041936&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import heapq

hq = []  # Min heap

# 힙에 요소 추가
heapq.heappush(hq, 45)
heapq.heappush(hq, 36)
heapq.heappush(hq, 54)
heapq.heappush(hq, 27)
heapq.heappush(hq, 63)

print(hq)
&amp;gt;&amp;gt; 27, 36, 45, 54, 63

# 힙에서 요소 제거
print(heapq.heappop(hq))
&amp;gt;&amp;gt; 27
print(heapq.heappop(hq))
&amp;gt;&amp;gt; 36
print(heapq.heappop(hq))
&amp;gt;&amp;gt; 45

# 요소 제거 후 추가
heapq.heapreplace(hq, 10)
print(hq[0])
&amp;gt;&amp;gt; 10

# 요소 추가 후 제거
heapq.heappushpop(hq, 5)
print(hq[0])
&amp;gt;&amp;gt; 10


# 리스트를 힙으로 변경
lst = [5, 1, 2, 7, 4, 9, 8, 10, 3, 6]
heapify(lst)
print(lst)
&amp;gt;&amp;gt; [1, 3, 2, 5, 4, 9, 8, 10, 7, 6]  # Heap 기준에서 바라볼 때 정렬된 모습&lt;/code&gt;&lt;/pre&gt;</description>
      <category>TIL/알고리즘  with 파이썬</category>
      <category>우선순위 큐</category>
      <category>자료구조</category>
      <category>파이썬</category>
      <category>힙</category>
      <author>yangahh</author>
      <guid isPermaLink="true">https://devvvyang.tistory.com/63</guid>
      <comments>https://devvvyang.tistory.com/63#entry63comment</comments>
      <pubDate>Sun, 15 Jan 2023 22:41:15 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] 해시 테이블</title>
      <link>https://devvvyang.tistory.com/62</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;해시 테이블&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 테이블은 key-value 시스템을 이용하여 데이터를 저장하는 자료구조다.&lt;br /&gt;해시 테이블은 한정된 &lt;b&gt;배열 공간&lt;/b&gt;에 key를 index로 변환하여 그 index에 각각의 value들을 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key를 index로 변환할 때는 &lt;b&gt;해시함수&lt;/b&gt;가 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** 해시함수: 입력받은 값을 특정 범위 내의 숫자로 변경하는 함수를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 예를 들면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1bux0/btrWeXz0XT0/wtObMtaFvtW3RQI4Zbbmb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1bux0/btrWeXz0XT0/wtObMtaFvtW3RQI4Zbbmb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1bux0/btrWeXz0XT0/wtObMtaFvtW3RQI4Zbbmb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1bux0%2FbtrWeXz0XT0%2FwtObMtaFvtW3RQI4Zbbmb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;730&quot; height=&quot;868&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;868&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pizza, cake, taco는 key 이고, 이 메뉴들의 가격이 value라고 하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 key들을 hash function에 넣어 구한 값(=Hasing해서 나온 값)이 index가 되고, 이렇게 구한 인덱스에 value를 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 배열이 해시 테이블이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시테이블에서는 index를 bucket이라고 부르며 각 요소에는 key와 value를 모두 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;시간 복잡도&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삽입의 시간 복잡도는 O(1)이고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key를 알고있다면 삭제, 탐색도 역시 O(1)시간이 소요된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;해시 충돌 Hash Collision&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 언급했듯이 해시 함수를 이용하여 인덱스 값을 구할 때, 만일 해싱된 값이 중복되게 나올 경우 이를 해시 충돌이 발생했다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 충돌을 해결하는 대표적인 4가지 방법은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. 선형 탐사법&lt;br /&gt;&amp;nbsp; &amp;nbsp; 충돌이 발생하면 한 칸 옆으로 이동한다. 이동했을 때 또 충돌이 난다면 충돌이 발생하지 않을 때까지 이동하는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 따라서, 최악의 경우 탐색에 O(n)시간이 걸릴 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;722&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFQPr5/btrWdHqVpOj/DeISGMywawrI7quLYUwouk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFQPr5/btrWdHqVpOj/DeISGMywawrI7quLYUwouk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFQPr5/btrWdHqVpOj/DeISGMywawrI7quLYUwouk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFQPr5%2FbtrWdHqVpOj%2FDeISGMywawrI7quLYUwouk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;443&quot; height=&quot;722&quot; data-origin-width=&quot;1142&quot; data-origin-height=&quot;722&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. 제곱 탐사법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 충돌이 발생하면 충돌이 발생한 횟수의 제곱만큼 옆 칸으로 이동하는 방법&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzYaNd/btrWfQ8CiS8/X4Whu2NQBozkmnaz168dbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzYaNd/btrWfQ8CiS8/X4Whu2NQBozkmnaz168dbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzYaNd/btrWfQ8CiS8/X4Whu2NQBozkmnaz168dbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzYaNd%2FbtrWfQ8CiS8%2FX4Whu2NQBozkmnaz168dbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;441&quot; height=&quot;259&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 3. 이중 해시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 충돌이 발생하면 다른 해시함수를 이용하여 index를 구하는 방법. &lt;br /&gt;&amp;nbsp; &amp;nbsp; 또 충돌이 발생하면 충돌이 발생하지 않을때 까지 두번째 해시로 인덱스를 만들어낸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;892&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byBul7/btrWd1Qlllv/Vt0UJ74fv7JKdK2x3ENFUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byBul7/btrWd1Qlllv/Vt0UJ74fv7JKdK2x3ENFUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byBul7/btrWd1Qlllv/Vt0UJ74fv7JKdK2x3ENFUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyBul7%2FbtrWd1Qlllv%2FVt0UJ74fv7JKdK2x3ENFUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;289&quot; data-origin-width=&quot;892&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 4. 분리 연결법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 위 3가지 방법과는 다르게 충돌이 발생할 경우, 다른 인덱스로 이동하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 대신 해시테이블의 요소를 연결 리스트로 만들어 충돌이 발생한 버켓에 그대로 요소를 추가하는 방법이다. &lt;br /&gt;&amp;nbsp; &amp;nbsp; 이 방법은 최악의 경우 하나의 버켓이 무한정 늘어날 수 있다는 단점이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rU1Dr/btrWdgmLOD6/FHEBwGMHWpKMcgcbcl3m10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rU1Dr/btrWdgmLOD6/FHEBwGMHWpKMcgcbcl3m10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rU1Dr/btrWdgmLOD6/FHEBwGMHWpKMcgcbcl3m10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrU1Dr%2FbtrWdgmLOD6%2FFHEBwGMHWpKMcgcbcl3m10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;398&quot; height=&quot;255&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;해시 테이블 어디에 사용할까?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색에 상수시간에 걸리므로 **탐색**이 많이 일어나는 경우에 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(해시 충돌로 인해 최악의 경우 선형시간이 걸릴 수 있지만 그래도 배열로 저장했을 때보다 속도면에서는 안전)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;파이썬으로 해시테이블 구현하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Dictionary타입으로 해시테이블 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 내부적으로 동작하는 건 조금 다르지만 사용법은 거의 동일하다.&lt;/p&gt;
&lt;pre id=&quot;code_1673782432138&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;table = {}  # 해시 테이블

table['key'] = 100
table['key2'] = 'hello'

print(table['key'])
&amp;gt;&amp;gt; 100

table['key'] = 300

print(table['key'])
&amp;gt;&amp;gt; 300

del table['key']

print(table['key'])
&amp;gt;&amp;gt; 에러 발생&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. set타입으로 해시테이블 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; set을 사용하면 key와 value가 동일하게 저장되는 방식으로 구현할 수 있다. 또는 집합이라고 볼 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &lt;span style=&quot;background-color: #ffffff; color: #232830;&quot;&gt;중복된 내용을 전부 제거할 때도 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1673782775351&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;table1 = set()

table1.add('key')
table1.add(100)

table2 = set()
table2.add('key')
table2.add('hello')

print(table1 &amp;amp; table2)  # 교집합
&amp;gt;&amp;gt; {'key'}
print(table1 | table2) # 합집합
&amp;gt;&amp;gt; {'key', 100, 'hello'}
print(table1 - table2)  # 차집합
&amp;gt;&amp;gt; {100}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>TIL/알고리즘  with 파이썬</category>
      <category>자료구조</category>
      <category>파이썬</category>
      <category>해시충돌</category>
      <category>해시테이블</category>
      <author>yangahh</author>
      <guid isPermaLink="true">https://devvvyang.tistory.com/62</guid>
      <comments>https://devvvyang.tistory.com/62#entry62comment</comments>
      <pubDate>Sun, 15 Jan 2023 20:42:01 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] 파이썬에서 큐 구현</title>
      <link>https://devvvyang.tistory.com/61</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;deque를 이용한 Queue 구현&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;deque는 스택과 큐가 합쳐진 자료구조라고 생각하면 된다.&lt;br /&gt;deque는 list와 사용방법이 거의 비슷하지만,&lt;br /&gt;첫번째 요소를 제거하는 popleft()함수를 지원하고 있어서 이를 이용하면 상수시간으로 첫번째 요소를 제거할 수 있다.&lt;br /&gt;따라서 파이썬으로 queue를 구현할 때 deque를 사용하면 좋다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;from collections import deque

q = deque()  # queue 생성
q.append(1)  # EnQueue (=요소 추가)
q.append(2)
q.append(4)
print(q.popleft())  # DeQueue(=첫번째 요소 삭제)
&amp;gt;&amp;gt; 1

q.append(8)
print(len(q))
&amp;gt;&amp;gt; 3

&lt;/code&gt;&lt;/pre&gt;</description>
      <category>TIL/알고리즘  with 파이썬</category>
      <category>자료구조</category>
      <category>큐</category>
      <category>파이썬</category>
      <author>yangahh</author>
      <guid isPermaLink="true">https://devvvyang.tistory.com/61</guid>
      <comments>https://devvvyang.tistory.com/61#entry61comment</comments>
      <pubDate>Sun, 15 Jan 2023 19:48:52 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] 연결리스트</title>
      <link>https://devvvyang.tistory.com/60</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;연결 리스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결리스트는 각 요소를 포인터로 연결하여 관리하는 선형 자료구조다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 요소는 노드라고 부르며 데이터 영역과 포인터 영역으로 구성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 첫번째 노드를 Head라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 노드에 알파벳으로 써놓은 부분이 데이터 영역(=노드의 값)이며 동그라미 부분이 포인터 영역으로 다음 노드를 가리키는 역할을 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cd4WDQ/btrVWyGikOc/e9X4DwPJhWCmcT5UPIkfxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cd4WDQ/btrVWyGikOc/e9X4DwPJhWCmcT5UPIkfxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cd4WDQ/btrVWyGikOc/e9X4DwPJhWCmcT5UPIkfxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcd4WDQ%2FbtrVWyGikOc%2Fe9X4DwPJhWCmcT5UPIkfxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;754&quot; height=&quot;291&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리가 허용하는 한 요소를 제한없이 추가할 수 있다.&lt;/li&gt;
&lt;li&gt;탐색은&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;O(n)이 소요된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;요소를 추가하거나 제거할 때는 O(1)이 소요된다.&lt;/li&gt;
&lt;li&gt;Singly Linked List, Doubly Linked List, Circular Linked List가 존재한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;연결 리스트에서의 요소 삭제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 삭제할 요소를 선택&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;279&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw7Hts/btrVTVJO9HG/JUEMWs800FlDWoZg0jkx4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw7Hts/btrVTVJO9HG/JUEMWs800FlDWoZg0jkx4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw7Hts/btrVTVJO9HG/JUEMWs800FlDWoZg0jkx4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw7Hts%2FbtrVTVJO9HG%2FJUEMWs800FlDWoZg0jkx4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;264&quot; height=&quot;138&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;279&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 삭제할 요소의 이전 요소가 가리키는 포인터를 삭제할 요소의 다음 요소에 연결한다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ObKgy/btrVWx1E0sJ/HrSHtG2H45aDs3OA1aXkqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ObKgy/btrVWx1E0sJ/HrSHtG2H45aDs3OA1aXkqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ObKgy/btrVWx1E0sJ/HrSHtG2H45aDs3OA1aXkqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FObKgy%2FbtrVWx1E0sJ%2FHrSHtG2H45aDs3OA1aXkqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;265&quot; height=&quot;134&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 삭제할 요소를 완전히 삭제. 배열과는 다르게 이 로직을 수행하는데 상수시간(=O(1))소요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;251&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFF1UN/btrVTUxqjN3/rrJz4T3uowIWbKhWUJkiFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFF1UN/btrVTUxqjN3/rrJz4T3uowIWbKhWUJkiFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFF1UN/btrVTUxqjN3/rrJz4T3uowIWbKhWUJkiFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFF1UN%2FbtrVTUxqjN3%2FrrJz4T3uowIWbKhWUJkiFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;264&quot; height=&quot;140&quot; data-origin-width=&quot;472&quot; data-origin-height=&quot;251&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;연결 리스스트에서의 요소 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 추가할 요소의 포인터가 끼워넣을 부분의 다음 요소를 가리키도록 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BHMFJ/btrVT5Fmb33/gwpmSuLkmEXXWH88Iy45tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BHMFJ/btrVT5Fmb33/gwpmSuLkmEXXWH88Iy45tK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BHMFJ/btrVT5Fmb33/gwpmSuLkmEXXWH88Iy45tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBHMFJ%2FbtrVT5Fmb33%2FgwpmSuLkmEXXWH88Iy45tK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;274&quot; height=&quot;147&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 끼워넣을 부분의 이전 요소의 포인터를 추가할 요소를 가리키도록 한다. 삭제 로직과 마찬가지로 추가 로직도 상수시간(=O(n))소요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU0m1V/btrVT8a3Hub/5GZbl9khLyrpH2g4CH8yk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU0m1V/btrVT8a3Hub/5GZbl9khLyrpH2g4CH8yk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU0m1V/btrVT8a3Hub/5GZbl9khLyrpH2g4CH8yk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU0m1V%2FbtrVT8a3Hub%2F5GZbl9khLyrpH2g4CH8yk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;280&quot; height=&quot;147&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Singly Linked List (단일 연결 리스트)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 단순한 연결리스트. Head(첫번째 요소)에서 Tail(마지막 요소)까지 단방향으로 이어지는 연결리스트다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;헤드포인터: 헤드를 가리킴. 출발점.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tail의 포인터 영역은 Null로 되어있음.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1039&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDukjn/btrVUkPM8Qp/Gz3NsPUkYjhSi64TD5dky1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDukjn/btrVUkPM8Qp/Gz3NsPUkYjhSi64TD5dky1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDukjn/btrVUkPM8Qp/Gz3NsPUkYjhSi64TD5dky1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDukjn%2FbtrVUkPM8Qp%2FGz3NsPUkYjhSi64TD5dky1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1039&quot; height=&quot;231&quot; data-origin-width=&quot;1039&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Singly Linked List 요소 찾기 (탐색)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 위 연결 리스트에서 '4'를 찾는다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. 헤드 포인터에서 다음 요소인 Head를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. Head에 가서 데이터가 4인지 확인하고 아니면 다음 요소로 넘어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 3. 다음 요소의 데이터도 4가 아니므로 그 다음 요소로 넘어간다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 4. 이번 요소는 4이므로 탐색을 종료한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;gt;&amp;gt; O(n)시간 소요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Singly Linked List 요소 추가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 위 연결리스트에서 데이터 값이 2인 요소와 4인 요소 사이에 데이터 값이 3인 요소를 추가한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. 추가할 요소의 포인터 영역이 4인 요소를 가리키게 만든다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1026&quot; data-origin-height=&quot;457&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JwC6s/btrVVHQ37iY/jd7ItquoG2HxTqFvTRkQ2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JwC6s/btrVVHQ37iY/jd7ItquoG2HxTqFvTRkQ2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JwC6s/btrVVHQ37iY/jd7ItquoG2HxTqFvTRkQ2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJwC6s%2FbtrVVHQ37iY%2Fjd7ItquoG2HxTqFvTRkQ2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;532&quot; height=&quot;237&quot; data-origin-width=&quot;1026&quot; data-origin-height=&quot;457&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. 2인 요소의 포인터가 추가할 요소를 가리키게 만든다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biCa5h/btrVT8vnyzf/WkUg995KrZ9gK7tWxHM2n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biCa5h/btrVT8vnyzf/WkUg995KrZ9gK7tWxHM2n0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biCa5h/btrVT8vnyzf/WkUg995KrZ9gK7tWxHM2n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiCa5h%2FbtrVT8vnyzf%2FWkUg995KrZ9gK7tWxHM2n0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;592&quot; height=&quot;267&quot; data-origin-width=&quot;1036&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;gt;&amp;gt; O(1)시간 소요&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, O(1)이 소요되는 것은 단순히 '추가'하는 것만 생각했을 때의 소요시간. 즉, 끼워넣을 위치를 찾고 추가한다면 탐색이 더해져서 O(n)이 늘어남. 따라서 연결 리스트를 사용할 때는 추가를 위한 탐색을 하지 않도록 주의해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Singly Linked List 요소 삭제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 위 연결리스트에서 데이터 값이 2인 요소를 삭제한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. 삭제할 요소의 이전 요소가 삭제할 요소의 다음 요소를 가리키도록 수정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1027&quot; data-origin-height=&quot;294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TwfeM/btrVTmN7wvn/tJjDVkfkh1edwxbUFjjrc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TwfeM/btrVTmN7wvn/tJjDVkfkh1edwxbUFjjrc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TwfeM/btrVTmN7wvn/tJjDVkfkh1edwxbUFjjrc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTwfeM%2FbtrVTmN7wvn%2FtJjDVkfkh1edwxbUFjjrc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;612&quot; height=&quot;175&quot; data-origin-width=&quot;1027&quot; data-origin-height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. 메모리상에서 요소를 완전하게 삭제&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/70tg9/btrVQOYILRf/GJaFTk6ZmFpSUVaJ0Cggd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/70tg9/btrVQOYILRf/GJaFTk6ZmFpSUVaJ0Cggd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/70tg9/btrVQOYILRf/GJaFTk6ZmFpSUVaJ0Cggd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F70tg9%2FbtrVQOYILRf%2FGJaFTk6ZmFpSUVaJ0Cggd0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;603&quot; height=&quot;174&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt; O(1)시간 소요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Doubly Linked List (이중 연결 리스트)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인터가 두개 존재하여 다음과 이전을 가르킬 수 있어 양방향으로 이어지는 구조인 연결 리스트다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Head는 첫번째 요소이므로 이전 노드를 가리키는 포인터는 Null이고, Tail은 마지막 요소이므로 다음 노드를 가리키는 포인터가 Null이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cV7gwi/btrVVIoWeeB/nW3awoSYZNKkiMiJm4Wc10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cV7gwi/btrVVIoWeeB/nW3awoSYZNKkiMiJm4Wc10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cV7gwi/btrVVIoWeeB/nW3awoSYZNKkiMiJm4Wc10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcV7gwi%2FbtrVVIoWeeB%2FnW3awoSYZNKkiMiJm4Wc10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1025&quot; height=&quot;306&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;306&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Doubly Linked List 요소 추가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 위 연결리스트에서 데이터 값이 2인 요소와 4인 요소 사이에 데이터 값이 3인 요소를 추가한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. 추가할 요소의 다음 요소를 가리키는 포인터가 4인 요소를 가리키게 만든다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;593&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vYqTf/btrVUlnDBrn/zGYKk5qKhXfGDXuQr7mUZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vYqTf/btrVUlnDBrn/zGYKk5qKhXfGDXuQr7mUZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vYqTf/btrVUlnDBrn/zGYKk5qKhXfGDXuQr7mUZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvYqTf%2FbtrVUlnDBrn%2FzGYKk5qKhXfGDXuQr7mUZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;494&quot; height=&quot;286&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;593&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. 추가할 요소의 이전 요소(2)의 다음 포인터가 추가할 요소를 가리키도록 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1043&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqbJgJ/btrVStGQ2Pp/R7k6ELADV1SyXs1u5pLdHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqbJgJ/btrVStGQ2Pp/R7k6ELADV1SyXs1u5pLdHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqbJgJ/btrVStGQ2Pp/R7k6ELADV1SyXs1u5pLdHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqbJgJ%2FbtrVStGQ2Pp%2FR7k6ELADV1SyXs1u5pLdHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;586&quot; height=&quot;331&quot; data-origin-width=&quot;1043&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 3. 추가할 요소의 다음 요소(4)의 이전 포인터가 추가할 요소를 가리키도록 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;587&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R5DxK/btrVUiRYXmF/0He4Qw7pTZ8RzKmqEKme9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R5DxK/btrVUiRYXmF/0He4Qw7pTZ8RzKmqEKme9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R5DxK/btrVUiRYXmF/0He4Qw7pTZ8RzKmqEKme9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR5DxK%2FbtrVUiRYXmF%2F0He4Qw7pTZ8RzKmqEKme9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;582&quot; height=&quot;332&quot; data-origin-width=&quot;1029&quot; data-origin-height=&quot;587&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 4. 추가할 요소의 이전 포인터가 이전 요소(2)를 가리키도록 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgOndw/btrVU8uE3Zd/ccbOnpYgwTk9Oe2lsd77qK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgOndw/btrVU8uE3Zd/ccbOnpYgwTk9Oe2lsd77qK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgOndw/btrVU8uE3Zd/ccbOnpYgwTk9Oe2lsd77qK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgOndw%2FbtrVU8uE3Zd%2FccbOnpYgwTk9Oe2lsd77qK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;532&quot; height=&quot;590&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt;&amp;gt; 단일 연결 리스트와 마찬가지로 요소 추가 로직에 O(1)시간이 소요된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Doubly Linked List 요소 삭제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 위 연결리스트에서 데이터 값이 2인 요소를 삭제한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. 삭제할 요소의 이전 요소(1)의 다음 포인터가 삭제할 요소의 다음 요소(4)를 가리키도록 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;359&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/le81C/btrVWeA8J43/c7lN72tKWGkJn6fwI7raOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/le81C/btrVWeA8J43/c7lN72tKWGkJn6fwI7raOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/le81C/btrVWeA8J43/c7lN72tKWGkJn6fwI7raOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fle81C%2FbtrVWeA8J43%2Fc7lN72tKWGkJn6fwI7raOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;567&quot; height=&quot;201&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;359&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2. 삭제할 요소의 다음 요소(4)가 이전 노드로 삭제할 요소의 이전 요소(2)를 가리키도록 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcBP1l/btrVVgsz5Mt/c2lTuxIW85OdCCLszitx9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcBP1l/btrVVgsz5Mt/c2lTuxIW85OdCCLszitx9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcBP1l/btrVVgsz5Mt/c2lTuxIW85OdCCLszitx9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdcBP1l%2FbtrVVgsz5Mt%2Fc2lTuxIW85OdCCLszitx9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;576&quot; height=&quot;249&quot; data-origin-width=&quot;1025&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 3. 삭제할 요소를 메모리상에서 삭제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;gt;&amp;gt; 마찬가지로 O(1)시간 소요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Circular Linked List (환형 연결 리스트)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tail의 포인터가 Head를 가리키도록 한 연결 리스트. 메모리를 아껴쓸 수 있다. 원형 큐 등을 만들 때도 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에서 탐색을 시작하더라도, 한 바퀴를 다 돌 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VEkxV/btrVVIJd0UT/SiPmxIK61gifezfs3gGvMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VEkxV/btrVVIJd0UT/SiPmxIK61gifezfs3gGvMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VEkxV/btrVVIJd0UT/SiPmxIK61gifezfs3gGvMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVEkxV%2FbtrVVIJd0UT%2FSiPmxIK61gifezfs3gGvMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1074&quot; height=&quot;267&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;파이썬으로 구현한 연결리스트&lt;/h3&gt;
&lt;pre id=&quot;code_1673365662388&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Node:
    def __init__(self, value):  # 최초 생성시에는 다음 노드에 대한 정보가 없음. 아직 연결을 안했으므로
        self.value = value
        self.next = None
        
 
class SinglyLinkedList:  # 노드와 노드를 연결해주는 역할
    def __init__(self):
    	self.head = None
        self.tail = None
    
    def find(self, value):
    	curr_node = self.head
        while curr_node.value != value:
        	curr_node = curr_node.next
        return curr_node
    
    def append(self, new_value):  # 끝부분에 추가하는 append 로직
    	new_node = Node(new_value)
        if self.head is None:  # head가 없으면 아직 아무것도 없다는 뜻
        	self.head = new_node
            self.tail = new_node
        else:  # head가 이미 있으면 추가되는 node는 마지막 노드가 된다.
        	self.tail.next = new_node
            self.tail = new_node
    
    def insert(self, node: Node, new_value):  # 중간에 추가하는 insert 로직. node는 추가할 노드의 이전 노드를 말함
    	new_node = Node(new_value)
        new_node.next = node.next  # 추가할 노드의 포인터를 이전 노드의 포인터가 가르키던 다음 노드로 설정
        node.next = new_node  # 이전 노드의 포인터는 추가할 노드를 가리키도록 설정
    
    def remove(self, value):  # 값을 찾고, 삭제하는 로직. 따라서 O(n)시간(==선형시간) 소요
    	prev_node = self.head
        while prev_node.next.value != value:  # 이전 노드가 가르키는 노드의 값이 내가 삭제할 노드면 종료
        	prev_node = prev_node.next  # 다음 노드로 넘어감
        
        if prev_node.next is not None:  # 삭제할 노드가 Tail이 아니라면
        	prev_node.next = prev_node.next.next  # 삭제할 노드의 이전 노드가 가르키는 노드를 삭제할 노드의 다음 노드로 설정
            
    def display(self):
    	curr_node = self.head  # 첫번째 노드부터 탐색
        display_string = &quot;[&quot;
        while curr_node is not None:
        	display_string += f&quot;{curr_node.value}, &quot;
            curr_node = curr_node.next
        
        display_string = display_string[0: len(display_string) - 2]  # 여기서 2를 뺀 이유는 맨 앞 '[' 와 맨 마지막 요소가 None이 들어가므로 이것까지 제외한 것
        display_string += &quot;]&quot;
        
        print(display_string)
        


linked_list = SinglyLinkedList()
linked_list.append(1)
linked_list.append(2)
linked_list.append(3)
linked_list.append(5)
linked_list.display()
 &amp;gt;&amp;gt; [1, 2, 3, 5]
 
print(linked_list.find(3))
 &amp;gt;&amp;gt; &amp;lt;__main__.Node object at 0x10538cd60&amp;gt;
 
linked_list.remove(3)
linked_list.display()
 &amp;gt;&amp;gt; [1, 2, 5]
 
linked_list.insert(linked_list.find(2), 10)
linked_list.display()
 &amp;gt;&amp;gt; [1, 2, 10, 5]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL/알고리즘  with 파이썬</category>
      <category>연결리스트</category>
      <category>자료구조</category>
      <category>파이썬</category>
      <author>yangahh</author>
      <guid isPermaLink="true">https://devvvyang.tistory.com/60</guid>
      <comments>https://devvvyang.tistory.com/60#entry60comment</comments>
      <pubDate>Wed, 11 Jan 2023 00:55:44 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] Dockerfile 작성법 간단 정리</title>
      <link>https://devvvyang.tistory.com/59</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dockerfile이란,&amp;nbsp;Docker &lt;span&gt;이미지를&lt;/span&gt; &lt;span&gt;만드는&lt;/span&gt;&amp;nbsp;일종의 스크립트다. &lt;span&gt;Docker build &lt;/span&gt;명령어를&lt;span&gt; &lt;/span&gt;쓰면&lt;span&gt; &lt;/span&gt;이&lt;span&gt; &lt;/span&gt;파일을&lt;span&gt; &lt;/span&gt;읽어서&lt;span&gt; &lt;/span&gt;여기에&lt;span&gt; &lt;/span&gt;명시된&lt;span&gt; &lt;/span&gt;대로&lt;span&gt; &lt;/span&gt;이미지를&lt;span&gt; &lt;/span&gt;만든다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2138&quot; data-origin-height=&quot;713&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUk73g/btq5t2fDVjI/wKzHpkW9EZXB5VlMS5jtGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUk73g/btq5t2fDVjI/wKzHpkW9EZXB5VlMS5jtGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUk73g/btq5t2fDVjI/wKzHpkW9EZXB5VlMS5jtGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUk73g%2Fbtq5t2fDVjI%2FwKzHpkW9EZXB5VlMS5jtGk%2Fimg.png&quot; data-origin-width=&quot;2138&quot; data-origin-height=&quot;713&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Dockerfile 작성 예시&lt;/h2&gt;
&lt;pre id=&quot;code_1621679237153&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM ubuntu:14.04

LABEL version=0.1

# app 디렉토리 생성
RUN mkdir -p /app

# Docker 이미지 내부에서 RUN, CMD, ENTRYPOINT의 명령이 실행될 디렉터리를 설정
WORKDIR /app


# 현재 디렉터리에 있는 파일들을 이미지 내부 /app 디렉터리에 추가함
ADD . /app


RUN apt-get update

RUN apt-get install apache2

RUN service apache2 start


VOLUME [&quot;/data&quot;, &quot;/var/log/httpd&quot;]


# 외부로 노출하는 포트 지정
EXPOSE 80

# 이미지를 도커 컨테이너로 실행하기 전에 먼저 실행할 명령어
CMD [&quot;/app/log.backup.sh&quot;]

&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Dockerfile 형식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;주의사항: 컨테이너에 담을 파일들은 Dockerfile 하위 디렉토리에 있어야 한다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;FROM&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1621862469974&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM 이미지 이름:태그&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;base 이미지로 사용할 레이어를 가져오는 단계이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;FROM &amp;lt;이미지 이름&amp;gt;:&amp;lt;태그&amp;gt; 형식으로 작성한다.&lt;br /&gt;ex) ubuntu:14.04&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;LABEL&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1621862634968&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LABEL key=value&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이미지의 버전 정보, 작성자, 코멘트와 같이 이미지의 메타 정보를 입력하는 부분으로 빌드 자동화 등에 사용될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;** 라벨 확인 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;docker image inspect --format='label key값' 이미지명&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ENV&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Dockerfile 또는 컨테이너 내부의 환경변수에 대한 선언을 하는 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;ex) &lt;span style=&quot;color: #333333;&quot;&gt;JAVA_HOME /usr/lib/java&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;WORKDIR&lt;/b&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;명령을 실행하기 위한 디렉토리를 지정하는 부분이다. WORKDIR 을 지정하면 RUN, CMD, ENTRYPOINT, COPY, ADD 등의 명령이 영향을 받는다. 이 명령어에서 컨테이너의 '.' 으로 명시하면 WORKDIR의 위치를 가르키는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;COPY&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1621927670944&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;COPY [--chown=&amp;lt;user&amp;gt;:&amp;lt;group&amp;gt;] &amp;lt;src&amp;gt;... &amp;lt;dest&amp;gt;
# 공백이 포함된 경우는 
COPY [--chown=&amp;lt;user&amp;gt;:&amp;lt;group&amp;gt;] [&quot;&amp;lt;src&amp;gt;&quot;,... &quot;&amp;lt;dest&amp;gt;&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;호스트OS의 파일 및 디렉토리를 컨테이너 내부로 복사하는 명령어이다. 소유자와 소유그룹도 수정이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ADD&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1621927717996&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ADD [--chown=&amp;lt;user&amp;gt;:&amp;lt;group&amp;gt;] &amp;lt;src&amp;gt;.. &amp;lt;dest&amp;gt;
# 공백이 필요한 경우는 
ADD [--chown=&amp;lt;user&amp;gt;:&amp;lt;group&amp;gt;] [&quot;&amp;lt;src&amp;gt;&quot;.. &quot;&amp;lt;dest&amp;gt;&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;COPY와 마찬가지로 파일 및 디렉토리를 컨테이너 내부로 복사하는 명령어이다. 추가적으로 &lt;span style=&quot;color: #494e52;&quot;&gt;URL 및 &lt;/span&gt;원격 파일 다운로드 또는 압축 해제 등과 같은 기능도 있다. Dockerfile 안에서 ADD시&amp;nbsp;&lt;u&gt;절대경로는 사용이 불가능하다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;ex) ADD http://~~~/index.php /data/index.php&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;&lt;b&gt;RUN&lt;/b&gt;&amp;nbsp;&lt;br /&gt;도커 이미지가 생성되기 전에(=이미지를 빌드하는 시점에) 실행되는 쉘 명령어를 작성하는 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;RUN 명령은&amp;nbsp;설치/설정 등을 위한 용도로 쓰여서 image layer를 만들어낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;RUN을 사용하는 방법에는 2가지 형식이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. /bin/bash -c command 형식으로 shell 명령을 실행&lt;/p&gt;
&lt;pre id=&quot;code_1621863641990&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN &quot;command&quot; 
# 예) RUN yum install -y python&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1621863627406&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;RUN [&quot;executable&quot;, &quot;param1&quot;, &quot;param2&quot;] 
# 예) RUN [&quot;/bin/bash&quot;, &quot;-c&quot;, &quot;echo hello&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;executable 은 명령어를 실행할 양식 (bash, zsh, etc)을 지정.&lt;/li&gt;
&lt;li&gt;executable 을 이용해서 별도의 python, ruby 스크립트를 실행 가능하다.&lt;/li&gt;
&lt;li&gt;param1, param2 는 해당 명령어를 실행하면서 전달할 파라미터이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;CMD&lt;/b&gt;&lt;br /&gt;RUN 명령어는 이미지를 빌드하는 시점에 실행되는 반면에, CMD 는 &lt;u&gt;컨테이너를 실행할 때(=컨테이너가 시작될 때) 수행&lt;/u&gt;되는 실행 파일 또는 셸 스크립트를 작성하는 부분이다.&lt;br /&gt;주의 해야할 점은 Dockerfile 에서 CMD 는 1개만 적용되며 &lt;u&gt;여러 개를 지정한 경우 마지막 CMD 만이 적용&lt;/u&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;또한 docker run 을 사용하며 새로운 명령을 지정한 경우(=명령에 쉘 명령어 및 인자값 전달할 경우) CMD에 작성된 명령어와 인자값은 무시된다. 즉, 우선 순위는 docker run &amp;gt; CMD 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;CMD를 사용하는 방법에는 3가지 형식이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 가장 기본적인 형식&lt;/p&gt;
&lt;pre id=&quot;code_1621864640108&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CMD [&quot;executable&quot;,&quot;param1&quot;,&quot;param2&quot;]
# 예) CMD [&quot;gunicorn&quot;, &quot;--bind&quot;, &quot;0.0.0.0:8000&quot;, &quot;test_project.wsgi:application&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. shell 명령을 실행&lt;/p&gt;
&lt;pre id=&quot;code_1621864674616&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CMD command param1 param2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. ENTRYPOINT 의 매개변수 전달&lt;/p&gt;
&lt;pre id=&quot;code_1621864701527&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CMD [&quot;param1&quot;,&quot;param2&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;ENTRYPOINT&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1621925776818&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ENTRYPOINT [&quot;executable&quot;, &quot;param1&quot;, &quot;param2&quot;]
# 또는
ENTRYPOINT command param1 param2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;도커 컨테이너를 실행하기 전에 &lt;u&gt;최종적으로 실행&lt;/u&gt;할 명령어를 적는 부분이다. CMD와 마찬가지로 &lt;u&gt;1번만 수행&lt;/u&gt;할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;CMD와의 차이점은 ENTRYPOINT는 CMD를 인자로 받아 사용할 수 있는 스크립트를 쓴다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;또한 CMD는 docker run 을 사용하며 새로운 명령을 지정한 경우 CMD에 지정한 명령이 무시되지만, ENTRYPOINT는 docker run에서 지정한 명령과 관계 없이 실행된다는 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;VOLUME&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1621862484845&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;VOLUME ['컨테이너 디렉토리1', '컨테이너 디렉토리2' , .... ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;컨테이너 안에 있는 데이터는 컨테이너를 삭제하면 모든 데이터가 같이 삭제(휘발성 데이터) 되기 때문에 데이터를 보존하기 위해 VOLUME을 사용한다.&lt;br /&gt;VOLUME에 명시된 (컨테이너에 있는) 디렉토리 안의 모든 데이터는 컨테이너에 저장하지 않고 호스트 OS에 저장하거나 컨테이너들간의 데이터를 공유가 가능하도록 설정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Dockerfile 에서 생성한 볼륨은 호스트OS의 &lt;u&gt;/var/lib/docker/volumes&lt;/u&gt;에 생성되며, Docker 에서 자동 생성한 hash값으로 디렉토리가 생긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;** docker run 명령에서 -v 옵션을 아래와 같이 사용하면 호스트 OS의 위치(볼륨 마운트의 위치)를 지정한 위치(아래의 예시에서는 /root/data)로 변경할 수 있다.&lt;br /&gt;ex)&amp;nbsp;-v&amp;nbsp;/root/data:/data&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;EXPOSE&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1621928260737&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;EXPOSE &amp;lt;port&amp;gt; [&amp;lt;port&amp;gt;/&amp;lt;protocol&amp;gt;...]
# 예) EXPOSE 80/tcp
# 프로토콜 default는 tcp&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #494e52;&quot;&gt;컨테이너의 런타임에 지정된 네트워크 포트에서 수신 대기를 한다는 것을 나타낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;참고: &lt;a href=&quot;https://docs.docker.com/engine/reference/builder/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;docker docs&lt;/a&gt;&lt;/p&gt;</description>
      <category>TIL/Docker</category>
      <category>docker</category>
      <author>yangahh</author>
      <guid isPermaLink="true">https://devvvyang.tistory.com/59</guid>
      <comments>https://devvvyang.tistory.com/59#entry59comment</comments>
      <pubDate>Tue, 25 May 2021 16:42:13 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] Docker 개념 간단 정리</title>
      <link>https://devvvyang.tistory.com/58</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;docker-logo.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;129&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jj2pl/btq04LH5bmJ/Ci7vP3nkdBtSsIHeM9oxy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jj2pl/btq04LH5bmJ/Ci7vP3nkdBtSsIHeM9oxy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jj2pl/btq04LH5bmJ/Ci7vP3nkdBtSsIHeM9oxy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJj2pl%2Fbtq04LH5bmJ%2FCi7vP3nkdBtSsIHeM9oxy0%2Fimg.png&quot; data-filename=&quot;docker-logo.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;129&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;도커란, 컨테이너 기반의 오픈소스 가상화 플랫폼 중 하나인데, 지금은 도커가 널리 쓰여지면서 컨테이너기반 가상화 플랫폼의 대명사처럼 되어버렸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여기서 컨테이너란 우리가 흔히 생각하는 화물들을 실어서 수송할 때 사용하는 그 컨테이너에서 착안한 개념이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;서버에서 컨테이너를 사용하면 다양한 OS환경, 여러 프로그램들을 컨테이너에 실어 여러 곳으로 운반하여 배포할 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;즉, 도커를 사용하면(=컨테이너를 사용하면) 하나의 서버에서 각각의 서비스들이 서로 방해받을 일 없이 프로그램처럼 돌아가게 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이런 독립된 컨테이너들은 Image 기반으로 만들어지고, 이 Image는 Docker(기업)에서 제공하고 있는 dockerhub라는 곳에 push/pull 해서 어디에서든 서비스를 배포할 수 있게 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;VM vs Container&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;도커는 하나의 가상 서버라고도 할 수 있다(사실상 컨테이너는 인프라이면서 프로그램 인 것이다).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그렇다면 이전에 많이 사용하던 VM(가상머신)들과는 어떻게 다른 것일까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;vmvsdocker.png&quot; data-origin-width=&quot;3560&quot; data-origin-height=&quot;1780&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QtCVl/btq1tDXgYOZ/26VC7AZlnYwPYt61tCUadk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QtCVl/btq1tDXgYOZ/26VC7AZlnYwPYt61tCUadk/img.png&quot; data-alt=&quot;출처:&amp;amp;amp;nbsp;https://www.weave.works/blog/a-practical-guide-to-choosing-between-docker-containers-and-vms&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QtCVl/btq1tDXgYOZ/26VC7AZlnYwPYt61tCUadk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQtCVl%2Fbtq1tDXgYOZ%2F26VC7AZlnYwPYt61tCUadk%2Fimg.png&quot; data-filename=&quot;vmvsdocker.png&quot; data-origin-width=&quot;3560&quot; data-origin-height=&quot;1780&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처:&amp;nbsp;https://www.weave.works/blog/a-practical-guide-to-choosing-between-docker-containers-and-vms&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;- VM (Virtual Machines, 가상머신)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기존의 가상화 시스템인 VM은 host OS위에 설치된 &lt;u&gt;hypervisor라는 프로그램(가상화 제어 프로그램) 위에서 동작&lt;/u&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;VM은 hypervisor를 통해 그 위에서 수십개의&amp;nbsp;Guest OS를 돌리고, 하드웨어를 가상으로 할당해준다.&lt;br /&gt;실제로 사용할 땐&amp;nbsp; Guest OS &amp;gt; Host OS &amp;gt; H/W 순으로 접근하게 된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이런 구조다 보니 실행이 느리고, 시스템의 리소스를 많이 잡아먹게 된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;또한 호스트 서버가 내려갔을 시, 호스트&amp;nbsp;컴퓨터를&amp;nbsp;다시&amp;nbsp;부팅시키는&amp;nbsp;시간과&amp;nbsp;각 VM 부팅하는&amp;nbsp;시간이 더해져서 부팅만 하는 데에도&amp;nbsp;docker에 비해 오랜 시간이 걸린다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;뿐만 아니라, VM의 이미지에는 OS 이미지도 포함되어 있는데, 이 때문에 이미지 용량이 상당해서 배포와 관리를 힘들게 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;- Container&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;컨테이너 기반의 가상화 시스템(이하 도커)은 VM과 다르게 Host OS위에서 바로 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;도커는 hypervisor와는 다르게 &lt;u&gt;Host OS와 커널을 공유&lt;/u&gt;하기 때문에 하드웨어 제어 부분을 같이 공유해서 쓸 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;도커 데몬은 호스트 OS가 무슨 종류이든지간에 호스트 OS의 커널에 접근해서 통역을 해준다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;또한 커널을 공유하기 때문에 부팅이 없으며 &lt;u&gt;마치 프로세스와 같이 메모리에 적재되어 실행&lt;/u&gt;된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그래서 이미지를 실행하게되면 컴퓨터가 바로 실행되듯 플레이가 된다(부팅시간 없음).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이러한 장점들로 인해 도커를 사용하면 배포가 빨라지고, 서버가 망가져도 서버만 다시 실행시키고 이미지만 다시&amp;nbsp;실행하면 되서 복구 시간이 단축된다는 장점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker의 구조&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker는 아래와 같이 구분되어 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker client와 server(server는 Docker engine, Docker daemon으로 불리기도 한다.)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker image&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker registries&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker containers&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;- Docker client와 server&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker는 클라리언트와 서버 구조로 이루어져 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker 클라이언트는 Docker 사용자가 Docker 서버와 상호작용하게 하게 한다. 즉 우리가 docker run 과 같은 명령어를 입력하면 클라이언크가 API로 dockerd로 보내 도커를 실행시킨다. 여기서 dockerd가 Docker server(=Docker daemon 또는 Docker engine)이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker 서버는 클라이언트에서 보낸 API 요청을 수신하고 이미지, 컨테이너, 네트워크 및 볼륨과 같은 Docker 객체를 관리한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;- Docker image&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이미지는 &lt;b&gt;컨테이너를 구성하는 파일 시스템과 실행할 어플리케이션의 설정 값 들을 포함하고 있는 것&lt;/b&gt;으로, 컨테이너를 생성하는 템플릿 역할을 한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker 이미지는 'Dockerfile'에 명시된 것들을 기반으로 build라는 명령어를 통해 생성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker 이미지의 특징은 Immutable(변하지 않음)하다는 것이다. 때문에 이미지를 통해 생성한 컨테이너의 상태가 바뀌거나 컨테이너가 삭제되더라도 이미지는 변하지 않고 그대로 남아있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;- Docker registires&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker registries는 Docker 이미지를 저장하는 '저장소'다. 소스코드를 github과 같은 저장소에 관리하듯, Docker 이미지는 Dockerhub와 같은 Docker registires에 저장한다고 생각하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Dockerhub는 누구나 사용할 수 있는 공용 registry이며(github과 마찬가지로 public registry 가 있고 private registry도 있다) Docker는 기본적으로 Dockerhub에서 이미지를 찾는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;registries 덕분에 이미지만 있으면 어디서든 배포가 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;- Docker container&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Docker container는 &lt;b&gt;Docker 이미지를 실행한 상태&lt;/b&gt;라고 볼 수있다. 추가되거나 변하는 값은 이미지가 아닌 컨테이너에 저장된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;run이라는 명령어를 통해 이미지를 실행시켜서 컨테이너를 띄운다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL/Docker</category>
      <category>docker</category>
      <author>yangahh</author>
      <guid isPermaLink="true">https://devvvyang.tistory.com/58</guid>
      <comments>https://devvvyang.tistory.com/58#entry58comment</comments>
      <pubDate>Fri, 21 May 2021 19:58:13 +0900</pubDate>
    </item>
  </channel>
</rss>