<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>JiHoon.log</title>
    <link>https://kjhs-97.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 28 Sep 2026 21:10:24 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>KongJiHoon</managingEditor>
    <image>
      <title>JiHoon.log</title>
      <url>https://tistory1.daumcdn.net/tistory/6995431/attach/9b8a83a87c5f4de89f4227b93b5b7b1a</url>
      <link>https://kjhs-97.tistory.com</link>
    </image>
    <item>
      <title>ArrayList</title>
      <link>https://kjhs-97.tistory.com/335</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1️⃣ ArrayList&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayList는 Java의&lt;b&gt; List 인터페이스의 구현체 중 하나&lt;/b&gt;로, &lt;b&gt;내부적으로 배열을 사용해서 데이터를 저장하는 동적 배열 자료구조&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1790507124722&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

list.add(&quot;A&quot;);
list.add(&quot;B&quot;);
list.add(&quot;C&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;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;span&gt;일반 배열:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;String[] arr = new String[3];&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;크기 &lt;/span&gt;3&lt;span&gt;으로 고정된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ArrayList:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;필요한 데이터가 늘어나면 내부 배열을 더 큰 배열로 교체&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 내부 구성 요소&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념적으로 ArrayList 내부에는 다음과 같은 필드가 있다고 보면된다.&lt;/p&gt;
&lt;pre id=&quot;code_1790507606834&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Object[] elementData;
int size&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;즉,&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;elementData
&amp;rarr; 실제 데이터를 저장하는 배열

size
&amp;rarr; 현재 저장된 데이터 개수&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 중요한 개념이 하나 더 있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;size&lt;span&gt;와 &lt;/span&gt;capacity&lt;span&gt;는 다르다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&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;  size와 capacity의 차이&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;예를 들어, 내부 배열이 다음과 같다고 한다면&lt;/p&gt;
&lt;pre id=&quot;code_1790507655371&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[A][B][C][ ][ ][ ][ ][ ][ ][ ]&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;실제 데이터는 3개지만 배열 공간은 10이다.&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;pre id=&quot;code_1790507674251&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;size = 3
capacity = 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉,&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;size
= 실제 들어있는 요소 개수

capacity
= 내부 배열이 저장할 수 있는 전체 공간&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) add() 동작&lt;/h4&gt;
&lt;pre id=&quot;code_1790507704026&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;list.add(&quot;D&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;내부에 공간이 있다면 매우 단순하다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;[A][B][C][ ][ ]
         &amp;darr;
[A][B][C][D][ ]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개념적으로:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;elementData[size] = value;
size++;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처럼 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 맨 뒤에 데이터를 추가하는 경우 보통:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 여기서 중요한 표현이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ArrayList의 맨 뒤 삽입은 정확히 항상 O(1)이 아니라 **amortized O(1)**이다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;왜냐하면 resize가 발생할 수 있기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) 배열의 공간 부족&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 상태라고 해보자.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;[A][B][C]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;배열이 꽉 찼다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그런데:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;list.add(&quot;D&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 수행해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존 배열 자체의 크기를 늘리는 것은 불가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java 배열은 생성 시 크기가 고정되기 때문이다.&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&gt;그래서 ArrayList는&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-27 오후 8.16.21.png&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;998&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q4nqX/dJMcagmM3Dd/ioCDOjqHYoHTnh8HDJagtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q4nqX/dJMcagmM3Dd/ioCDOjqHYoHTnh8HDJagtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q4nqX/dJMcagmM3Dd/ioCDOjqHYoHTnh8HDJagtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq4nqX%2FdJMcagmM3Dd%2FioCDOjqHYoHTnh8HDJagtK%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;540&quot; height=&quot;814&quot; data-filename=&quot;스크린샷 2026-09-27 오후 8.16.21.png&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;998&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;이 과정을 거치게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개념적으로:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;기존 배열

[A][B][C]

        &amp;darr;

새로운 더 큰 배열

[A][B][C][ ][ ][ ]

        &amp;darr;

D 추가

[A][B][C][D][ ][ ]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Open JDK의 현대적인 ArrayList 구현체는 일반적으로 &lt;b&gt;기존 capacity의 1.5배 정도 크게 확장되는 방식이 사용&lt;/b&gt;된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;일반적으로 O(1)이고, 내부 배열의 capacity가 부족해 resize가 발생하면 기존 요소를 새로운 배열로 복사해야 하기 때문에 해당 시점에는 O(n)이 걸립니다. 하지만 여러 삽입을 평균적으로 보면 amortized O(1)입니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(4) get()&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;get()의 시간복잡도는 O(1)dlek.&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;ArrayList는 인덱스를 통해 저장된 값에 접근할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개념적으로:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;배열 시작 주소
+
index &amp;times; 요소 크기&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 통해 원하는 위치를 바로 찾을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;get(index)
&amp;rarr; O(1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;LinkedList와 가장 크게 차이나는 부분이다.&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;size18&quot;&gt;&lt;b&gt;&lt;span&gt;  중간 삽입 &amp;amp; 삭제 O(n)&lt;/span&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;&lt;span&gt;다음 배열을 보자.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;[A][B][C][D]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;index 1에 &lt;/span&gt;X&lt;span&gt;를 삽입한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;list.add(1, &quot;X&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그러면 기존 값들을 뒤로 밀어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;기존

[A][B][C][D]

     &amp;darr;

[A][ ][B][C][D]

     &amp;darr;

[A][X][B][C][D]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&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&gt;따라서 &lt;b&gt;중간에 값을 삽입하는 경우에 값을 이동시켜야 하기 때문에&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;시간 복잡도는 O(n)&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;ArrayList의 값을 삭제하는 시간복잡도 또한 O(n)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;[A][B][C][D][E]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B&lt;span&gt;를 삭제하면:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;list.remove(1);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;빈 공간을 그대로 남겨두는 게 아니라 뒤쪽 요소들을 앞으로 당긴다&lt;/b&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 중간 삭제도&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(5) ArrayList 검색&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;list.contains(&quot;hello&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또는:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;list.indexOf(&quot;hello&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;배열 기반이라고 해서 값 검색도 O(1)은 아니다. &lt;/span&gt;&lt;span&gt;index를 알고 있을 때만 O(1)이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;값 자체를 찾으려면&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;0번째 확인
1번째 확인
2번째 확인
...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;contains()
indexOf()

&amp;rarr; O(n)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&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&gt;  정리&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;연산&lt;/td&gt;
&lt;td&gt;시간복잡도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;get(index)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;set(index)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;맨 뒤 add()&lt;/td&gt;
&lt;td&gt;amortized O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;중간 add(index, value)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;중간 remove(index)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;contains()&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;indexOf()&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2️⃣ ArrayList의 장점과 단점&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 장점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ArrayList의 가장 큰 장점은 &lt;/span&gt;&lt;b&gt;&lt;span&gt;빠른 index 접근&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이다. &lt;/span&gt;&lt;span&gt;그리고 실제로는 순회 성능도 좋은 편이다.&amp;nbsp; &lt;/span&gt;&lt;span&gt;왜냐하면 배열의 요소가 메모리상 비교적 연속적으로 배치되기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CPU는 데이터를 읽을 때 필요한 값 하나만 읽는 것이 아니라 주변 데이터도 같이 캐시에 가져오는 경우가 많다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이를 &lt;/span&gt;&lt;b&gt;&lt;span&gt;Spatial Locality&lt;/span&gt;&lt;/b&gt;&lt;span&gt; 관점으로 이해할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-27 오후 8.24.51.png&quot; data-origin-width=&quot;1326&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VVU6s/dJMcab0gkFl/OPj86O4aznsAyV47dOIO8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VVU6s/dJMcab0gkFl/OPj86O4aznsAyV47dOIO8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VVU6s/dJMcab0gkFl/OPj86O4aznsAyV47dOIO8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVVU6s%2FdJMcab0gkFl%2FOPj86O4aznsAyV47dOIO8k%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;682&quot; height=&quot;276&quot; data-filename=&quot;스크린샷 2026-09-27 오후 8.24.51.png&quot; data-origin-width=&quot;1326&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 순차적으로 데이터를 읽는 작업에서 ArrayList가 유리한 경우가 많다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 단점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;중간 삽입/삭제가 많은 경우에는 데이터 이동 비용이 발생&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또 capacity가 실제 size보다 클 수 있기 때문에 사용하지 않는 공간이 생길 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;size = 3

capacity = 10

[A][B][C][ ][ ][ ][ ][ ][ ][ ]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;즉 여분의 메모리를 확보해두고 사용&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 &lt;b&gt;매번 정확한 크기의 배열을 만드는 것보다 이런 방식이 반복적인 &lt;/b&gt;&lt;/span&gt;&lt;b&gt;add()&lt;/b&gt;&lt;span&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;size18&quot;&gt;&lt;b&gt;&lt;span&gt;  ArrayList vs 일반 배열&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;배열&lt;/td&gt;
&lt;td&gt;&amp;nbsp;ArrayList&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;크기 고정&lt;/td&gt;
&lt;td&gt;크기 동적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;primitive 저장 가능&lt;/td&gt;
&lt;td&gt;Generic은 객체 타입&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;낮은 수준의 구조&lt;/td&gt;
&lt;td&gt;여러 편의 메서드 제공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;arr[index]&lt;/td&gt;
&lt;td&gt;list.get(index)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 배열은:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int[] numbers = new int[10];&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;primitive인 &lt;/span&gt;int&lt;span&gt;를 바로 저장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; numbers = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;에서는 &lt;/span&gt;Integer&lt;span&gt; 객체 타입을 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오토박싱도 발생할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;numbers.add(10);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개념적으로:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;numbers.add(Integer.valueOf(10));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;와 비슷하다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>자료구조</category>
      <author>KongJiHoon</author>
      <guid isPermaLink="true">https://kjhs-97.tistory.com/335</guid>
      <comments>https://kjhs-97.tistory.com/335#entry335comment</comments>
      <pubDate>Sun, 27 Sep 2026 20:27:55 +0900</pubDate>
    </item>
    <item>
      <title>Collection Framework</title>
      <link>https://kjhs-97.tistory.com/334</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 7.32.20.png&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sQkkc/dJMcahlRESc/B60QInekhYdNWM79LK3tn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sQkkc/dJMcahlRESc/B60QInekhYdNWM79LK3tn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sQkkc/dJMcahlRESc/B60QInekhYdNWM79LK3tn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsQkkc%2FdJMcahlRESc%2FB60QInekhYdNWM79LK3tn1%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;811&quot; height=&quot;283&quot; data-filename=&quot;스크린샷 2026-09-26 오후 7.32.20.png&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;460&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;1️⃣ Collection Framework&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Java에서 여러 데이터를 저장하고 조작하기 위한 자료구조와 관련 인터페이스의 집합&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;예를 들면&lt;/p&gt;
&lt;pre id=&quot;code_1790418826972&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;User&amp;gt; users = new ArrayList&amp;lt;&amp;gt;();
Set&amp;lt;Long&amp;gt; ids = new HashSet&amp;lt;&amp;gt;();
Map&amp;lt;Long, User&amp;gt; userMap = new HashMap&amp;lt;&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;배열만 사용하면 데이터 추가, 삭제, 검색 등을 직접 구현해야 하는데 Collection Framework가 이를 표준화하여 제공한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Collection Framework는 여러 데이터를 효율적으로 저장하고 조회, 추가, 삭제할 수 있도록 Java에서 제공하는 자료구조 관련 인터페이스와 구현체의 집합입니다. 대표적으로 List, Set, Queue, Map 등이 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) Collection과 Map의 차이&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List, Set, Queue는&lt;/p&gt;
&lt;pre id=&quot;code_1790418930774&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Collection&amp;lt;E&amp;gt;&lt;/code&gt;&lt;/pre&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;b&gt; Map&amp;lt;K, V&amp;gt;은 Collection을 상속하지 않는다&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 7.36.02.png&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnhF8y/dJMcab6VolI/XurS1nXinsqAMDavurhLLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnhF8y/dJMcab6VolI/XurS1nXinsqAMDavurhLLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnhF8y/dJMcab6VolI/XurS1nXinsqAMDavurhLLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnhF8y%2FdJMcab6VolI%2FXurS1nXinsqAMDavurhLLK%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;697&quot; height=&quot;432&quot; data-filename=&quot;스크린샷 2026-09-26 오후 7.36.02.png&quot; data-origin-width=&quot;974&quot; data-origin-height=&quot;604&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;왜냐하면 &lt;b&gt;Collection은 기본적으로 하나의 값 요소를 다루지만 Map은 key, value 두 개의 값을 다루기 때문&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2️⃣ List&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List의 특징은 다음과 같다.&lt;/p&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;/li&gt;
&lt;li&gt;index 접근 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;pre id=&quot;code_1790419105682&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; list = new ArrayList&amp;lt;&amp;gt;();

list.add(&quot;A&quot;);
list.add(&quot;B&quot;);
list.add(&quot;A&quot;);


위와 값이 값이 저장되면

0 -&amp;gt; A
1 -&amp;gt; B
2 -&amp;gt; A&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;중복값이 허용되고 순서가 존재한다.&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;대표적인 구현체로는 ArrayList와 LinkedList&lt;/b&gt;가 존재한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) ArrayList&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 가장 많이 사용되는 List 구현체 중 하나이다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 7.39.36.png&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bijqst/dJMcafBtxe1/sJdlWuxXMGWIc0nrWmGkUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bijqst/dJMcafBtxe1/sJdlWuxXMGWIc0nrWmGkUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bijqst/dJMcafBtxe1/sJdlWuxXMGWIc0nrWmGkUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbijqst%2FdJMcafBtxe1%2FsJdlWuxXMGWIc0nrWmGkUk%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;774&quot; height=&quot;189&quot; data-filename=&quot;스크린샷 2026-09-26 오후 7.39.36.png&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;314&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;배열 기반이기 때문에 list.get(3);&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;size18&quot;&gt;&lt;b&gt;  시간 복잡도&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;작업&lt;/td&gt;
&lt;td&gt;평균적인 복잡도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;index 조회&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;마지막 추가&lt;/td&gt;
&lt;td&gt;amortized O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;중간 삽입&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;중간 삭제&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;값 검색&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;b&gt;ArrayList 중간 삽입/삭제가 O(n)인 이유&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;예를 들어&lt;/p&gt;
&lt;pre id=&quot;code_1790419337462&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{A, B, C, D}

이 때 index 1에 X를 넣으면

{A, X, B, C, D}&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;기존 요소를 뒤로 옮겨야 한다. 그래서 데이터가 많으면 이동 비용이 발생한다.&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;b&gt;ArrayList의 크기 변화&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;ArrayList는 내부적으로 배열을 사용하지만 크기가 고정되어 있지 않다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 7.43.57.png&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;972&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC0Uxx/dJMcaamudlJ/ajMi56EV22PBPQyOlEKE71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC0Uxx/dJMcaamudlJ/ajMi56EV22PBPQyOlEKE71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC0Uxx/dJMcaamudlJ/ajMi56EV22PBPQyOlEKE71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC0Uxx%2FdJMcaamudlJ%2FajMi56EV22PBPQyOlEKE71%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;483&quot; height=&quot;686&quot; data-filename=&quot;스크린샷 2026-09-26 오후 7.43.57.png&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;972&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 &lt;/span&gt;add()&lt;span&gt;가 항상 정확히 O(1)은 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;배열 확장이 발생하는 순간에는 복사 비용이 O(n)이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 여러 삽입을 평균내면:&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;amortized O(1)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) LinkedList&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LinkedList는 노드들이 서로 연결된 구조&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 7.45.29.png&quot; data-origin-width=&quot;1284&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Eg0mg/dJMcab0fT61/rkQJTKtgtDr6oTHYOI6HHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Eg0mg/dJMcab0fT61/rkQJTKtgtDr6oTHYOI6HHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Eg0mg/dJMcab0fT61/rkQJTKtgtDr6oTHYOI6HHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEg0mg%2FdJMcab0fT61%2FrkQJTKtgtDr6oTHYOI6HHK%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;739&quot; height=&quot;176&quot; data-filename=&quot;스크린샷 2026-09-26 오후 7.45.29.png&quot; data-origin-width=&quot;1284&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 LinkedList는 Doubley Linked List기반이다. -&amp;gt; 양쪽으로 연결된 구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각 노드는:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;이전 노드
현재 값
다음 노드&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;size18&quot;&gt;&lt;b&gt;&lt;span&gt;1) LinkedList의 조회&lt;/span&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;&lt;span&gt;예를 들어:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;list.get(100);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;LinkedList는 배열처럼:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;100번째 위치로 바로 이동&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;할 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;노드를 따라 이동해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;Node0
 &amp;darr;
Node1
 &amp;darr;
Node2
 &amp;darr;
...
 &amp;darr;
Node100&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 일반적인 index 조회는:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;O(n)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;&amp;nbsp;ArrayList&lt;/td&gt;
&lt;td&gt;LinkedList&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;내부 구조&lt;/td&gt;
&lt;td&gt;배열&lt;/td&gt;
&lt;td&gt;연결 리스트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;index 조회&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;마지막 추가&lt;/td&gt;
&lt;td&gt;평균 O(1)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;중간 삽입/삭제&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;탐색 후 O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;메모리&lt;/td&gt;
&lt;td&gt;상대적으로 적음&lt;/td&gt;
&lt;td&gt;노드 포인터 추가 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;캐시 친화성&lt;/td&gt;
&lt;td&gt;좋음&lt;/td&gt;
&lt;td&gt;상대적으로 떨어짐&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 중요한 부분:&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;LinkedList는 삽입/삭제가 무조건 O(1)이다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;라고 하면 틀릴 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;삽입할 위치를 찾는 과정에서 O(n)이 필요할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정확히는:&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이미 해당 노드의 위치를 알고 있다면 연결 변경은 O(1)이지만, index로 위치를 찾아야 한다면 탐색 비용 O(n)이 추가된다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&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;  ArrayList가 더 자주 쓰이는 이유&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일반적으로는 ArrayList가 더 많이 쓰인다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이유는:&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&gt;조회가 빠름&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;연속된 메모리 구조로 CPU cache에 유리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;대부분의 서비스에서는 중간 삽입보다 순회/조회가 많음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;LinkedList는 각 Node마다 추가 메모리가 필요&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;List&amp;lt;User&amp;gt; users = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 기본 선택으로 생각하고, 특별한 이유가 있을 때 다른 자료구조를 고르는 방식이 보통 적절하다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3️⃣ Set&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Set은 중복을 허용하지 않는 Collection&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1790421258439&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set&amp;lt;Long&amp;gt; ids = new HashSet&amp;lt;&amp;gt;();

ids.add(1L);
ids.add(2L);
ids.add(1L);

결과
1, 2만 저장된다.&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;중복된 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;대표적인 구현체로는 HashSet, LinkedHashSet, TreeSet이 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) HashSet&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HashSet은 내부적으로는 HashMap을 활용한다.&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;pre id=&quot;code_1790421333266&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashSet&amp;lt;String&amp;gt; set = new HashSet&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;에서&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;set.add(&quot;A&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;를 하면 내부적으로 키에 &lt;/span&gt;&quot;A&quot;&lt;span&gt;를 저장하는 형태로 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 &lt;b&gt;HashSet의 중복 판단에도 hashCode, equals가 중요&lt;/b&gt;하다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 8.16.12.png&quot; data-origin-width=&quot;1326&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgU0MU/dJMcahFZW6s/oDS0G5LAk6HdHisWiDHtlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgU0MU/dJMcahFZW6s/oDS0G5LAk6HdHisWiDHtlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgU0MU/dJMcahFZW6s/oDS0G5LAk6HdHisWiDHtlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgU0MU%2FdJMcahFZW6s%2FoDS0G5LAk6HdHisWiDHtlK%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;786&quot; height=&quot;181&quot; data-filename=&quot;스크린샷 2026-09-26 오후 8.16.12.png&quot; data-origin-width=&quot;1326&quot; data-origin-height=&quot;306&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) Set의 중복 판단&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;pre id=&quot;code_1790421439164&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;User user1 = new User(1L);
User user2 = new User(1L);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 논리적으로 같은 사용자라고 정의했다면&lt;/p&gt;
&lt;pre id=&quot;code_1790421480307&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;user1.equals(user2); // true

user1.hashCode() == user2.hashCode(); // true&lt;/code&gt;&lt;/pre&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;Set도 같은 원리로 동작한다.&lt;/p&gt;
&lt;pre id=&quot;code_1790421523456&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set&amp;lt;User&amp;gt; users = new HashSet&amp;lt;&amp;gt;();

users.add(user1);
users.add(user2);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우에 두 객체가 논리적으로 같은 값이라면&lt;/p&gt;
&lt;pre id=&quot;code_1790421550959&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;equals/ hashCode -&amp;gt; HashSet -&amp;gt; 중복 판단&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과정을 거쳐 하나의 객체만 저장된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) TreeSet&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TreeSet은 이름 그대로 Tree 기반이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서는 일반적으로 Red-Black Tree 기반으로 구현되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특징:&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&gt;중복 허용 X&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;정렬된 상태 유지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;탐색/삽입/삭제 O(log n)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;Set&amp;lt;Integer&amp;gt; numbers = new TreeSet&amp;lt;&amp;gt;();

numbers.add(5);
numbers.add(1);
numbers.add(3);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;순회하면:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1
3
5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;처럼 정렬된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4️⃣ Queue&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Queue는 기본적으로 FIFO 구조의 자료구조이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 8.21.07.png&quot; data-origin-width=&quot;1326&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJL4y1/dJMcadwH82z/HesEXNvF9lK8VrnHkkP4O0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJL4y1/dJMcadwH82z/HesEXNvF9lK8VrnHkkP4O0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJL4y1/dJMcadwH82z/HesEXNvF9lK8VrnHkkP4O0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJL4y1%2FdJMcadwH82z%2FHesEXNvF9lK8VrnHkkP4O0%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;773&quot; height=&quot;178&quot; data-filename=&quot;스크린샷 2026-09-26 오후 8.21.07.png&quot; data-origin-width=&quot;1326&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Queue&amp;lt;String&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();

queue.offer(&quot;A&quot;);
queue.offer(&quot;B&quot;);
queue.offer(&quot;C&quot;);

queue.poll(); // A&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) offer / poll / peek&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Queue에서 자주 사용하는 메서드다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;queue.offer(value);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;추가.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;queue.poll();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;꺼내면서 제거.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;queue.peek();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;BFS에서 자주 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS에서 &lt;b&gt;Queue를 사용하는 이유는 가까운 노드부터 순서대로 탐색하기 위해서다&lt;/b&gt;.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) PriorityQueue&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PriorityQueue는 FIFO 구조가 아니라 우선순위에 따라 데이터가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;보통 Heap 자료구조를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;();

pq.offer(5);
pq.offer(1);
pq.offer(3);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;poll()&lt;span&gt; 하면:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1
3
5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;순서로 나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;중요:&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;내부 배열 전체가 완전히 정렬돼 있다는 뜻은 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Heap의 규칙에 따라 &lt;/span&gt;&lt;b&gt;&lt;span&gt;우선순위가 가장 높은 값에 빠르게 접근할 수 있도록 구성&lt;/span&gt;&lt;/b&gt;&lt;span&gt;된 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;삽입/삭제:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;O(log n)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;최솟값 조회:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5️⃣ Map&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Map은:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Key &amp;rarr; Value&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;형태로 데이터를 저장한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Map&amp;lt;Long, User&amp;gt; users = new HashMap&amp;lt;&amp;gt;();

users.put(1L, user);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;조회:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;User user = users.get(1L);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특징:&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&gt;Key 중복 X&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Value 중복 O&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;1 &amp;rarr; Kim
2 &amp;rarr; Lee
3 &amp;rarr; Kim&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Value &lt;/span&gt;&quot;Kim&quot;&lt;span&gt;은 여러 개 존재할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) HashMap&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 8.24.21.png&quot; data-origin-width=&quot;1326&quot; data-origin-height=&quot;306&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GmM07/dJMcadp5nPR/zWIaUxMQbKMIWePS5WEUw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GmM07/dJMcadp5nPR/zWIaUxMQbKMIWePS5WEUw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GmM07/dJMcadp5nPR/zWIaUxMQbKMIWePS5WEUw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGmM07%2FdJMcadp5nPR%2FzWIaUxMQbKMIWePS5WEUw0%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;760&quot; height=&quot;175&quot; data-filename=&quot;스크린샷 2026-09-26 오후 8.24.21.png&quot; data-origin-width=&quot;1326&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;span&gt;일반적인 조회:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;map.get(key);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;평균 시간복잡도는:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;O(1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 항상 O(1)은 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;Hash Collision&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이 발생할 수 있기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이건 다음 단계에서:&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&gt;Bucket&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Hash Collision&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Linked List&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Red-Black Tree&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Load Factor&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Resize&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;까지 연결해서 깊게 볼 거다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6️⃣ ArrayDeque&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Stack이나 Queue가 필요하면 Java에서는 &lt;/span&gt;ArrayDeque&lt;span&gt;도 매우 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Deque&amp;lt;Integer&amp;gt; stack = new ArrayDeque&amp;lt;&amp;gt;();

stack.push(1);
stack.push(2);

stack.pop();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Stack처럼 사용할 수도 있고:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Deque&amp;lt;Integer&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();

queue.offer(1);
queue.offer(2);

queue.poll();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Queue로 사용할 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;과거에는:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Stack&amp;lt;Integer&amp;gt; stack = new Stack&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;을 많이 사용했지만 &lt;/span&gt;Stack&lt;span&gt;은 오래된 클래스이며 &lt;/span&gt;Vector&lt;span&gt;를 상속하고 있기 때문에 일반적으로는 &lt;/span&gt;Deque&lt;span&gt; 사용을 권장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>KongJiHoon</author>
      <guid isPermaLink="true">https://kjhs-97.tistory.com/334</guid>
      <comments>https://kjhs-97.tistory.com/334#entry334comment</comments>
      <pubDate>Sat, 26 Sep 2026 20:25:35 +0900</pubDate>
    </item>
    <item>
      <title>String / equals / hashCode</title>
      <link>https://kjhs-97.tistory.com/333</link>
      <description>&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-filename=&quot;스크린샷 2026-09-26 오후 2.44.05.png&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;1102&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z9bcY/dJMcacLDHN2/iRmSN80mvNkr5OIcVJH401/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z9bcY/dJMcacLDHN2/iRmSN80mvNkr5OIcVJH401/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z9bcY/dJMcacLDHN2/iRmSN80mvNkr5OIcVJH401/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz9bcY%2FdJMcacLDHN2%2FiRmSN80mvNkr5OIcVJH401%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;695&quot; height=&quot;475&quot; data-filename=&quot;스크린샷 2026-09-26 오후 2.44.05.png&quot; data-origin-width=&quot;1612&quot; data-origin-height=&quot;1102&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;1️⃣ String&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String은 문자열을 표현하는 Java 클래스이다.&lt;/p&gt;
&lt;pre id=&quot;code_1790401674707&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String name = &quot;Jihoon&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;size16&quot;&gt;중요한 특징은 &lt;b&gt;String은 불변 객체(Immutable Object)&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;예를 들어,&lt;/p&gt;
&lt;pre id=&quot;code_1790401725041&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str = &quot;hello&quot;;
str = str + &quot; world&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;size16&quot;&gt;겉으로는 기존 문자열이 수정된 것처럼 보이지만 실제로는 새로운 String 객체가 생성되고, str이 새로운 객체를 참조하게 된다.&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;(1) String이 불변 객체인 이유&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 이유는&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;String Pool 활용&lt;/li&gt;
&lt;li&gt;Thread Safety&lt;/li&gt;
&lt;li&gt;Hash 값의 안정성&lt;/li&gt;
&lt;li&gt;보안&lt;/li&gt;
&lt;li&gt;캐싱 가능&lt;/li&gt;
&lt;/ul&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;특히 HashMap과 연결된다.&lt;/p&gt;
&lt;pre id=&quot;code_1790401830979&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Map&amp;lt;String, User&amp;gt; map = new HashMap&amp;lt;&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;만약 String이 변경이 가능하다면&lt;/p&gt;
&lt;pre id=&quot;code_1790402304617&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;key의 값 변경 -&amp;gt; hashCode 변경 -&amp;gt; 기존 Bucket과 불일치 -&amp;gt; 데이터를 못 찾을 가능성&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 생길 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String이 불변이기 때문에 key로 사용하기 좋다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) String Pool&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서 문자열 리터럴을 효율적으로 재사용하기 위해 String Pool을 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1790402675884&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String a = &quot;hello&quot;;
String b = &quot;hello&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;size16&quot;&gt;이 경우 보통 같은 String Pool 객체를 참조한다. 따라서&lt;/p&gt;
&lt;pre id=&quot;code_1790402697768&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a == b -&amp;gt; true&lt;/code&gt;&lt;/pre&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;b&gt;new String();은 다르다&lt;/b&gt;.&lt;/p&gt;
&lt;pre id=&quot;code_1790402737849&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String a = &quot;hello&quot;;
String b = new String(&quot;hello&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 구조는 개념적으로 new 생성자로 새로운 객체를 생성하기 때문에 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 3.06.04.png&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNA4XM/dJMcaiyhg0c/WM8PyOFksZWoMSJmi2UDf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNA4XM/dJMcaiyhg0c/WM8PyOFksZWoMSJmi2UDf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNA4XM/dJMcaiyhg0c/WM8PyOFksZWoMSJmi2UDf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNA4XM%2FdJMcaiyhg0c%2FWM8PyOFksZWoMSJmi2UDf1%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;694&quot; height=&quot;403&quot; data-filename=&quot;스크린샷 2026-09-26 오후 3.06.04.png&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;430&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;그래서&lt;/p&gt;
&lt;pre id=&quot;code_1790402784671&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a == b -&amp;gt; false&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;하지만&lt;/p&gt;
&lt;pre id=&quot;code_1790402798631&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a.equals(b);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;는 true다. 왜냐하면 두 비교 방법이 다르기 때문이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2️⃣ == vs equals()&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) == 동등 연산자&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동등 연산자는 &lt;b&gt;참조 타입에서 두 참조가 같은 객체를 가리키는지 비교하는 방식&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1790402863509&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;User a = new User(&quot;kim&quot;);
User b = new User(&quot;kim&quot;);

a == b; // false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 new 생성자로 객체를 생성하면 객체가 서로 다르기 때문에 false가 반환된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) equals()&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 &lt;b&gt;논리적인 동등성을 비교하기 위해 사용&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String에서는 문자열 내용이 같은지를 비교하도록 equals()가 이미 재정의되어 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1790402944509&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String a = new String(&quot;hello&quot;);
String b = new String(&quot;hello&quot;);

a.equals(b); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;한 문장으로&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;==&lt;span&gt;는 참조값을 비교하고, &lt;/span&gt;equals()&lt;span&gt;는 객체의 논리적 동등성을 비교한다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3️⃣ Object.equals()&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Object는 &lt;b&gt;모든 Java 클래스의 최상위 부모 객체&lt;/b&gt;이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 3.18.53.png&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYFCu5/dJMcagf1XU9/8GcJ7HelrItAI8WrcalAQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYFCu5/dJMcagf1XU9/8GcJ7HelrItAI8WrcalAQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYFCu5/dJMcagf1XU9/8GcJ7HelrItAI8WrcalAQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYFCu5%2FdJMcagf1XU9%2F8GcJ7HelrItAI8WrcalAQ0%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;706&quot; height=&quot;338&quot; data-filename=&quot;스크린샷 2026-09-26 오후 3.18.53.png&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;430&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;Object에는&lt;/p&gt;
&lt;pre id=&quot;code_1790403559932&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public boolean equals(Object obj)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메서드가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 &lt;b&gt;기본 Object.equals()는 사실상 동일 객체인지 비교하는 방식&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;그래서 직접 만든 클래스에서&lt;/p&gt;
&lt;pre id=&quot;code_1790403595548&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;User user1 = new User(1L, &quot;kim&quot;);
User user2 = new User(1L, &quot;kim&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;두 객체를 논리적으로 같은 사용자로 판단하고 싶다면 equals()를 재정의&lt;/b&gt; 해야한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) equals() 재정의&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;pre id=&quot;code_1790403864942&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class User {

    private Long id;

    @Override
    public boolean equals(Object o) {

        if (this == o) {
            return true;
        }

        if (!(o instanceof User user)) {
            return false;
        }

        return Objects.equals(id, user.id);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는를 하나씩 봐보면&lt;/p&gt;
&lt;pre id=&quot;code_1790403986131&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;this == o -&amp;gt; 같은 메모리상의 객체를 가리키는지 확인한다.

instanceof User -&amp;gt; 비교대상이 같은 객체가 아니라면 사용할 수 없다고 판다.

Object.equals(this.id, user.id) -&amp;gt; id값이 같은지를 비교&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;위와 같은 재정의를 통해 논리적인 기준으로 비교할 수 있게된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) hashCode()&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;hashCode()는 객체를 나타내는 정수형 해시 값을 반환&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;대표적으로:&lt;/p&gt;
&lt;pre id=&quot;code_1790404043005&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HashMap
HashSet&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;같은 자료구조에서 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 HashMap은 대략:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 3.27.37.png&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/laFQU/dJMcaikGuR6/SaHdYF201mNngFhZCRgtuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/laFQU/dJMcaikGuR6/SaHdYF201mNngFhZCRgtuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/laFQU/dJMcaikGuR6/SaHdYF201mNngFhZCRgtuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlaFQU%2FdJMcaikGuR6%2FSaHdYF201mNngFhZCRgtuk%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;741&quot; height=&quot;242&quot; data-filename=&quot;스크린샷 2026-09-26 오후 3.27.37.png&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 순서로 key를 찾는다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) equals와 hashCode의 계약&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 규약상 &lt;b&gt;eqauls()가 true인 두 객체는 반드시 같은 hashCode를 가져야한다&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;즉&lt;/p&gt;
&lt;pre id=&quot;code_1790407419102&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a.equals(b) == true 라면
a.hashCode() == b.hashCode()&lt;/code&gt;&lt;/pre&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 data-ke-size=&quot;size16&quot;&gt;hashCode가 같다고해서 equals도 true인 것은 아니다.&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;이것이 바로 Hash Collision 가능성 때문이다.&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;  Hash Collision이란?&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;해시 충돌은 &lt;b&gt;서로 다른 개체인데도 hashCode() 결과가 같은 경우&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;예를 들어&lt;/p&gt;
&lt;pre id=&quot;code_1790407539386&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;User user1 = new User(1L, &quot;Kim&quot;);
User user2 = new User(2L, &quot;Lee&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;size16&quot;&gt;두 객체는 서로 다른 객체인데 우연히&lt;/p&gt;
&lt;pre id=&quot;code_1790407551177&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;user1.hashCode() == 12345
user2.hashCode() == 12345&lt;/code&gt;&lt;/pre&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;b&gt;hashCode가 같다고 해서 equals까지 같은 것은 아니다&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;예를 들어 HashSet에 다음과 같은 객체를 넣는다고 가정해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1790407615033&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set&amp;lt;User&amp;gt; users = new HashSet&amp;lt;&amp;gt;();

users.add(user1);
users.add(user2);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 두 객체의&lt;b&gt; hashCode()가 같다면 둘 다 같은 버킷 후보&lt;/b&gt;로 들어간다. &lt;b&gt;그런데 거기서 끝나는 것이 아니라 equals()를 다시 확인&lt;/b&gt;한다.&lt;/p&gt;
&lt;pre id=&quot;code_1790407680473&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;user1.hashCode() == user2.hashCode() // true
user1.equals(user2); // false&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;이 경우 &lt;b&gt;HashSet은 해시값은 같지만 다른 객체로 간주&lt;/b&gt;한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(4) 둘을 같이 재정의해야 되는 이유&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;User user1 = new User(1L);
User user2 = new User(1L);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;equals()&lt;span&gt;만 재정의해서:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;user1.equals(user2); // true&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&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&gt;그런데 hashCode()가 서로 다르면&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 4.29.07.png&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCpFVf/dJMcajcKbHt/y9KVVxOsKkkuFIvwFjNms0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCpFVf/dJMcajcKbHt/y9KVVxOsKkkuFIvwFjNms0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCpFVf/dJMcajcKbHt/y9KVVxOsKkkuFIvwFjNms0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCpFVf%2FdJMcajcKbHt%2Fy9KVVxOsKkkuFIvwFjNms0%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;692&quot; height=&quot;300&quot; data-filename=&quot;스크린샷 2026-09-26 오후 4.29.07.png&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;572&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;HashSet에서는 서로 다른 위치로 들어갈 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1790407766645&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Set&amp;lt;User&amp;gt; users = new HashSet&amp;lt;&amp;gt;();

users.add(user1);
users.add(user2);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&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;따라서 &lt;b&gt;equals()를 재정의하면 hashCode()도 같은 기준으로 재정의해야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4️⃣ StringBuilder와 StringBuffer&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String은 &lt;b&gt;불변 객체라서 반복적으로 문자열을 변경하면 객체가 계속 생성되어 메모리가 낭비&lt;/b&gt;될 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1790407923016&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String result = &quot;&quot;;

for (int i = 0; i &amp;lt; 10000; i++) {
    result += i;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위와 같은 경우 수많은 String 객체가 생성될 수 있다.&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;이럴 때 사용하는 것이 StringBuilder와 StringBuffer이다.&lt;/p&gt;
&lt;pre id=&quot;code_1790407957831&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;StringBuilder sb = new StringBuilder();

for (int i = 0; i &amp;lt; 10000; i++) {
    sb.append(i);
}

String result = sb.toString();&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;둘 다 가변 문자열을 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;차이점은 Thread Safety 제공 여부&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;StringBuilder&lt;/td&gt;
&lt;td&gt;StringBuffer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;가변 객체&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thread Safe&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;synchronized&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일반적인 성능&lt;/td&gt;
&lt;td&gt;상대적으로 빠름&lt;/td&gt;
&lt;td&gt;상대적으로 느림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;일반적인 용도&lt;/td&gt;
&lt;td&gt;단일 스레드&lt;/td&gt;
&lt;td&gt;여러 스레드 공유&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 Local 문자열 조합에서는 StringBuilder를 주로 사용한다.&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;StringBuffer는 메서드에 동기화가 적용되어 있기 때문에 멀티 스레드 환경에서 공유할 경우 Thread Safety를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다만:&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;멀티스레드 애플리케이션이면 무조건 StringBuffer를 써야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;는 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;로컬 변수로 사용하는 StringBuilder라면 여러 요청 스레드가 같은 객체를 공유하지 않으므로 문제가 없다.&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;size18&quot;&gt;&lt;b&gt;&lt;span&gt;  Thread Safety란?&lt;/span&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;Thread Safty, 즉 스레드 안정성은 &lt;b&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;예를 들어 다음과 같은 코드가 있다고 해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1790408462997&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Counter {

    private int count = 0;

    public void increase() {
        count++;
    }
}&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;그리고 두 스레드가 동시에 increase()를 호출한다고 가정해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;겉으로 보면 count++ 한 줄이라 안전해 보이지만 실제로는 대략 다음과 같이 동작한다.&lt;/p&gt;
&lt;pre id=&quot;code_1790408515733&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1. count 값을 읽음
2. count + 1 계산
3. 결과를 count에 저장&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;만약 현재 count=0이고 두 스레드가 동시에 실행되면&lt;/p&gt;
&lt;pre id=&quot;code_1790408578143&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Thread A: count 읽음 -&amp;gt; 0
Thread B: count 읽음 -&amp;gt; 0

Thread A: 0 + 1 = 1
Thread B: 0 + 1 = 1

Thread A: count = 1
Thread B: count = 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;원래 기대값은:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인데 실제 결과는:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&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&gt;&lt;b&gt;이런 현상이 바로 프로젝트에서 경험한 Race Condition(&lt;/b&gt;경쟁 상태)이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-26 오후 4.43.38.png&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;1040&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kQIbr/dJMcacrjY67/TRSRZIBnguzu1KBKGo2ngK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kQIbr/dJMcacrjY67/TRSRZIBnguzu1KBKGo2ngK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kQIbr/dJMcacrjY67/TRSRZIBnguzu1KBKGo2ngK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkQIbr%2FdJMcacrjY67%2FTRSRZIBnguzu1KBKGo2ngK%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;652&quot; height=&quot;514&quot; data-filename=&quot;스크린샷 2026-09-26 오후 4.43.38.png&quot; data-origin-width=&quot;1318&quot; data-origin-height=&quot;1040&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;그래서 이 코드는 Thread Safe하지 않다고 표현한다.&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;pre id=&quot;code_1790408651831&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Counter {

    private int count = 0;

    public synchronized void increase() {
        count++;
    }
}&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;synchronized를 사용하면 한 순간에 한 스레드만 접근하도록 제한할 수 있다.&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;autohotkey&quot;&gt;&lt;code&gt;Thread A &amp;rarr; increase() 실행
Thread B &amp;rarr; 대기

Thread A 종료
Thread B &amp;rarr; increase() 실행&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결과적으로:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;0 &amp;rarr; 1 &amp;rarr; 2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thread Safety를 이해할 때 중요한 건 공유 상태(shared mutable state)다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 보통 다음과 같은 조건에서 발생한다.&lt;/p&gt;
&lt;pre id=&quot;code_1790410034976&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;여러 스레드 -&amp;gt; 같은 데이터 접근 -&amp;gt; 그 데이터를 변경 -&amp;gt; 동시에 실행 -&amp;gt; Race Condition 가능&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;반면, 공유되는 변경 가능한 상태가 없다면 Thread Safety를 확보하기 쉽다.&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;pre id=&quot;code_1790410063591&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int add(int a, int b) {
    return a + b;
}&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;&lt;b&gt;이 메서드는 지역 변수와 매게 변수만 사용&lt;/b&gt;한다&lt;b&gt;. 각 스레드의 스택에 따로 저장되기 때문에 여러 스레드가 동시 접근해도 서로 영향을 주지 않는다&lt;/b&gt;.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Thread Safety란 여러 스레드가 동시에 동일한 자원에 접근하더라도 데이터의 일관성과 프로그램의 정상적인 동작이 보장되는 것을 의미합니다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;공유되는 변경 가능한 상태가 있을 경우 Race Condition이 발생할 수 있으며, 이를 방지하기 위해 synchronized, Lock, Atomic 클래스, ConcurrentHashMap 등을 사용할 수 있습니다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;또한 Spring의 Singleton Bean처럼 여러 요청 스레드가 하나의 객체를 공유하는 환경에서는 상태를 필드에 저장하지 않고 지역 변수 중심으로 설계하는 것도 중요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&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>Java</category>
      <author>KongJiHoon</author>
      <guid isPermaLink="true">https://kjhs-97.tistory.com/333</guid>
      <comments>https://kjhs-97.tistory.com/333#entry333comment</comments>
      <pubDate>Sat, 26 Sep 2026 17:09:53 +0900</pubDate>
    </item>
    <item>
      <title>객체 지향 프로그래밍</title>
      <link>https://kjhs-97.tistory.com/332</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1️⃣ 객체 지향 프로그래밍&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 지향 프로그래밍(Objecy-Oriented Programming)은 프로그램을 단순한 명령어의 집합으로 보기보다는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&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;예를 들어, 농구 매칭 서비스를 절차적으로 생각하면&lt;/p&gt;
&lt;pre id=&quot;code_1790364320524&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;사용자 조회
-&amp;gt; 경기 조회
-&amp;gt; 참가 가능한지 검사
-&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;객체지향적으로 보면 각각의 객체가 자신의 책임을 가진다.&lt;/p&gt;
&lt;pre id=&quot;code_1790364341795&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Game {

    private int headCount;
    private int participantCount;

    public void join() {
        if (participantCount &amp;gt;= headCount) {
            throw new IllegalStateException(&quot;모집이 완료되었습니다.&quot;);
        }

        participantCount++;
    }
}&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;이 경우 Game도메인이 자신의 상태인 participantCount를 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;핵심은:&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;객체가 자신의 상태와 행동을 함께 가지고, 다른 객체와 메시지를 주고받으며 프로그램을 구성한다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&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;blockquote data-ke-style=&quot;style2&quot;&gt;객체지향 프로그래밍은 프로그램을 상태와 행동을 가진 객체들의 협력으로 구성하는 프로그래밍 방식입니다. 각 객체에 책임을 분배하고 객체 간의 의존성을 적절하게 관리함으로써 변경에 유연하고 유지보수하기 좋은 코드를 만드는 것을 목표로 합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 클래스와 객체의 차이&lt;/h4&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;pre id=&quot;code_1790364462423&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class User {

    private String name;

    public User(String name) {
        this.name = name;
    }
}&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;그리고&lt;/p&gt;
&lt;pre id=&quot;code_1790364474317&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;User user1 = new User(&quot;지훈&quot;);
User user2 = new User(&quot;철수&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;size16&quot;&gt;User는 클래스이고, new 생성자에 의해 호출되는 것이 바로 객체이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user1, user2는 각각 별도의 객체이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2️⃣ 객체지향의 4가지 특징&lt;/h3&gt;
&lt;pre id=&quot;code_1790364529790&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;객체지향 4대 특징

캡슐화
추상화
상속
다형성&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 캡슐화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캡슐화는 &lt;b&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;나쁜 예&lt;/p&gt;
&lt;pre id=&quot;code_1790364675489&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Game {

    public int participantCount;
}&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;위와 같이 public 접근제어자로 변수를 생성 시에 외부에서 아래와 같이&lt;/p&gt;
&lt;pre id=&quot;code_1790364697887&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;game.participantCount = -100;&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;변경이 가능하여 객체의 상태가 깨진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public class Game {

    private int participantCount;

    public void join() {

        if (participantCount &amp;gt;= 10) {
            throw new IllegalStateException();
        }

        participantCount++;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;외부에서는&amp;nbsp; game.join()만 호출한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1790364738084&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;외부

game.join()
    &amp;darr;
┌──────────────────────┐
│ Game                 │
│                      │
│ participantCount     │
│     &amp;darr;                │
│ validate &amp;rarr; 증가      │
└──────────────────────┘&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;객체 내부의 구체적인 처리 방법은 외부에서 알 필요가 없다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;캡슐화는 &lt;b&gt;객체의 상태와 행동을 하나로 묶고 내부 구현을 외부로부터 숨기는 것&lt;/b&gt;입니다. 단순히 필드를 private으로 만드는 것뿐 아니라, 객체의 상태를 외부에서 직접 변경하지 못하게 하고 의미 있는 메서드를 통해 상태를 변경하도록 만들어 객체의 무결성을 유지하는 것이 중요하다고 생각합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 추상화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상화는 &lt;b&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;예를 들어 자동차를 운전한다고 생각하면&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;pre id=&quot;code_1790364894572&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;엔진 연료 분사, 점화 타이밍, 변속기 내부 구조&lt;/code&gt;&lt;/pre&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;Java 코드로 보면&lt;/p&gt;
&lt;pre id=&quot;code_1790364919269&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Payment {

    void pay(int amount);
}&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;
&lt;pre id=&quot;code_1790364948377&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;payment.pay(10000);&lt;/code&gt;&lt;/pre&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;pre id=&quot;code_1790364972198&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;카드사 API 호출 -&amp;gt; 인증 -&amp;gt; 승인 -&amp;gt; 결제 기록&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;&lt;span&gt;캡슐화와 추상화 차이&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;헷갈리기 쉽다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;캡슐화
&amp;rarr; 내부 상태와 구현을 보호

추상화
&amp;rarr; 필요한 핵심만 외부에 노출&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;둘은 서로 관련 있지만 같은 개념은 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) 상속&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속은 &lt;b&gt;부모 클래스의 특성과 기능을 자식 클래스가 물려받아 사용할 수 있도록 하는 특징&lt;/b&gt;입니다.&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Animal {

    public void eat() {
        System.out.println(&quot;먹는다&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Dog extends Animal {

    public void bark() {
        System.out.println(&quot;멍멍&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그러면:&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1790365099782&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Dog dog = new Dog();

dog.eat();
dog.bark();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;구조는:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;inform7&quot;&gt;&lt;code&gt;        Animal
          &amp;uarr;
          │
         Dog&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이것을 &lt;/span&gt;&lt;b&gt;&lt;span&gt;IS-A 관계&lt;/span&gt;&lt;/b&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;size18&quot;&gt;&lt;b&gt;&lt;span&gt;‼️ 상속의 문제점&lt;/span&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;&lt;span&gt;상속에는 강한 결합이라는 문제가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class Parent {

    protected void calculate() {
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;자식:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Child extends Parent {

    public void execute() {
        calculate();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;부모의 구현이 변경되면 자식 클래스의 동작까지 영향을 받을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1790365483895&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Parent 변경 -&amp;gt; Child 영향 -&amp;gt; GrandChild 영향&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;계층이 깊어질수록 유지보수가 어려워질 수 있다는 단점이 있다.&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;b&gt;Composition(조합)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Composition은 &lt;b&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;예를들어, 아래와 같이 Engine 클래스가 존재하고 Car클래스는 Engine클래스를 필드로 가진다.&lt;/p&gt;
&lt;pre id=&quot;code_1790365571118&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Engine {

    public void start() {
        System.out.println(&quot;엔진 시작&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1790365606295&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Car {

    private final Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        engine.start();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;관계는:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;Car
 │
 └── has Engine&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;상속:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;IS-A&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;조합:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;dns&quot;&gt;&lt;code&gt;HAS-A&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;조합은 구현체를 쉽게 바꾸는 것도 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;Car car = new Car(new GasolineEngine());&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또는:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;Car car = new Car(new ElectricEngine());&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;이 구조가 Spring의 DI와 매우 가까워진다&lt;/b&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(4) 다형성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;다형성은 &lt;b&gt;같은 타입으로 여러 구현 객체를 사용할 수 있는 성질&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;interface Payment {

    void pay();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;구현체:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;class CardPayment implements Payment {

    @Override
    public void pay() {
        System.out.println(&quot;카드 결제&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;class KakaoPayment implements Payment {

    @Override
    public void pay() {
        System.out.println(&quot;카카오 결제&quot;);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;pre id=&quot;code_1790365720717&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Payment payment;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라는 하나의 타입으로&lt;/p&gt;
&lt;pre id=&quot;code_1790365743080&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;payment = new CartPayment();
payment = new KakaoPayment();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 구현 객체를 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1790365764293&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;             Payment

            pay()

          ↙       ↘

CardPayment       KakaoPayment&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;호출자는:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;payment.pay();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만 알면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;size18&quot;&gt;&lt;b&gt;&lt;span&gt;  다형성의 중요성&lt;/span&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;&lt;span&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;&lt;span&gt;예를 들어 다음과 같은 코드가 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1790365870976&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class OrderService {
	private CardPayment cardPayment;
}&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;OrderService가 CardPayment 객체에 직접 의존한다.&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;그러면 나중에 KakaoPayment로 변경하면 OrderService를 직접 수정해야 한다.&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;pre id=&quot;code_1790365958298&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class OrderService {

	private final Payment payment;
    
    public OrderService(Payment payment) {
    	this.payment = payment;
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 OrderService는 구현체 변경을 몰라도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이게 &lt;/span&gt;&lt;b&gt;&lt;span&gt;다형성 + 추상화 + DI&lt;/span&gt;&lt;/b&gt;&lt;span&gt;의 핵심이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1790365981527&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;OrderService
     &amp;darr;
 Payment
   ↙     ↘
Card   Kakao&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;  Spring과 다형성&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;예를 들어&lt;/p&gt;
&lt;pre id=&quot;code_1790366030412&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface NotificationService {

    void send(String message);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;구현체:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Service
public class EmailNotificationService
        implements NotificationService {

    @Override
    public void send(String message) {
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Service
@RequiredArgsConstructor
public class GameService {

    private final NotificationService notificationService;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GameService&lt;span&gt;가 &lt;b&gt;EmailNotificationService라는 구현체에 직접 의존하지 않고 NotificationService라는 추상화된 객체에 의존&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;&lt;span&gt;Spring Container가 구현체를 주입해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;객체지향 다형성
       &amp;darr;
Interface
       &amp;darr;
DI
       &amp;darr;
Spring IoC Container&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;Spring이 객체지향을 잘 활용한다고 생각하는 이유?&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Spring에서는 인터페이스를 기반으로 구현체를 분리하고, &lt;b&gt;IoC 컨테이너가 구현 객체를 주입해주는 DI 구조를 사용하기 쉽습니다&lt;/b&gt;. 따라서 &lt;b&gt;클라이언트 코드가 구체 구현보다 추상화에 의존하도록 만들 수 있고, 구현체 변경에 대한 영향을 줄일 수 있다는 점에서 객체지향의 다형성을 잘 활용할 수 있다고 생각&lt;/b&gt;합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;3️⃣ 오버로딩과 오버라이딩&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) Overloading&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오버로딩은 같은 클래스에서 메서드 이름은 같고 매게변수는 다르게 정의하는 것이다.&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public int add(int a, int b) {
    return a + b;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public int add(int a, int b, int c) {
    return a + b + c;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public double add(double a, double b) {
    return a + b;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;메서드 이름:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;add&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&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&gt;판단 기준은&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1790366295043&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;매개변수 개수
매개변수 타입
매개변수 순서&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&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&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&gt;Java 소스코드는 컴파일 시점에 타입을 검사하므로 컴파일러 입장에서 호출할 때,&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1790366355311&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;test();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 메서드인지 판단할 수 없기 떄문이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) Overriding&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오버라이딩은 &lt;b&gt;부모나 인터페이스에서 정의한 메서드를 자식 클래스에서 다시 구현하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;interface Payment {

    void pay();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;class CardPayment implements Payment {

    @Override
    public void pay() {
        System.out.println(&quot;카드 결제&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다형성과 직접 연결된다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;abnf&quot;&gt;&lt;code&gt;Payment payment = new CardPayment();

payment.pay();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;참조 타입은:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Payment&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이지만 실제 실행되는 것은:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;CardPayment.pay()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&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&gt;  오버로딩 vs 오버라이딩&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;Overloading&lt;/td&gt;
&lt;td&gt;Overriding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;위치&lt;/td&gt;
&lt;td&gt;같은 클래스 중심&lt;/td&gt;
&lt;td&gt;상속/인터페이스 관계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;메서드명&lt;/td&gt;
&lt;td&gt;동일&lt;/td&gt;
&lt;td&gt;동일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;매개변수&lt;/td&gt;
&lt;td&gt;달라야 함&lt;/td&gt;
&lt;td&gt;동일&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;목적&lt;/td&gt;
&lt;td&gt;같은 기능의 여러 형태&lt;/td&gt;
&lt;td&gt;부모 동작 재정의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;결정 시점&lt;/td&gt;
&lt;td&gt;주로 컴파일 타임&lt;/td&gt;
&lt;td&gt;런타임 다형성과 연결&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4️⃣ 추상 클래스와 인터페이스&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 추상 클래스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상 클래스는&lt;/p&gt;
&lt;pre id=&quot;code_1790366648565&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;abstract class Payment {

    protected String name;

    public void print() {
        System.out.println(name);
    }

    public abstract void pay();
}&lt;/code&gt;&lt;/pre&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;div&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class CardPayment extends Payment {

    @Override
    public void pay() {
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 직접 인스턴스를 만들 수는 없다.&lt;/p&gt;
&lt;pre id=&quot;code_1790366685916&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;new Payment(); // 불가능&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 인터페이스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는 &lt;b&gt;객체가 어떤 행동을 제공해야 하는지 계약을 정의하는 역할로 많이 사용한&lt;/b&gt;다.&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;interface Payment {

    void pay();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;구현:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class CardPayment implements Payment {
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Java에서는 여러 인터페이스를 구현할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class UserService
        implements UserReader, UserWriter {
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;반면 클래스 상속은 하나만 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Child extends Parent&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;인터페이스는 주로 객체가 제공해야 하는 역할이나 계약을 정의하고, 서로 다른 클래스에 동일한 추상화를 제공할 때 사용합니다.&lt;br /&gt;&lt;br /&gt;반면 추상 클래스는 상속 관계에 있는 클래스들이 공통 상태나 구현을 공유해야 할 때 사용할 수 있습니다.&lt;br /&gt;Java에서는 클래스는 하나만 상속할 수 있지만 여러 인터페이스를 구현할 수 있기 때문에, 구현체를 교체하거나 확장해야 하는 구조에서는 인터페이스를 주로 활용합니다.&lt;/blockquote&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;</description>
      <category>Java</category>
      <author>KongJiHoon</author>
      <guid isPermaLink="true">https://kjhs-97.tistory.com/332</guid>
      <comments>https://kjhs-97.tistory.com/332#entry332comment</comments>
      <pubDate>Sat, 26 Sep 2026 05:07:45 +0900</pubDate>
    </item>
    <item>
      <title>Java 컴파일 과정</title>
      <link>https://kjhs-97.tistory.com/331</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1️⃣ JDK/ JRE/ JVM의 차이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 큰 구조는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1790362077179&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JDK
├── 개발 도구
│   ├── javac
│   ├── javadoc
│   └── jar ...
│
└── Java 실행 환경
    ├── Java 표준 라이브러리
    └── JVM&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) JVM(Java Virtual Machine)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 바이트코드를 실제 실행시키는 가상 머신이다.&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;예를 들어 Jav 소스 코드를 컴파일 하면&lt;/p&gt;
&lt;pre id=&quot;code_1790362143078&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hello.java -&amp;gt; Hello.class&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.class파일에는 CPU가 바로 이해하는 기계어가 아닌 Java Bytecode가 들어 있다.&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;이걸 JVM이 실행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1790362200550&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hello.java -&amp;gt; Hello.class -&amp;gt; JVM -&amp;gt; Window/ Linux/ macOS&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;운영체제별 JVM은 서로 다르지만 &lt;b&gt;바이트코드로 변환되어 JVM에 의해 실행되므로 플랫폼 독립성이 높다.&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;&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;Bytecode 실행&lt;/li&gt;
&lt;li&gt;메모리 관리&lt;/li&gt;
&lt;li&gt;GC 수행&lt;/li&gt;
&lt;li&gt;클래스 로딩&lt;/li&gt;
&lt;li&gt;JIT 컴파일&lt;/li&gt;
&lt;li&gt;런타임 환경 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) JRE(Java Runtime Environment)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JRE는 말 그대로 Java 프로그램을 실행하기 위한 환경이다.&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;pre id=&quot;code_1790362346483&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JRE
├── JVM
└── Java Library&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;JVM만 있다고 Java 프로그램을 정상적으로 실행할 수 있는 것은 아니다.&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;pre id=&quot;code_1790362384018&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String
ArrayList
HashMap
LocalDateTime&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 Java 표준 라이브러리도 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 개념적으로&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;JVM + Java 실행에 필요한 라이브러리 = JRE&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;라고 이해하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) JDK(Java Development Kit)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDK는 &lt;b&gt;Java 프로그램을 개발하기 위한 도구의 모음&lt;/b&gt;이다.&lt;/p&gt;
&lt;pre id=&quot;code_1790362498600&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JDK
├── Java 실행 환경
│    ├── JVM
│    └── Java Library
│
└── 개발 도구
     ├── javac
     ├── jar
     ├── javadoc
     └── jdb 등&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;예를들어, IntelliJ에서 Java 17을 설정할 때 설치하는 것이 바로 JDK17이다.&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;pre id=&quot;code_1790362554882&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;javac -&amp;gt; Java Compiler&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;프로그램 실행 시 javac에 의해&lt;/p&gt;
&lt;pre id=&quot;code_1790362583332&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hello.java -&amp;gt; Hello.class&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 Bytecode로 변환된다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 74px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;span&gt;구분&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;span&gt;역할&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&lt;span&gt;주요 구성&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span&gt;JVM&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span&gt;Bytecode 실행&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span&gt;Class Loader, Execution Engine, Runtime Memory 등&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span&gt;JRE&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span&gt;Java 프로그램 실행 환경&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span&gt;JVM + 실행 라이브러리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span&gt;JDK&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span&gt;Java 프로그램 개발 환경&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;&lt;span&gt;실행 환경 + javac 등 개발 도구&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2️⃣ Java 컴파일 및 실행 과정&lt;/h3&gt;
&lt;pre id=&quot;code_1790362883821&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Java Source Code
      &amp;darr;
    javac
      &amp;darr;
Java Bytecode
   (.class)
      &amp;darr;
 Class Loader
      &amp;darr;
Bytecode Verification
      &amp;darr;
JVM Runtime Data Area
      &amp;darr;
Execution Engine
 ├─ Interpreter
 └─ JIT Compiler
      &amp;darr;
 Native Machine Code
      &amp;darr;
      CPU&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) Java Source Code 작성&lt;/h4&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;pre id=&quot;code_1790362948281&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pulic class Hello {

	public static void main(String[] args) {
    
    	System.out.println(&quot;Hello&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파일:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Hello.java&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) javac가 컴파일한다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDK의 &lt;b&gt;Java Compiler인 javac가 소스 코드를 컴파일&lt;/b&gt; 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1790363009172&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;javac Hello.java -&amp;gt; Hello.class&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;Java 소스 코드는 여기서 &lt;b&gt;바로 CPU 기계어로 변환되는 것이 아닌 Java Bytecode로 변환&lt;/b&gt;된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) JVM의 Class Loader가 .class를 로딩&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM이 실행되면 Class Loader가 필요한 .class 파일을 JVM메모리로 가져온다.&lt;/p&gt;
&lt;pre id=&quot;code_1790363108603&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hello.class -&amp;gt; Class Loader -&amp;gt; JVM&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(4) Bytecode 검증&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JVM에서는 로딩된 Bytecode가 안전한 지 검사한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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&gt;잘못된 Bytecode인지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;JVM 규칙을 위반하지 않는지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;타입이 올바른지&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;등을 검증한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(5) JVM Runtime Data 영역에 배치&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스에 객체, 메서드, 변수 실행 등에 필요한 데이터가 JVM 메모리 영역에서 관리된다.&lt;/p&gt;
&lt;pre id=&quot;code_1790363213947&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JVM Runtime Data Area

┌─────────────────────┐
│       Heap          │ &amp;larr; 객체
├─────────────────────┤
│  Method Area        │ &amp;larr; 클래스 관련 정보
├─────────────────────┤
│       Stack         │ &amp;larr; 메서드 호출 / 지역변수
├─────────────────────┤
│   PC Register       │
├─────────────────────┤
│ Native Method Stack │
└─────────────────────┘&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;  JVM이 &lt;b&gt;실행에 필요한 데이터를 여러 메모리 영역에 관리&lt;/b&gt;한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(6) Excuetion Engine이 Bytecode를 실행&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 JVM의 &lt;/span&gt;&lt;b&gt;&lt;span&gt;Execution Engine&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이 Bytecode를 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 중요한 두 개:&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Interpreter
JIT Compiler&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;Interpreter&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bytecode 명령을 읽어서 하나씩 실행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1790363343774&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Bytecode -&amp;gt; 한 줄씩 해석 -&amp;gt; 실행&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;장점:&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;바로 실행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;단점:&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;같은 코드를 반복 실행하면 계속 해석해야 한다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&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;JIT(Just In Time) Compiler&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;JVM이 프로그램을 실행하면서 &lt;b&gt;자주 실행되는 코드를 발견하면 해당 Bytecode를 네이티브 코드로 컴파일&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1790363428766&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Bytecode

    &amp;darr; 처음

Interpreter
    &amp;darr;
실행

    &amp;darr; 반복적으로 많이 실행됨

JIT Compiler
    &amp;darr;

Native Code
    &amp;darr;

CPU 직접 실행&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;예를 들어 서버에서 다음과 같은 코드를 수십만 번 실행한다고 가정해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1790363451117&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public GameResponse findGame(Long gameId)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 Bytecode를 하나씩 해석하는 것보다 &lt;b&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;정리&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Java 소스 코드는 JDK에 포함된 javac 컴파일러를 통해 JVM이 이해할 수 있는 Bytecode 형태의 .class 파일로 컴파일됩니다.&lt;br /&gt;이후 JVM의 Class Loader가 필요한 클래스를 로딩하고 Bytecode를 검증한 뒤 JVM의 Runtime Data Area에서 관리합니다.&lt;br /&gt;&lt;br /&gt;Execution Engine이 Bytecode를 실행하며, 처음에는 인터프리터 방식으로 실행할 수 있고 반복적으로 실행되는 코드는 JIT Compiler가 네이티브 코드로 컴파일하여 성능을 최적화합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java</category>
      <author>KongJiHoon</author>
      <guid isPermaLink="true">https://kjhs-97.tistory.com/331</guid>
      <comments>https://kjhs-97.tistory.com/331#entry331comment</comments>
      <pubDate>Sat, 26 Sep 2026 04:12:52 +0900</pubDate>
    </item>
    <item>
      <title>이진 탐색 트리(1)</title>
      <link>https://kjhs-97.tistory.com/329</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1️⃣ 이진 탐색 트리(Binary Search Tree)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진 탐색 트리(BST)는 데이터를 빠르게 탐색하기 위해 일정한 규칙에 따라 노드를 배치한 이진 트리이다.&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;일반적인 이진 트리는 단순히 &quot;하나의 노드가 최대 2개의 자식을 가진다&quot;는 조건만 만족한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;595&quot; data-start=&quot;579&quot;&gt;부모보다 작은 값 &amp;rarr; 왼쪽&lt;/li&gt;
&lt;li data-end=&quot;612&quot; data-start=&quot;596&quot;&gt;부모보다 큰 값 &amp;rarr; 오른쪽&lt;/li&gt;
&lt;li data-end=&quot;641&quot; data-start=&quot;613&quot;&gt;왼쪽과 오른쪽의 서브 트리도 동일한 규칙을 만족&lt;/li&gt;
&lt;li data-end=&quot;660&quot; data-start=&quot;642&quot;&gt;중복된 Key는 허용하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 다음 값을 순서대로 삽입한다고 생각해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1789209196110&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;20 &amp;rarr; 10 &amp;rarr; 30 &amp;rarr; 1 &amp;rarr; 15 &amp;rarr; 25&lt;/code&gt;&lt;/pre&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-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.33.29.png&quot; data-origin-width=&quot;806&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rqYGw/dJMcacxM4Nm/TG9KUl4MkmCj85RgWF2v50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rqYGw/dJMcacxM4Nm/TG9KUl4MkmCj85RgWF2v50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rqYGw/dJMcacxM4Nm/TG9KUl4MkmCj85RgWF2v50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrqYGw%2FdJMcacxM4Nm%2FTG9KUl4MkmCj85RgWF2v50%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;602&quot; height=&quot;427&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.33.29.png&quot; data-origin-width=&quot;806&quot; data-origin-height=&quot;572&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;20을 기준으로 보면 왼쪽에는 20보다 작은 값이 존재하고, 오른쪽에는 20보다 큰 값이 존재한다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 탐색이 빠른 이유&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 적인 트리에서 25라는 값이 어디 있는지 모른다면 여러 노드를 직접 확인해야 할 수 있다.&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;하지만 BST에서는 값의 크기를 비교한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.35.16.png&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LpogF/dJMcadwxFEg/OPuAzh0vdwOfayv58dn3ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LpogF/dJMcadwxFEg/OPuAzh0vdwOfayv58dn3ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LpogF/dJMcadwxFEg/OPuAzh0vdwOfayv58dn3ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLpogF%2FdJMcadwxFEg%2FOPuAzh0vdwOfayv58dn3ak%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;676&quot; height=&quot;147&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.35.16.png&quot; data-origin-width=&quot;1354&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;즉, 매번 비교를 통해 탐색할 필요가 없는 영역을 제외할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(2) BST 탐색&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BST의 탐색과정은 매우 단순하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 노드를 current, 찾고 싶은 값을 target이라고 하면 다음 세 가지 경우가 존재한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;target == current
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원하는 값을 찾았으므로 탐색 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;target &amp;lt; current
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 값보다 작으므로 왼쪽으로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;target &amp;gt; current
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 값보다 크므로 오른쪽으로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 코드로 구현하면 대략 다음과 같다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;public Node search(int key) {
    Node cur = head;
    
    
    while (cur != null) {
        
        if (cur.key == key) {
            return cur;
        }
        
        if (key &amp;lt; cur.key) {
            cur = cur.left;
        } else {
            cur = cur.right;
        }
        
    }
    
    return null;
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2️⃣ BST 삽입&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BST의 삽입 방법도 탐색과 거의 동일하다.&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;새로운 값 12를 삽입한다고 가정해보자.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.41.59.png&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;582&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nXwJo/dJMcajwYLZ3/RpbhKgJ0I09PMIdlVew83K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nXwJo/dJMcajwYLZ3/RpbhKgJ0I09PMIdlVew83K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nXwJo/dJMcajwYLZ3/RpbhKgJ0I09PMIdlVew83K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnXwJo%2FdJMcajwYLZ3%2FRpbhKgJ0I09PMIdlVew83K%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;456&quot; height=&quot;462&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.41.59.png&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;582&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;12와 20을 비교한다.&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;12 &amp;lt; 20&lt;/p&gt;
&lt;p data-end=&quot;2210&quot; data-start=&quot;2206&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 왼쪽&lt;/p&gt;
&lt;p data-end=&quot;2225&quot; data-start=&quot;2212&quot; data-ke-size=&quot;size16&quot;&gt;12와 10을 비교한다.&lt;/p&gt;
&lt;p data-end=&quot;2234&quot; data-start=&quot;2227&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2234&quot; data-start=&quot;2227&quot; data-ke-size=&quot;size16&quot;&gt;12 &amp;gt; 10&lt;/p&gt;
&lt;p data-end=&quot;2241&quot; data-start=&quot;2236&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 오른쪽&lt;/p&gt;
&lt;p data-end=&quot;2256&quot; data-start=&quot;2243&quot; data-ke-size=&quot;size16&quot;&gt;12와 15를 비교한다.&lt;/p&gt;
&lt;p data-end=&quot;2265&quot; data-start=&quot;2258&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2265&quot; data-start=&quot;2258&quot; data-ke-size=&quot;size16&quot;&gt;12 &amp;lt; 15&lt;/p&gt;
&lt;p data-end=&quot;2271&quot; data-start=&quot;2267&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 왼쪽&lt;/p&gt;
&lt;p data-end=&quot;2298&quot; data-start=&quot;2273&quot; data-ke-size=&quot;size16&quot;&gt;15의 왼쪽이 비어 있으므로 여기에 삽입한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.42.29.png&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;744&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckmhpc/dJMcaaNz1HG/rEFCDOhJxa5HpBSrLTOswK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckmhpc/dJMcaaNz1HG/rEFCDOhJxa5HpBSrLTOswK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckmhpc/dJMcaaNz1HG/rEFCDOhJxa5HpBSrLTOswK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fckmhpc%2FdJMcaaNz1HG%2FrEFCDOhJxa5HpBSrLTOswK%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;454&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.42.29.png&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;744&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;Java 코드로 구현하면 다음과 같다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;public Node addNodeRecursive(Node cur, int key) {

    if (cur == null) {
        // 삽입할 위치를 찾으면 새 Node에 key값을 저장해 반환한다.
        return new Node(key, null, null);
    }
    
    
    // 삽입 위치를 찾은경우 새Node가 반환되어 현재 위치에 오른쪽이나 왼쪽 위치에 배치해준다.
    if (key &amp;lt; cur.key) {
        cur.left = addNodeRecursive(cur.left, key);
    } else {
        cur.right = addNodeRecursive(cur.right, key);
    }

    return cur;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3️⃣ BST의 삭제&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(1) 자식노드가 없는 경우&lt;/h4&gt;
&lt;p data-end=&quot;2643&quot; data-start=&quot;2620&quot; data-ke-size=&quot;size16&quot;&gt;BST의 삭제가 삽입이나 탐색보다 어렵다. 삭제하는 노드의 자식 개수에 따라 처리 방법이 달라지기 때문이다.&lt;/p&gt;
&lt;p data-end=&quot;2700&quot; data-start=&quot;2683&quot; data-ke-size=&quot;size16&quot;&gt;첫 번째는 가장 간단한 경우다. 삭제할 노드가 Leaf Node라면 그냥 제거하면 된다.&lt;/p&gt;
&lt;p data-end=&quot;2758&quot; data-start=&quot;2735&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 다음 트리에서 15를 삭제한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.45.10.png&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAD6kj/dJMcagmBA8v/LDaEHe3EK9ySilYVQeJw7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAD6kj/dJMcagmBA8v/LDaEHe3EK9ySilYVQeJw7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAD6kj/dJMcagmBA8v/LDaEHe3EK9ySilYVQeJw7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAD6kj%2FdJMcagmBA8v%2FLDaEHe3EK9ySilYVQeJw7K%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;480&quot; height=&quot;490&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.45.10.png&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;586&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;15는 자식이 없다.&lt;/p&gt;
&lt;p data-end=&quot;2917&quot; data-start=&quot;2871&quot; data-ke-size=&quot;size16&quot;&gt;따라서 부모인 10이 가지고 있는 15에 대한 링크를 null로 변경하면 된다.&lt;/p&gt;
&lt;p data-end=&quot;2917&quot; data-start=&quot;2871&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(2) 자식이 하나인 경우&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째는 삭제할 노드가 자식을 하나 가지고 있는 경우이다.&lt;/p&gt;
&lt;p data-end=&quot;3203&quot; data-start=&quot;3165&quot; data-ke-size=&quot;size16&quot;&gt;이 경우에는 &lt;b&gt;삭제 대상의 자식을 삭제 대상의 부모와 연결한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3210&quot; data-start=&quot;3205&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;10
 \
  15
    \
     17&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3263&quot; data-start=&quot;3250&quot; data-ke-size=&quot;size16&quot;&gt;여기서 15를 삭제한다면&lt;/p&gt;
&lt;p data-end=&quot;3289&quot; data-start=&quot;3265&quot; data-ke-size=&quot;size16&quot;&gt;15의 자식인 17을 10과 연결하면 된다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;10
 \
  17&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3316&quot; data-start=&quot;3315&quot; data-ke-size=&quot;size16&quot;&gt;즉&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;부모 &amp;rarr; 삭제 대상 &amp;rarr; 자식&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3350&quot; data-start=&quot;3347&quot; data-ke-size=&quot;size16&quot;&gt;구조를&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;부모 &amp;rarr; 자식&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3381&quot; data-start=&quot;3373&quot; data-ke-size=&quot;size16&quot;&gt;으로 변경한다.&lt;/p&gt;
&lt;p data-end=&quot;3381&quot; data-start=&quot;3373&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3381&quot; data-start=&quot;3373&quot; data-ke-size=&quot;size16&quot;&gt;Java 코드로 작성하면 자식이 없는 경우와 자식이 하나인 경우는 아래와 같이 작성할 수 있다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;if (key &amp;lt; cur.key) {
    cur.left = removeNodeRecursive(cur.left, key);
} else if (key &amp;gt; cur.key){
    cur.right = removeNodeRecursive(cur.right, key);
} else {
    if (cur.left == null) {
        return cur.right;
    } else if (cur.right == null) {
        return cur.left;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 key값의 크기에 따라 재귀 호출로 이동하고 key값을 찾았을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 노드의 왼쪽 값이 null이면 오른쪽 값을 반환해주고, 오른쪽 값이 null이면 왼쪽값을 반환해준다.&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;자식이 없는경우는 두 검증 조건에서 한쪽이 없을 경우 다른 한쪽을 반환하는데 다른 한쪽도 null일 것이기 때문에 해당 조건으로 검증이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) 자식이 둘인 경우&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 복잡한 경우이다. 삭제 대상이 왼쪽과 오른쪽 자식을 모두 가지고 있다면 단순히 노드를 없애면 BST의 규칙이 깨질 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;3586&quot; data-start=&quot;3527&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3586&quot; data-start=&quot;3527&quot; 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-filename=&quot;스크린샷 2026-09-12 오후 7.52.52.png&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m9pTR/dJMcabS9RGr/7gBoiL2wAu2DGZJSXzkJz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m9pTR/dJMcabS9RGr/7gBoiL2wAu2DGZJSXzkJz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m9pTR/dJMcabS9RGr/7gBoiL2wAu2DGZJSXzkJz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm9pTR%2FdJMcabS9RGr%2F7gBoiL2wAu2DGZJSXzkJz0%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;765&quot; height=&quot;501&quot; data-filename=&quot;스크린샷 2026-09-12 오후 7.52.52.png&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;586&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;여기서 20을 삭제하고 싶다고 해보자. 20을 대신할 값으로 사용할 수 있는 대표적인 후보가 두 가지 있다.&lt;/p&gt;
&lt;p data-end=&quot;3780&quot; data-start=&quot;3772&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;방법 1&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3799&quot; data-start=&quot;3782&quot; data-ke-size=&quot;size16&quot;&gt;왼쪽 서브 트리에서 가장 큰 값&lt;/p&gt;
&lt;p data-end=&quot;3805&quot; data-start=&quot;3801&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 15&lt;/p&gt;
&lt;p data-end=&quot;3815&quot; data-start=&quot;3807&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;방법 2&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;3836&quot; data-start=&quot;3817&quot; data-ke-size=&quot;size16&quot;&gt;오른쪽 서브 트리에서 가장 작은 값&lt;/p&gt;
&lt;p data-end=&quot;3842&quot; data-start=&quot;3838&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 25&lt;br /&gt;이 두 방법 중 하나를 선택하여 삭제 대상의 위치로 올리는 방식을 사용하면 된다.&lt;/p&gt;
&lt;p data-end=&quot;3842&quot; data-start=&quot;3838&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3842&quot; data-start=&quot;3838&quot; data-ke-size=&quot;size16&quot;&gt;Java 코드로 설명하자면&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;Node predecessor = cur;
Node successor = cur.left;

while (successor.right != null) {
    predecessor = successor;
    successor = successor.right;
}

predecessor.right = successor.left;
cur.key = successor.key;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;삭제할 노드의 왼쪽 서브트리에서 가장 큰 노드를 찾고, 그 노드의 값을 삭제 대상 노드에 복사한 뒤, 원래 위치에 있던 해당 노드를 제거하면서 왼쪽 자식이 있다면 부모 노드에 연결한다.&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;  BST의 시간 복잡도&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BST의 탐색, 삽입, 삭제는 기본적으로 루트에서 아래 방향으로 내려간다. 따라서 시간 복잡도는 &lt;b&gt;트리의 높이 h&lt;/b&gt;에 영향을 받는다.&lt;/p&gt;
&lt;p data-end=&quot;4280&quot; data-start=&quot;4274&quot; data-ke-size=&quot;size16&quot;&gt;일반적으로는O(h) 라고 표현하는 것이 가장 정확하다.&lt;/p&gt;
&lt;p data-end=&quot;4324&quot; data-start=&quot;4311&quot; data-ke-size=&quot;size16&quot;&gt;트리가 균형 잡혀 있다면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;       20
      /  \
    10    30
   / \    / \
  5  15  25  40&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4422&quot; data-start=&quot;4403&quot; data-ke-size=&quot;size16&quot;&gt;높이는 대략 log N이 된다.&lt;/p&gt;
&lt;p data-end=&quot;4427&quot; data-start=&quot;4424&quot; data-ke-size=&quot;size16&quot;&gt;따라서&lt;/p&gt;
&lt;p data-end=&quot;4442&quot; data-start=&quot;4429&quot; data-ke-size=&quot;size16&quot;&gt;탐색 : O(log N)&lt;/p&gt;
&lt;p data-end=&quot;4457&quot; data-start=&quot;4444&quot; data-ke-size=&quot;size16&quot;&gt;삽입 : O(log N)&lt;/p&gt;
&lt;p data-end=&quot;4472&quot; data-start=&quot;4459&quot; data-ke-size=&quot;size16&quot;&gt;삭제 : O(log N)&lt;/p&gt;
&lt;p data-end=&quot;4481&quot; data-start=&quot;4474&quot; data-ke-size=&quot;size16&quot;&gt;이 가능하다.&lt;/p&gt;</description>
      <category>자료구조</category>
      <author>KongJiHoon</author>
      <guid isPermaLink="true">https://kjhs-97.tistory.com/329</guid>
      <comments>https://kjhs-97.tistory.com/329#entry329comment</comments>
      <pubDate>Sat, 12 Sep 2026 19:56:37 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 Lv3 - 여행경로</title>
      <link>https://kjhs-97.tistory.com/327</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43164&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/43164&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1788951096629&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 여행경로&quot; data-og-description=&quot;알고리즘 문제 연습 카카오톡 친구해요! 프로그래머스 교육 카카오 채널을 만들었어요. 여기를 눌러, 친구 추가를 해주세요. 신규 교육 과정 소식은 물론 다양한 이벤트 소식을 가장 먼저 알려&quot; data-og-host=&quot;school.programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43164&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/og36x/dJMb86Plvdd/M5z3H2rYX8TqXNbq1Ja1I0/img.jpg?width=2000&amp;amp;height=2000&amp;amp;face=0_0_2000_2000,https://scrap.kakaocdn.net/dn/bMOvFJ/dJMb84Yiwgg/OIo9gKUlKVSLLuoGKUr1dk/img.jpg?width=2000&amp;amp;height=2000&amp;amp;face=0_0_2000_2000,https://scrap.kakaocdn.net/dn/y9eZj/dJMb89yxviv/oL2apA2A7XvkPexFCU0L31/img.jpg?width=960&amp;amp;height=270&amp;amp;face=0_0_960_270&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43164&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43164&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/og36x/dJMb86Plvdd/M5z3H2rYX8TqXNbq1Ja1I0/img.jpg?width=2000&amp;amp;height=2000&amp;amp;face=0_0_2000_2000,https://scrap.kakaocdn.net/dn/bMOvFJ/dJMb84Yiwgg/OIo9gKUlKVSLLuoGKUr1dk/img.jpg?width=2000&amp;amp;height=2000&amp;amp;face=0_0_2000_2000,https://scrap.kakaocdn.net/dn/y9eZj/dJMb89yxviv/oL2apA2A7XvkPexFCU0L31/img.jpg?width=960&amp;amp;height=270&amp;amp;face=0_0_960_270');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 여행경로&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;알고리즘 문제 연습 카카오톡 친구해요! 프로그래머스 교육 카카오 채널을 만들었어요. 여기를 눌러, 친구 추가를 해주세요. 신규 교육 과정 소식은 물론 다양한 이벤트 소식을 가장 먼저 알려&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;school.programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1️⃣ 문제 요약&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 항공권을 모두 사용하여 여행 경로를 만드는 문제이다.&lt;/p&gt;
&lt;p data-end=&quot;126&quot; data-start=&quot;83&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;126&quot; data-start=&quot;83&quot; data-ke-size=&quot;size16&quot;&gt;항상 &quot;ICN&quot; 공항에서 출발하며, 하나의 항공권은 한 번만 사용할 수 있다. 모든 항공권을 사용한 가능한 경로가 여러 개 존재할 경우, 알파벳 사전순으로 가장 앞서는 경로를 반환해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;246&quot; data-start=&quot;192&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;246&quot; data-start=&quot;192&quot; data-ke-size=&quot;size16&quot;&gt;이 문제에서 &lt;b&gt;중요한 점은 공항의 방문 여부가 아니라 항공권의 사용 여부를 관리&lt;/b&gt;해야 한다는 것이다.&lt;/p&gt;
&lt;p data-end=&quot;352&quot; data-start=&quot;248&quot; data-ke-size=&quot;size16&quot;&gt;동일한 공항을 여러 번 방문할 수 있고, 같은 출발지와 도착지를 가지는 항공권도 여러 장 존재할 수 있기 때문에 visited 배열은 공항이 아닌 항공권의 인덱스를 기준으로 관리한다.&lt;/p&gt;
&lt;p data-end=&quot;352&quot; data-start=&quot;248&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;352&quot; data-start=&quot;248&quot; data-ke-size=&quot;size20&quot;&gt;2️⃣ 문제 풀이&lt;/h4&gt;
&lt;p data-end=&quot;352&quot; data-start=&quot;248&quot; data-ke-size=&quot;size16&quot;&gt;DFS와 백트래킹을 이용해서 여행 경로를 탐색하면되는 문제이다.&lt;/p&gt;
&lt;p data-end=&quot;352&quot; data-start=&quot;248&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;352&quot; data-start=&quot;248&quot; data-ke-size=&quot;size16&quot;&gt;다만 가능한 모든 경로를 저장한 뒤 정렬하는 방식이 아니라, 처음부터 제공되는 tickets를 사전순으로 정렬한 뒤에 탐색한다.&lt;/p&gt;
&lt;p data-end=&quot;352&quot; data-start=&quot;248&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;352&quot; data-start=&quot;248&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;먼저 항공권을 출발지 기준으로 정렬하고, 출발지가 같다면 도착지 기준으로 정렬&lt;/b&gt;한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;Arrays.sort(tickets, (a, b) -&amp;gt; {
    if (a[0].equals(b[0])) {
        return a[1].compareTo(b[1]);
    }

    return a[0].compareTo(b[0]);
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여행은 항상 &quot;ICN&quot;에서 시작하므로 처음 경로에 &quot;ICN&quot;을 추가하고 방문 여부를 체크해줄 visited 배열을 생성해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1788951400469&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;routes.add(&quot;ICN&quot;);

visited = new boolean[tickets.length];&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;DFS에서는 현재 공항 cur에서 출발할 수 있는 항공권을 찾는다.&lt;/p&gt;
&lt;p data-end=&quot;1009&quot; data-start=&quot;986&quot; data-ke-size=&quot;size16&quot;&gt;이미 사용한 항공권이라면 사용할 수 없다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;if (visited[i]) {
    continue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1100&quot; data-start=&quot;1058&quot; data-ke-size=&quot;size16&quot;&gt;현재 공항과 항공권의 출발지가 다르면 사용할 수 없는 항공권이므로 넘어간다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;if (!tickets[i][0].equals(cur)) {
    continue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1215&quot; data-start=&quot;1165&quot; data-ke-size=&quot;size16&quot;&gt;사용 가능한 항공권이라면 해당 항공권을 사용 처리하고 도착지를 현재 여행 경로에 추가한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;visited[i] = true;
routes.add(tickets[i][1]);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1311&quot; data-start=&quot;1276&quot; data-ke-size=&quot;size16&quot;&gt;이후 도착지를 새로운 현재 공항으로 설정하고 DFS를 진행한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;모든 항공권을 사용했다면 하나의 완전한 여행 경로가 만들어진다.&lt;/div&gt;
&lt;div&gt;이 때 true를 반환하여 더 이상 경로를 탐색하지 않게한다.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;항공권을 미리 사전순으로 정렬했기 때문에 DFS에서 처음으로 완성된 여행 경로가 문제에서 요구한 가장 앞선 경로가 된다.&lt;/div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1788951488792&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (count == tickets.length) {
    return true;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;import java.util.ArrayList;
import java.util.Arrays;

class Solution {

    boolean[] visited;
    ArrayList&amp;lt;String&amp;gt; routes = new ArrayList&amp;lt;&amp;gt;();


    public String[] solution(String[][] tickets) {

        Arrays.sort(tickets, (a, b) -&amp;gt; {
            if (a[0].equals(b[0])) {
                return a[1].compareTo(b[1]);
            }

            return a[0].compareTo(b[0]);
        });

        routes.add(&quot;ICN&quot;);

        visited = new boolean[tickets.length];

        dfs(&quot;ICN&quot;, 0, tickets);

        return routes.toArray(new String[0]);
    }

    private boolean dfs(String cur, int count, String[][] tickets) {

        if (count == tickets.length) {

            return true;
        }

        for (int i = 0; i &amp;lt; tickets.length; i++) {

            if (visited[i]) {
                continue;
            }

            if (!tickets[i][0].equals(cur)) {
                continue;
            }

            visited[i] = true;
            routes.add(tickets[i][1]);

            if (dfs(tickets[i][1], count + 1, tickets)) {
                return true;
            }

            routes.remove(routes.size() - 1);
            visited[i] = false;


        }

        return false;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <category>프로그래머스</category>
      <author>KongJiHoon</author>
      <guid isPermaLink="true">https://kjhs-97.tistory.com/327</guid>
      <comments>https://kjhs-97.tistory.com/327#entry327comment</comments>
      <pubDate>Wed, 9 Sep 2026 19:58:25 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 Lv3 - 아이템 줍기</title>
      <link>https://kjhs-97.tistory.com/325</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/87694&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/87694&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1788856922751&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/87694&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mv2to/dJMb81gcgp4/E2RaaTmCMKTPYnvBYwLgTK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bb3pkO/dJMb83kMJwU/ncDSGjtiNgXcIZ4Tmp55JK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/87694&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/87694&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mv2to/dJMb81gcgp4/E2RaaTmCMKTPYnvBYwLgTK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bb3pkO/dJMb83kMJwU/ncDSGjtiNgXcIZ4Tmp55JK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;1️⃣ 문제 요약&lt;/h4&gt;
&lt;p data-end=&quot;40&quot; data-start=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;여러 개의 직사각형이 겹쳐 만들어진 다각형 지형이 주어진다.&lt;/p&gt;
&lt;p data-end=&quot;107&quot; data-start=&quot;42&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터는 직사각형 내부를 이동할 수 없고, &lt;b&gt;겹쳐진 직사각형들로 만들어진 다각형의 바깥 테두리만 따라 이동&lt;/b&gt;할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;208&quot; data-start=&quot;109&quot; data-ke-size=&quot;size16&quot;&gt;캐릭터의 &lt;b&gt;시작 위치와 아이템의 위치가 주어졌을 때, 테두리를 따라 아이템까지 이동하는 최단거리&lt;/b&gt;를 구해야 한다.&lt;/p&gt;
&lt;p data-end=&quot;208&quot; data-start=&quot;109&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;208&quot; data-start=&quot;109&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;2️⃣ 문제 풀이&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 모든 직사각형의 영역을 채운다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 직사각형 내부의 영역 0으로 채워 테두리만 1로 남긴다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 남아 있는 테두리를 BFS로 탐색해 최단거리를 구한다.&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; 좌표를 2배로 확대&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;단순히 원래 좌표 그대로 테두리를 만들면, 실제로는 연결되어 있지 않은 두 테두리가 배열에서는 붙어 있는 것처럼 표현되는 문제가 발생한다.&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;pre id=&quot;code_1788857176546&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(1,2) - (2,2)
  |       |
(1,1) - (2,1)&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;rarr; 오른쪽 &amp;rarr; 아래로 이동해야 하지만 좌표상으로는 인접해 있기 떄문에 바로 오른쪽으로 이동할 수가 있다 따라서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좌표를 2배로 설정하면&lt;/p&gt;
&lt;pre id=&quot;code_1788857332355&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(2,4) --------- (4,4)
  |               |
(2,2) - (3,2) - (4,2)&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;아래 좌표가 하나 더 생겨 원래 경로대로 움직일 수 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int x1 = rect[0] * 2;
int y1 = rect[1] * 2;
int x2 = rect[2] * 2;
int y2 = rect[3] * 2;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;852&quot; data-start=&quot;787&quot; data-ke-size=&quot;size16&quot;&gt;좌표를 2배로 만들면 기존 좌표 사이에 새로운 공간이 생기기 때문에 서로 붙어 있던 경로를 명확하게 구분할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;852&quot; data-start=&quot;787&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;852&quot; data-start=&quot;787&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;852&quot; data-start=&quot;787&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;(1) 모든 직사각형을 1로 채운다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;852&quot; data-start=&quot;787&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;852&quot; data-start=&quot;787&quot; data-ke-size=&quot;size16&quot;&gt;int형 배열은 좌표의 최대 수가 50이기 때문에 102로 잡아주고 각각의 좌표를 지나간 적이 있는지를 판별할 boolean배열도 생성해준다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;private final int[][] map = new int[102][102];
private final boolean[][] visited = new boolean[102][102];&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 아래와 같이 해당 직사각형을 1로 채워준다.&lt;/p&gt;
&lt;pre id=&quot;code_1788857454458&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (int i = x1; i &amp;lt;= x2; i++) {
    for (int j = y1; j &amp;lt;= y2; j++) {
        map[i][j] = 1;
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;(2) 직사각형 안을 0으로 채운다.&lt;/b&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;캐릭터가 이동할 수 있는 곳은 테두리뿐이다.&lt;/p&gt;
&lt;p data-end=&quot;1419&quot; data-start=&quot;1377&quot; data-ke-size=&quot;size16&quot;&gt;따라서 각 직사각형의 가장자리 한 칸을 제외하고 내부를 모두 0으로 만든다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;for (int i = x1 + 1; i &amp;lt; x2; i++) {
    for (int j = y1 + 1; j &amp;lt; y2; j++) {
        map[i][j] = 0;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1551&quot; data-start=&quot;1541&quot; data-ke-size=&quot;size16&quot;&gt;여기서 중요한 점은&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;x1 + 1
y1 + 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1587&quot; data-start=&quot;1580&quot; data-ke-size=&quot;size16&quot;&gt;부터 시작하고&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;i &amp;lt; x2
j &amp;lt; y2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1630&quot; data-start=&quot;1616&quot; data-ke-size=&quot;size16&quot;&gt;까지만 처리한다는 것이다. 즉, 테두리는 건드리지 않고 내부만 제거한다.&lt;/p&gt;
&lt;p data-end=&quot;1630&quot; data-start=&quot;1616&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1630&quot; data-start=&quot;1616&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;(3) BFS 최단거리 탐색&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1630&quot; data-start=&quot;1616&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1630&quot; data-start=&quot;1616&quot; data-ke-size=&quot;size16&quot;&gt;테두리가 만들어졌다면 일반적인 격자 BFS 문제와 동일해진다.&lt;/p&gt;
&lt;p data-end=&quot;2026&quot; data-start=&quot;2001&quot; data-ke-size=&quot;size16&quot;&gt;시작 위치도 마찬가지로 2배 좌표를 사용한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;return bfs(
        characterX * 2,
        characterY * 2,
        itemX * 2,
        itemY * 2
);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2148&quot; data-start=&quot;2141&quot; data-ke-size=&quot;size16&quot;&gt;BFS 큐에는&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;{x, y, distance}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2187&quot; data-start=&quot;2180&quot; data-ke-size=&quot;size16&quot;&gt;를 저장한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;queue.offer(new int[]{
        characterX,
        characterY,
        0
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2298&quot; data-start=&quot;2279&quot; data-ke-size=&quot;size16&quot;&gt;그리고 시작 위치를 방문 처리한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;visited[characterX][characterY] = true;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후에 상하좌우를 이동하면서 조건을 만족하는 좌표를 Queue에 넣어준다.&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;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;/li&gt;
&lt;li&gt;테두리인 경우에만 이동한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;for (int i = 0; i &amp;lt; 4; i++) {

    int nx = x + dx[i];
    int ny = y + dy[i];

    if (nx &amp;lt; 0 || nx &amp;gt;= 102 || ny &amp;lt; 0 || ny &amp;gt;= 102) {
        continue;
    }

    if (visited[nx][ny]) {
        continue;
    }

    if (map[nx][ny] != 1) {
        continue;
    }

    visited[nx][ny] = true;

    queue.offer(new int[]{nx, ny, distance + 1});

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import java.util.ArrayDeque;
import java.util.Queue;

class Solution {

    private final int[][] map = new int[102][102];
    private final boolean[][] visited = new boolean[102][102];

    private final int[] dx = {-1, 1, 0, 0};
    private final int[] dy = {0, 0, -1, 1};

    public int solution(int[][] rectangle, int characterX, int characterY, int itemX, int itemY) {


        for (int[] rect : rectangle) {

            /*
             * 직사각형 안을 모두 1로 채운다.
             * ㄷ자 경로에서 인접값이 존재하면 지름길 형성이 될 수 있으므로
             * 직사각형을 2배 키워서 좌표사이에 좌표를 생성해준다.
             */
            int x1 = rect[0] * 2;
            int y1 = rect[1] * 2;
            int x2 = rect[2] * 2;
            int y2 = rect[3] * 2;

            for (int i = x1; i &amp;lt;= x2; i++) {
                for (int j = y1; j &amp;lt;= y2; j++) {

                    map[i][j] = 1;

                }
            }
        }

        for (int[] rect : rectangle) {

            /*
             * 직사각형의 테두리만 탐색하므로 안쪽은 0으로 채운다
             * 각 직사각형의 안쪽을 채우므로 겹치는 부분은 0, 테두리는 1
             */

            int x1 = rect[0] * 2;
            int y1 = rect[1] * 2;
            int x2 = rect[2] * 2;
            int y2 = rect[3] * 2;

            for (int i = x1 + 1; i &amp;lt; x2; i++) {
                for (int j = y1 + 1; j &amp;lt; y2; j++) {
                    map[i][j] = 0;
                }
            }

        }


        return bfs(characterX * 2, characterY * 2, itemX * 2, itemY * 2);
    }

    private int bfs(int characterX, int characterY, int itemX, int itemY) {

        Queue&amp;lt;int[]&amp;gt; queue = new ArrayDeque&amp;lt;&amp;gt;();

        queue.offer(new int[]{characterX, characterY, 0});

        visited[characterX][characterY] = true;

        while (!queue.isEmpty()) {

            int[] cur = queue.poll();

            int x = cur[0];
            int y = cur[1];
            int distance = cur[2];

            if (x == itemX &amp;amp;&amp;amp; y == itemY) {
                return distance / 2;
            }

            for (int i = 0; i &amp;lt; 4; i++) {

                int nx = x + dx[i];
                int ny = y + dy[i];

                if (nx &amp;lt; 0 || nx &amp;gt;= 102 || ny &amp;lt; 0 || ny &amp;gt;= 102) {
                    continue;
                }

                if (visited[nx][ny]) {
                    continue;
                }

                if (map[nx][ny] != 1) {
                    continue;
                }

                visited[nx][ny] = true;

                queue.offer(new int[]{nx, ny, distance + 1});

            }

        }

        return -1;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;직사각형을 채우고 내부를 제거하는 과정은 직사각형 개수가 최대 4개이므로 사실상 매우 작다.&lt;/p&gt;
&lt;p data-end=&quot;4244&quot; data-start=&quot;4218&quot; data-ke-size=&quot;size16&quot;&gt;BFS 역시 각 좌표를 최대 한 번씩 방문한다.&lt;/p&gt;
&lt;p data-end=&quot;4274&quot; data-start=&quot;4246&quot; data-ke-size=&quot;size16&quot;&gt;따라서 격자의 가로와 세로를 각각 W, H라고 하면 O(W &amp;times; H)이다.&lt;/p&gt;</description>
      <author>KongJiHoon</author>
      <guid isPermaLink="true">https://kjhs-97.tistory.com/325</guid>
      <comments>https://kjhs-97.tistory.com/325#entry325comment</comments>
      <pubDate>Tue, 8 Sep 2026 17:54:16 +0900</pubDate>
    </item>
    <item>
      <title>가상 메모리와 페이징 시스템</title>
      <link>https://kjhs-97.tistory.com/323</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1️⃣ 가상 메모리(Virtual Memory)란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상 메모리는 &lt;b&gt;프로세스가 실제 물리 메모리(RAM)보다 더 큰 메모리 공간을 사용하는 것처럼 보이게 만드는 기술&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;예를 들어 실제 RAM이 8GB라고 해도, 각 프로세스는 자신만의 독립된 가상 주소 공간을 가진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.13.46.png&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nCSmy/dJMcabS5i3M/eQkfySsKpQ46Kt5YWRYh6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nCSmy/dJMcabS5i3M/eQkfySsKpQ46Kt5YWRYh6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nCSmy/dJMcabS5i3M/eQkfySsKpQ46Kt5YWRYh6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnCSmy%2FdJMcabS5i3M%2FeQkfySsKpQ46Kt5YWRYh6k%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;712&quot; height=&quot;251&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.13.46.png&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;486&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;프로그램 입장에서는 단순히 메모리 주소를 사용하지만,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;프로그램이 사용하는 주소
        &amp;darr;
    가상 주소
        &amp;darr;
MMU + Page Table
        &amp;darr;
    물리 주소
        &amp;darr;
       RAM&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;644&quot; data-start=&quot;602&quot; data-ke-size=&quot;size16&quot;&gt;실제로는 운영체제와 하드웨어가 &lt;b&gt;가상 주소 &amp;rarr; 물리 주소&lt;/b&gt;로 변환해준다.&lt;/p&gt;
&lt;p data-end=&quot;644&quot; data-start=&quot;602&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-end=&quot;644&quot; data-start=&quot;602&quot; data-ke-size=&quot;size20&quot;&gt;(1) 가상 메모리의 필요성&lt;/h4&gt;
&lt;p data-end=&quot;644&quot; data-start=&quot;602&quot; data-ke-size=&quot;size16&quot;&gt;가장 중요한 목적은 크게 세 가지다.&lt;/p&gt;
&lt;p data-end=&quot;719&quot; data-start=&quot;695&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;719&quot; data-start=&quot;695&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1) 물리 메모리보다 큰 프로그램 실행&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;745&quot; data-start=&quot;721&quot; data-ke-size=&quot;size16&quot;&gt;프로그램 전체를 RAM에 올릴 필요가 없다&lt;b&gt;. 현재 필요한 부분만 RAM에 올리고, 나머지는 디스크&lt;/b&gt;에 둔다.&lt;/p&gt;
&lt;p data-end=&quot;745&quot; data-start=&quot;721&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;프로그램 크기: 10GB
사용 가능한 RAM: 4GB

프로그램 전체 10GB를 RAM에 올림 ❌

현재 필요한 부분만 RAM에 올림
        &amp;darr;
RAM
┌──────────────┐
│ 현재 사용하는 영역 │
│ 현재 사용하는 영역 │
│              │
└──────────────┘

나머지
    &amp;darr;
Disk&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;2) 프로세스 간 메모리 격리&lt;/b&gt;&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-filename=&quot;스크린샷 2026-09-07 오후 8.15.33.png&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lDr6R/dJMcadJ4O8l/sj1n5KHSe0G58UAhUk6ns1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lDr6R/dJMcadJ4O8l/sj1n5KHSe0G58UAhUk6ns1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lDr6R/dJMcadJ4O8l/sj1n5KHSe0G58UAhUk6ns1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlDr6R%2FdJMcadJ4O8l%2Fsj1n5KHSe0G58UAhUk6ns1%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;641&quot; height=&quot;336&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.15.33.png&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;486&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;둘 다 0x1000이라는 주소를 사용하더라도 실제 RAM에서는 서로 다른 위치를 가리킬 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1278&quot; data-start=&quot;1238&quot; data-ke-size=&quot;size16&quot;&gt;따라서 &lt;b&gt;한 프로세스가 다른 프로세스의 메모리를 마음대로 침범하기 어렵다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-end=&quot;1278&quot; data-start=&quot;1238&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1278&quot; data-start=&quot;1238&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3) 메모리를 효율적으로 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1278&quot; data-start=&quot;1238&quot; data-ke-size=&quot;size16&quot;&gt;프로그램이 가지고 있는 모든 코드를 항상 사용하는 것은 아니다.&lt;/p&gt;
&lt;p data-end=&quot;1416&quot; data-start=&quot;1343&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 애플리케이션이 1GB라 하더라도 지금 실행하는 코드가 200MB뿐이라면 필요한 200MB 정도만 RAM에 올릴 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1459&quot; data-start=&quot;1418&quot; data-ke-size=&quot;size16&quot;&gt;이러한 방식을 &lt;b&gt;Demand Paging(요구 페이징)&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;p data-end=&quot;1459&quot; data-start=&quot;1418&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-end=&quot;1459&quot; data-start=&quot;1418&quot; data-ke-size=&quot;size23&quot;&gt;2️⃣ 페이징(Paging) 이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가상 메모리를 관리하기 위해 메모리를 고정된 크기의 작은 블록으로 나누는 방식&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상 메모리의 블록:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Page&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1581&quot; data-start=&quot;1570&quot; data-ke-size=&quot;size16&quot;&gt;물리 메모리의 블록:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Frame&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1604&quot; data-start=&quot;1602&quot; data-ke-size=&quot;size16&quot;&gt;즉,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;가상 메모리 &amp;rarr; Page
물리 메모리 &amp;rarr; Frame&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1669&quot; data-start=&quot;1648&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;페이지와 프레임은 같은 크기&lt;/b&gt;를 가진다.&lt;/p&gt;
&lt;p data-end=&quot;1669&quot; data-start=&quot;1648&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 페이지 크기가 4KB라면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;가상 메모리

Page 0
Page 1
Page 2
Page 3
Page 4
...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1758&quot; data-start=&quot;1753&quot; data-ke-size=&quot;size16&quot;&gt;RAM은:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Frame 0
Frame 1
Frame 2
Frame 3
Frame 4
...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1826&quot; data-start=&quot;1817&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 구성된다.&lt;/p&gt;
&lt;p data-end=&quot;1826&quot; data-start=&quot;1817&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;1826&quot; data-start=&quot;1817&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;1826&quot; data-start=&quot;1817&quot; data-ke-size=&quot;size20&quot;&gt;(1) Page와 Frame의 관계&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상 메모리의 페이지는 &lt;b&gt;물리 메모리에 연속해서 들어갈 필요가 없다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-end=&quot;1826&quot; data-start=&quot;1817&quot; 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-filename=&quot;스크린샷 2026-09-07 오후 8.28.24.png&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;776&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d38x5s/dJMcaa0W3qW/TZ63rfhutuFblkzt4sXhk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d38x5s/dJMcaa0W3qW/TZ63rfhutuFblkzt4sXhk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d38x5s/dJMcaa0W3qW/TZ63rfhutuFblkzt4sXhk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd38x5s%2FdJMcaa0W3qW%2FTZ63rfhutuFblkzt4sXhk0%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;672&quot; height=&quot;563&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.28.24.png&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;776&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스에서는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Page 0
Page 1
Page 2
Page 3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2136&quot; data-start=&quot;2122&quot; data-ke-size=&quot;size16&quot;&gt;연속된 메모리처럼 보인다.&lt;/p&gt;
&lt;p data-end=&quot;2152&quot; data-start=&quot;2138&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실제 RAM에서는:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Frame 1 &amp;rarr; Page 2
Frame 3 &amp;rarr; Page 0
Frame 5 &amp;rarr; Page 3
Frame 7 &amp;rarr; Page 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2250&quot; data-start=&quot;2235&quot; data-ke-size=&quot;size16&quot;&gt;처럼 흩어져 있을 수 있다. 이것이 페이징의 중요한 특징이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-end=&quot;2250&quot; data-start=&quot;2235&quot; data-ke-size=&quot;size20&quot;&gt;(2) Page Table&lt;/h4&gt;
&lt;p data-end=&quot;2250&quot; data-start=&quot;2235&quot; data-ke-size=&quot;size16&quot;&gt;그렇다면 CPU는 어떻게 Page 1 &amp;rarr; Frame7 이라는 사실을 알 수 있을까?&lt;/p&gt;
&lt;p data-end=&quot;2250&quot; data-start=&quot;2235&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2250&quot; data-start=&quot;2235&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이를 저장하는 자료구조가 Page Table&lt;/b&gt;이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Page Table

Page Number | Frame Number
---------------------------
Page 0      | Frame 3
Page 1      | Frame 7
Page 2      | Frame 1
Page 3      | Frame 5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2569&quot; data-start=&quot;2558&quot; 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-filename=&quot;스크린샷 2026-09-07 오후 8.30.04.png&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RBVV0/dJMcaiq7rKU/z7NuGMhA21UYLOmCZuMkT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RBVV0/dJMcaiq7rKU/z7NuGMhA21UYLOmCZuMkT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RBVV0/dJMcaiq7rKU/z7NuGMhA21UYLOmCZuMkT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRBVV0%2FdJMcaiq7rKU%2Fz7NuGMhA21UYLOmCZuMkT1%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;753&quot; height=&quot;162&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.30.04.png&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;278&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(3) 가상 주소의 구조&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상 주소는 일반적으로 두 부분으로 나뉜다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Virtual Address

┌─────────────┬─────────────┐
│ Page Number │   Offset    │
└─────────────┴─────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2892&quot; data-start=&quot;2872&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 페이지 크기가 4KB라면,&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;4KB = 2^12 bytes&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2946&quot; data-start=&quot;2924&quot; data-ke-size=&quot;size16&quot;&gt;이므로 Offset은 12bit가 된다.&lt;/p&gt;
&lt;p data-end=&quot;2946&quot; data-start=&quot;2924&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2946&quot; data-start=&quot;2924&quot; data-ke-size=&quot;size16&quot;&gt;CPU가 다음 주소를 접근한다고 가정해보자.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Virtual Address
       &amp;darr;
Page Number + Offset&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3046&quot; data-start=&quot;3033&quot; data-ke-size=&quot;size16&quot;&gt;Page Table에서:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Page Number &amp;rarr; Frame Number&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3113&quot; data-start=&quot;3088&quot; data-ke-size=&quot;size16&quot;&gt;으로 변환하고 Offset은 그대로 유지한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Virtual Address

Page Number | Offset
      &amp;darr;
Page Table
      &amp;darr;
Frame Number | Offset

Physical Address&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(4) 주소 변환 과정&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.32.16.png&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;1224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pfW1E/dJMcabS5jUW/oSLDqKhQwiNPDXtO3gyTIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pfW1E/dJMcabS5jUW/oSLDqKhQwiNPDXtO3gyTIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pfW1E/dJMcabS5jUW/oSLDqKhQwiNPDXtO3gyTIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpfW1E%2FdJMcabS5jUW%2FoSLDqKhQwiNPDXtO3gyTIK%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;657&quot; height=&quot;863&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.32.16.png&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;1224&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;즉,&lt;/p&gt;
&lt;pre id=&quot;code_1788780799491&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CPU &amp;rarr; 가상주소 생성 &amp;rarr; Page Nuber 확인 &amp;rarr; Page Table 조회 &amp;rarr; Frame Number 확인 &amp;rarr; 물리 주소 생성 &amp;rarr; RAM 접근&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;(5) Page Fault&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 CPU가 요청한 Page가 RAM에 없을 수도 있다는 것이다.&lt;/p&gt;
&lt;p data-end=&quot;3686&quot; data-start=&quot;3659&quot; data-ke-size=&quot;size16&quot;&gt;이때 발생하는 것이 &lt;b&gt;Page Fault&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-end=&quot;3694&quot; data-start=&quot;3688&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;CPU &amp;rarr; Page 5 요청&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3744&quot; data-start=&quot;3725&quot; data-ke-size=&quot;size16&quot;&gt;그런데 Page Table을 보니:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Page 5 &amp;rarr; RAM에 없음&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;3797&quot; data-start=&quot;3776&quot; data-ke-size=&quot;size16&quot;&gt;그러면 Page Fault가 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.34.15.png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;1476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtFAy5/dJMcaatb0St/8Mm2o2IUmYK4m5OTzGpFV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtFAy5/dJMcaatb0St/8Mm2o2IUmYK4m5OTzGpFV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtFAy5/dJMcaatb0St/8Mm2o2IUmYK4m5OTzGpFV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtFAy5%2FdJMcaatb0St%2F8Mm2o2IUmYK4m5OTzGpFV0%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;636&quot; height=&quot;935&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.34.15.png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;1476&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(6) Page Fault 처리과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 구체적으로 보면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;1. CPU가 메모리에 접근

2. Page Table 확인

3. 해당 Page가 RAM에 없음

4. Page Fault 발생

5. CPU가 OS에게 제어권 넘김

6. OS가 Disk에서 해당 Page 찾음

7. RAM의 빈 Frame에 Page 로드

8. Page Table 수정

9. 중단됐던 명령 다시 실행&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4382&quot; data-start=&quot;4365&quot; data-ke-size=&quot;size16&quot;&gt;여기서 매우 중요한 점이 있다.&lt;/p&gt;
&lt;p data-end=&quot;4416&quot; data-start=&quot;4384&quot; data-ke-size=&quot;size16&quot;&gt;RAM 접근은 매우 빠른 반면 디스크 접근은 훨씬 느리다.&lt;/p&gt;
&lt;p data-end=&quot;4459&quot; data-start=&quot;4418&quot; data-ke-size=&quot;size16&quot;&gt;따라서&lt;b&gt; Page Fault가 자주 발생하면 시스템 성능이 급격히 떨어진다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-end=&quot;4459&quot; data-start=&quot;4418&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4459&quot; data-start=&quot;4418&quot; data-ke-size=&quot;size16&quot;&gt;❓RAM이 꽉 차 있다면?&lt;/p&gt;
&lt;p data-end=&quot;4459&quot; data-start=&quot;4418&quot; data-ke-size=&quot;size16&quot;&gt;빈 Frame이 없다면 기존 페이지 하나를 제거해야 한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;RAM

Frame 0 &amp;rarr; Page A
Frame 1 &amp;rarr; Page B
Frame 2 &amp;rarr; Page C
Frame 3 &amp;rarr; Page D

새로운 Page E 필요&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4646&quot; data-start=&quot;4622&quot; data-ke-size=&quot;size16&quot;&gt;그러면 OS는 기존 페이지 하나를 골라낸다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Page C 제거
    &amp;darr;
Page E 삽입&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size16&quot;&gt;이것을 &lt;b&gt;Page Replacement(페이지 교체)&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size23&quot;&gt;3️⃣ 페이지 교체 알고리즘(Page Replacement Algorithm)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;어떤 페이지를 제거할 것인지를 결정하는 것이 페이지 교체 알고리즘&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;4814&quot; data-start=&quot;4808&quot; data-ke-size=&quot;size16&quot;&gt;대표적으로:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;FIFO
Optimal
LRU
Clock&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4857&quot; data-start=&quot;4852&quot; data-ke-size=&quot;size16&quot;&gt;가 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size20&quot;&gt;(1) FIFO&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 들어온 페이지를 제거한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Page A &amp;rarr; Page B &amp;rarr; Page C &amp;rarr; Page D

가장 오래된 Page A 제거&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4963&quot; data-start=&quot;4960&quot; data-ke-size=&quot;size16&quot;&gt;장점:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;구현이 단순함&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4989&quot; data-start=&quot;4986&quot; data-ke-size=&quot;size16&quot;&gt;단점:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;자주 사용하는 페이지도 오래됐다는 이유만으로 제거될 수 있음&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size20&quot;&gt;(2) Optimal&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 가장 오랫동안 사용되지 않을 페이지를 제거한다.&lt;/p&gt;
&lt;p data-end=&quot;5093&quot; data-start=&quot;5087&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;현재 RAM

A B C

앞으로 접근 순서

A D B C ...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5169&quot; data-start=&quot;5146&quot; data-ke-size=&quot;size16&quot;&gt;C가 가장 늦게 사용된다면 C를 제거한다.&lt;/p&gt;
&lt;p data-end=&quot;5186&quot; data-start=&quot;5171&quot; data-ke-size=&quot;size16&quot;&gt;이론적으로 가장 효율적이다.&lt;/p&gt;
&lt;p data-end=&quot;5199&quot; data-start=&quot;5188&quot; data-ke-size=&quot;size16&quot;&gt;하지만 문제가 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;erlang&quot;&gt;&lt;code&gt;미래의 메모리 접근을 알아야 한다.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5279&quot; data-start=&quot;5234&quot; data-ke-size=&quot;size16&quot;&gt;따라서 실제 구현은 불가능하고 다른 알고리즘의 성능을 비교하는 기준으로 사용한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size20&quot;&gt;(3) LRU(Least Recently Used)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 오랫동안 사용되지 않은 페이지를 제거한다.&lt;/p&gt;
&lt;p data-end=&quot;5353&quot; data-start=&quot;5347&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;dns&quot;&gt;&lt;code&gt;최근 접근

A &amp;rarr; B &amp;rarr; C &amp;rarr; A &amp;rarr; B&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5414&quot; data-start=&quot;5393&quot; data-ke-size=&quot;size16&quot;&gt;C가 가장 오랫동안 사용되지 않았다면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;C 제거&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5456&quot; data-start=&quot;5434&quot; data-ke-size=&quot;size16&quot;&gt;Locality 원리를 이용한 방식이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size23&quot;&gt;4️⃣ 지역성(Locality)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램은 특정 메모리 영역을 집중적으로 사용하는 경향이 있다. 이를 &lt;b&gt;지역성(Locality)&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;p data-end=&quot;5557&quot; data-start=&quot;5546&quot; data-ke-size=&quot;size16&quot;&gt;두 종류가 중요하다.&lt;/p&gt;
&lt;p data-end=&quot;5557&quot; data-start=&quot;5546&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;5557&quot; data-start=&quot;5546&quot; data-ke-size=&quot;size20&quot;&gt;(1) Temporal Locality&lt;/h4&gt;
&lt;p data-end=&quot;5557&quot; data-start=&quot;5546&quot; data-ke-size=&quot;size16&quot;&gt;최근 사용한 데이터는 다시 사용할 가능성이 높다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;for (int i = 0; i &amp;lt; 1000; i++) {
    count++;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5705&quot; data-start=&quot;5672&quot; data-ke-size=&quot;size16&quot;&gt;count, i 같은 변수는 계속 반복해서 사용된다.&lt;/p&gt;
&lt;p data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size20&quot;&gt;(2) Spatial Locality&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 메모리를 사용하면 근처 메모리도 사용할 가능성이 높다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int[] arr = new int[1000];

for (int i = 0; i &amp;lt; arr.length; i++) {
    System.out.println(arr[i]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;5910&quot; data-start=&quot;5883&quot; data-ke-size=&quot;size16&quot;&gt;배열은 연속된 메모리 영역을 순차적으로 접근한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size23&quot;&gt;5️⃣ TLB&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Page Table을 매번 조회하면 문제가 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;CPU
 &amp;darr;
Page Table 접근
 &amp;darr;
RAM 접근&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6022&quot; data-start=&quot;6001&quot; data-ke-size=&quot;size16&quot;&gt;RAM을 사실상 두 번 접근하게 된다.&lt;/p&gt;
&lt;p data-end=&quot;6087&quot; data-start=&quot;6024&quot; data-ke-size=&quot;size16&quot;&gt;그래서 CPU에는 &lt;b&gt;TLB(Translation Lookaside Buffer)&lt;/b&gt;라는 고속 캐시가 존재한다.&lt;/p&gt;
&lt;p data-end=&quot;6087&quot; data-start=&quot;6024&quot; data-ke-size=&quot;size16&quot;&gt;TLB는 최근 사용한:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Page Number &amp;rarr; Frame Number&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6155&quot; data-start=&quot;6143&quot; data-ke-size=&quot;size16&quot;&gt;매핑 정보를 저장한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-custom-highlighting-behavior=&quot;boundary&quot;&gt;
&lt;div&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.39.36.png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;1312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UwOmq/dJMcagmxeQK/fuW1YqptQ16ZwLIWFw9NO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UwOmq/dJMcagmxeQK/fuW1YqptQ16ZwLIWFw9NO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UwOmq/dJMcagmxeQK/fuW1YqptQ16ZwLIWFw9NO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUwOmq%2FdJMcagmxeQK%2FfuW1YqptQ16ZwLIWFw9NO1%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;718&quot; height=&quot;938&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.39.36.png&quot; data-origin-width=&quot;1004&quot; data-origin-height=&quot;1312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-code-block-preview-pane=&quot;mermaid&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size20&quot;&gt;(1) TLB HIT / TLB Miss&lt;/h4&gt;
&lt;p data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;TLB Hit&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4726&quot; data-start=&quot;4687&quot; data-ke-size=&quot;size16&quot;&gt;TLB에 주소 변환 정보가 존재한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;CPU
 &amp;darr;
TLB
 &amp;darr;
Frame Number 발견
 &amp;darr;
RAM&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6504&quot; data-start=&quot;6500&quot; data-ke-size=&quot;size16&quot;&gt;빠르다.&lt;/p&gt;
&lt;p data-end=&quot;6504&quot; data-start=&quot;6500&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;6504&quot; data-start=&quot;6500&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;TLB Miss&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;6504&quot; data-start=&quot;6500&quot; data-ke-size=&quot;size16&quot;&gt;TLB에 변환 정보가 없다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;CPU
 &amp;darr;
TLB
 &amp;darr;
없음
 &amp;darr;
Page Table 조회
 &amp;darr;
Frame Number 발견
 &amp;darr;
TLB 저장
 &amp;darr;
RAM&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6647&quot; data-start=&quot;6625&quot; data-ke-size=&quot;size16&quot;&gt;여기서 헷갈리면 안 되는 게 하나 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;TLB Miss &amp;ne; Page Fault&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6709&quot; data-start=&quot;6684&quot; data-ke-size=&quot;size16&quot;&gt;TLB에는 없지만 RAM에는 존재할 수 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;TLB Miss
    &amp;darr;
Page Table 확인
    &amp;darr;
RAM에 있음
    &amp;darr;
정상 접근&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6822&quot; data-start=&quot;6779&quot; data-ke-size=&quot;size16&quot;&gt;반대로 Page Table에도 해당 페이지가 RAM에 없다고 표시되어 있다면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Page Fault&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;6855&quot; data-start=&quot;6848&quot; data-ke-size=&quot;size16&quot;&gt;가 발생한다.&lt;/p&gt;
&lt;p data-end=&quot;6855&quot; data-start=&quot;6848&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;6855&quot; data-start=&quot;6848&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Page Fault와 TLB Miss 차이&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 76px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;상황&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;TLB Hit&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;주소 변환 정보를 TLB에서 찾음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;TLB Miss&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;TLB에는 없어서 Page Table 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;Page Fault&lt;/td&gt;
&lt;td style=&quot;height: 19px;&quot;&gt;필요한 Page 자체가 RAM에 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6️⃣ 내부 단편화와 외부 단편화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이징은 고정 크기의 블록을 사용하기 때문에 &lt;b&gt;외부 단편화 문제를 크게 줄일 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;7484&quot; data-start=&quot;7435&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 Page 크기가 4KB인데 프로세스가 마지막 Page에서 1KB만 사용한다면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;4KB Page

┌──────────────┐
│ 사용 1KB     │
├──────────────┤
│ 낭비 3KB     │
└──────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7631&quot; data-start=&quot;7590&quot; data-ke-size=&quot;size16&quot;&gt;이것은 &lt;b&gt;내부 단편화(Internal Fragmentation)&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-end=&quot;7631&quot; data-start=&quot;7590&quot; data-ke-size=&quot;size16&quot;&gt;반면 메모리 공간이 이렇게 되어 있다고 해보자.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;사용 100MB
빈 공간 20MB
사용 50MB
빈 공간 30MB
사용 200MB&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;7769&quot; data-start=&quot;7720&quot; data-ke-size=&quot;size16&quot;&gt;전체 빈 공간은 50MB지만 연속된 40MB 공간이 필요하다면 배치하지 못할 수도 있다.&lt;/p&gt;
&lt;p data-end=&quot;7812&quot; data-start=&quot;7771&quot; data-ke-size=&quot;size16&quot;&gt;이것이 &lt;b&gt;외부 단편화(External Fragmentation)&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-end=&quot;7860&quot; data-start=&quot;7814&quot; data-ke-size=&quot;size16&quot;&gt;페이징은 페이지를 아무 Frame에나 배치할 수 있기 때문에 외부 단편화를 줄인다.&lt;/p&gt;
&lt;p data-end=&quot;7860&quot; data-start=&quot;7814&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-end=&quot;7860&quot; data-start=&quot;7814&quot; data-ke-size=&quot;size23&quot;&gt;7️⃣ Thrashing&lt;/h3&gt;
&lt;p data-end=&quot;7860&quot; data-start=&quot;7814&quot; data-ke-size=&quot;size16&quot;&gt;Page Fault가 지나치게 자주 발생하는 상황을 &lt;b&gt;Thrashing&lt;/b&gt;이라고 한다.&lt;/p&gt;
&lt;p data-end=&quot;7984&quot; data-start=&quot;7935&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 RAM에 실제로 필요한 작업 세트보다 적은 페이지밖에 올릴 수 없다고 해보자.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;필요한 Page

A B C D E

RAM에 올릴 수 있는 Page

A B&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8049&quot; data-start=&quot;8043&quot; data-ke-size=&quot;size16&quot;&gt;프로그램이:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;A &amp;rarr; B &amp;rarr; C &amp;rarr; D &amp;rarr; E &amp;rarr; A &amp;rarr; B ...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8100&quot; data-start=&quot;8094&quot; data-ke-size=&quot;size16&quot;&gt;를 반복하면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;C 필요
&amp;rarr; A 제거

D 필요
&amp;rarr; B 제거

A 필요
&amp;rarr; C 제거
...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8165&quot; data-start=&quot;8157&quot; data-ke-size=&quot;size16&quot;&gt;페이지를 계속:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Disk &amp;harr; RAM&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;8202&quot; data-start=&quot;8191&quot; data-ke-size=&quot;size16&quot;&gt;으로 교환하게 된다.&lt;/p&gt;
&lt;p data-end=&quot;8239&quot; data-start=&quot;8204&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로 &lt;b&gt;CPU보다 디스크 I/O에 대부분의 시간을 소비&lt;/b&gt;한다.&lt;/p&gt;</description>
      <category>CS</category>
      <author>KongJiHoon</author>
      <guid isPermaLink="true">https://kjhs-97.tistory.com/323</guid>
      <comments>https://kjhs-97.tistory.com/323#entry323comment</comments>
      <pubDate>Mon, 7 Sep 2026 20:44:24 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 Lv3 - 단어 변환</title>
      <link>https://kjhs-97.tistory.com/322</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;출처 : &lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43163&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/43163&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1788779092974&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43163&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/brFoA9/dJMb8RSbtcE/43GkYKa2KkdA5MVzOB8XzK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/vNch7/dJMb8UH8MGD/mK2I1pUeurkHmsyGb5jfv0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43163&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43163&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/brFoA9/dJMb8RSbtcE/43GkYKa2KkdA5MVzOB8XzK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/vNch7/dJMb8UH8MGD/mK2I1pUeurkHmsyGb5jfv0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1️⃣ 문제 요약&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작 단어 begin을 목표 단어 target으로 변환해야 한다. 단어를 변환할 때는 다음 조건을 만족해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;264&quot; data-start=&quot;136&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;161&quot; data-start=&quot;136&quot;&gt;한 번에 하나의 알파벳만 변경할 수 있다.&lt;/li&gt;
&lt;li data-end=&quot;198&quot; data-start=&quot;162&quot;&gt;변경한 단어는 반드시 words 배열 안에 존재해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;241&quot; data-start=&quot;199&quot;&gt;begin에서 target으로 변환하는 최소 횟수를 구해야 한다.&lt;/li&gt;
&lt;li data-end=&quot;264&quot; data-start=&quot;242&quot;&gt;변환할 수 없다면 0을 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;271&quot; data-start=&quot;266&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;begin = &quot;hit&quot;
target = &quot;cog&quot;

words = [&quot;hot&quot;, &quot;dot&quot;, &quot;dog&quot;, &quot;lot&quot;, &quot;log&quot;, &quot;cog&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;367&quot; data-ke-size=&quot;size16&quot;&gt;이라면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;hit &amp;rarr; hot &amp;rarr; dot &amp;rarr; dog &amp;rarr; cog&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;436&quot; data-start=&quot;413&quot; data-ke-size=&quot;size16&quot;&gt;총 4번 변환하므로 정답은 4가 된다.&lt;/p&gt;
&lt;p data-end=&quot;436&quot; data-start=&quot;413&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-end=&quot;436&quot; data-start=&quot;413&quot; data-ke-size=&quot;size20&quot;&gt;2️⃣ 문제 풀이&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 각 단어를 하나의 정점으로 생각하면 그래프 탐색 문제로 볼 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;559&quot; data-start=&quot;500&quot; data-ke-size=&quot;size16&quot;&gt;두 단어의 문자를 비교했을 때 &lt;b&gt;서로 다른 문자가 정확히 1개라면 이동 가능한 관계&lt;/b&gt;라고 볼 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;566&quot; data-start=&quot;561&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;hit
hot&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;595&quot; data-start=&quot;589&quot; data-ke-size=&quot;size16&quot;&gt;을 비교하면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;h == h
i != o
t == t&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;670&quot; data-start=&quot;631&quot; data-ke-size=&quot;size16&quot;&gt;서로 다른 문자가 1개이므로 hit &amp;rarr; hot으로 이동할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;670&quot; data-start=&quot;631&quot; data-ke-size=&quot;size16&quot;&gt;반면&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;hit
dot&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;h != d
i != o
t == t&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;764&quot; data-start=&quot;734&quot; data-ke-size=&quot;size16&quot;&gt;서로 다른 문자가 2개이므로 한 번에 변환할 수 없다.&lt;/p&gt;
&lt;p data-end=&quot;764&quot; data-start=&quot;734&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;764&quot; data-start=&quot;734&quot; 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-filename=&quot;스크린샷 2026-09-07 오후 8.07.29.png&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WRsrI/dJMcajwTRPc/yzla5HrBy3a2ozqo2S2EJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WRsrI/dJMcajwTRPc/yzla5HrBy3a2ozqo2S2EJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WRsrI/dJMcajwTRPc/yzla5HrBy3a2ozqo2S2EJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWRsrI%2FdJMcajwTRPc%2Fyzla5HrBy3a2ozqo2S2EJ0%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;693&quot; height=&quot;244&quot; data-filename=&quot;스크린샷 2026-09-07 오후 8.07.29.png&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서 구해야 하는 것은 begin에서 target까지의 &lt;b&gt;최소 변환 횟수&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;1018&quot; data-start=&quot;985&quot; data-ke-size=&quot;size16&quot;&gt;따라서 가까운 단어부터 순서대로 탐색하는 BFS를 사용했다.&lt;/p&gt;
&lt;p data-end=&quot;1018&quot; data-start=&quot;985&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1018&quot; data-start=&quot;985&quot; data-ke-size=&quot;size16&quot;&gt;BFS에서 현재 단어와 지금까지의 변환 횟수를 함께 저장하기 위해 Word 클래스를 하나 생성해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1788779308775&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Word {

    String word;
    int count;

    public Word(String word, int count) {
        this.word = word;
        this.count = count;
    }
}&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;먼저 시작 단어를 Queue에 넣는다. 최솟값을 구해야 하므로 Queue의 선입선출 구조를 활용하여 탐색할 때 Queue에서 단어를&lt;br /&gt;꺼내 비교하고 변경할 수 있는 문자를 Queue에 넣는 방식으로 반복한다.&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;현재 단어에서 이동할 수 있는 단어를 찾기 위해 words배열 전체를 확인한다.&lt;/p&gt;
&lt;pre id=&quot;code_1788779403957&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (int i = 0; i &amp;lt; words.length; i++) {

    if (visited[i]) {
        continue;
    }

    if (isCanChanged(cur.word, words[i])) {

        visited[i] = true;
        queue.offer(new Word(words[i], cur.count + 1));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 방문한 단어라면 다시 탐색할 필요가 없으므로 넘어간다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;if (visited[i]) {
    continue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2062&quot; data-start=&quot;2017&quot; data-ke-size=&quot;size16&quot;&gt;현재 단어와 후보 단어의 차이가 한 글자인 경우 다음 탐색 대상으로 큐에 넣는다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;queue.offer(new Word(words[i], cur.count + 1));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2161&quot; data-start=&quot;2125&quot; data-ke-size=&quot;size16&quot;&gt;단어 하나를 변환했으므로 기존 변환 횟수에서 1을 증가시킨다.&lt;/p&gt;
&lt;p data-end=&quot;2161&quot; data-start=&quot;2125&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2161&quot; data-start=&quot;2125&quot; data-ke-size=&quot;size16&quot;&gt;두 단어가 한글자만 다른지는 isCanChanged()메서드로 확인한다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;private boolean isCanChanged(String word, String target) {

    int diff = 0;

    for (int i = 0; i &amp;lt; word.length(); i++) {

        if (word.charAt(i) != target.charAt(i)) {
            diff++;
        }

        if (diff &amp;gt; 1) {
            return false;
        }

    }

    return diff == 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;import java.util.LinkedList;
import java.util.Queue;

class Solution {

    boolean[] visited;

    class Word {

        String word;

        int count;

        public Word(String word, int count) {
            this.word = word;
            this.count = count;
        }
    }

    public int solution(String begin, String target, String[] words) {

        Queue&amp;lt;Word&amp;gt; queue = new LinkedList&amp;lt;&amp;gt;();

        visited = new boolean[words.length];

        queue.offer(new Word(begin, 0));

        while (!queue.isEmpty()) {

            Word cur = queue.poll();


            if (cur.word.equals(target)) {
                return cur.count;
            }

            for (int i = 0; i &amp;lt; words.length; i++) {

                if (visited[i]) {
                    continue;
                }


                if (isCanChanged(cur.word, words[i])) {

                    visited[i] = true;
                    queue.offer(new Word(words[i], cur.count + 1));
                }

            }


        }


        return 0;
    }

    private boolean isCanChanged(String word, String target) {

        int diff = 0;

        for (int i = 0; i &amp;lt; word.length(); i++) {

            if (word.charAt(i) != target.charAt(i)) {
                diff++;
            }

            if (diff &amp;gt; 1) {
                return false;
            }

        }

        return diff == 1;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도는 단어의 개수를 N개, 각 단어의 길이를 L이라 하면, 한 단어를 탐색할 때, 최대 N개의 단어와 비교하고, 두 단어를 비교하는 데 최대 L번의 문자 비교가 필요하다.&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;따라서 전체 시간 복잡도는 O(N&amp;sup2;&amp;nbsp;&amp;times;&amp;nbsp;L)&lt;/p&gt;</description>
      <category>프로그래머스</category>
      <author>KongJiHoon</author>
      <guid isPermaLink="true">https://kjhs-97.tistory.com/322</guid>
      <comments>https://kjhs-97.tistory.com/322#entry322comment</comments>
      <pubDate>Mon, 7 Sep 2026 20:11:46 +0900</pubDate>
    </item>
  </channel>
</rss>