<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>K.Back-end</title>
    <link>https://developer-rabbit.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 12 Jul 2026 14:03:22 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>dbssk</managingEditor>
    <item>
      <title>[TS] 실시간 재고 동시성 문제</title>
      <link>https://developer-rabbit.tistory.com/275</link>
      <description>&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;h2 data-ke-size=&quot;size26&quot;&gt;동시성 문제&lt;/h2&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;h2 data-ke-size=&quot;size26&quot;&gt;테스트 시나리오&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예약 구매 상품 A가 있으며, 초기 재고 수량은 10개이다.&lt;/li&gt;
&lt;li&gt;해당 상품을 구매하려고 10000명의 사용자가 접근한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;결제 프로세스.png&quot; data-origin-width=&quot;3478&quot; data-origin-height=&quot;1984&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CBdMU/btsFm2xLY9I/5bzu3idOCJXfEUt8O1zwtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CBdMU/btsFm2xLY9I/5bzu3idOCJXfEUt8O1zwtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CBdMU/btsFm2xLY9I/5bzu3idOCJXfEUt8O1zwtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCBdMU%2FbtsFm2xLY9I%2F5bzu3idOCJXfEUt8O1zwtK%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;700&quot; height=&quot;399&quot; data-filename=&quot;결제 프로세스.png&quot; data-origin-width=&quot;3478&quot; data-origin-height=&quot;1984&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 상황에서 결제 화면에 진입하면 재고 수량을 감소시키고, 결제 프로세스 진행 중 어떠한 이유로 이탈한다면 재고 수량을 증가 시켜야 한다. 이때, 여러 쓰레드가 동시에 접근하면서 결제 완료된 재고 수량이 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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터베이스 락&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에 직접 Lock을 적용하는 방법으로 각 Lock 별로 적용되는 범위가 다르다.&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;Table Lock&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;테이블 단위로 Lock을 생성한다.&lt;/li&gt;
&lt;li&gt;READ 옵션을 사용하면 데이터를 읽을 수 있지만, CUD(Create, Update, Delete) 작업은 할 수 없다.&lt;/li&gt;
&lt;li&gt;WRITE 옵션을 사용하면 데이터에 대한 CRUD 작업이 불가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Row Level Lock&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;테이블의 데이터 row 단위로 Lock을 생성한다.&lt;/li&gt;
&lt;li&gt;상태 값으로 확인할 수 없으며, 락이 걸릴 경우 수정이 안되면 로우 레벨 락이 수행되었다고 판단한다.&lt;/li&gt;
&lt;li&gt;S LOCK 옵션은 공유 락을 설정하고, X LOCK 옵션은 배타적 락을 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Record Lock&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;인덱스가 존재할 경우 인덱스 테이블에 LOCK이 생성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Gap Lock&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조건에 해당하는 범위 내에서 비어있는 영역을 락하는 경우 생성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Next-Key Lock&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레코드 락 + 갭 락으로, 범위에 존재하는 데이터에는 '레코드 락'이 발생하고 존재하지 않는 범위에는 '갭 락'이 생성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 방법들로는 서비스 가용성을 확보하면서 동시성 제어를 직접 구현하기 힘들다는 단점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 제어할 수 있는 방법은 크게 쿼리를 작성하여 직접 LOCK을 제어하는 방법과, 애플리케이션 안에서 제어하는 방법이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;쿼리를 통한 동시성 제어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Shared Lock (S Lock)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 트랜잭션이 특정 자원에 공유 락을 설정하면, 다른 트랜잭션도 동일한 자원에 대한 읽기 작업을 허용한다.&lt;/li&gt;
&lt;li&gt;즉, 여러 트랜잭션이 동시에 해당 자원을 읽을 수 있지만, 쓰기 작업은 허용하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Exclusive Lock (X Lock)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 트랜잭션이 배타적 락을 설정하면, 다른 트랜잭션은 동시에 해당 자원을 읽거나 쓰지 못한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Intent Lock&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인텐트 락은 락의 의도를 나타내는 표시 역할로 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;애플리케이션을 통한 동시성 제어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;JPA를 사용한다면, LockMode.OPTIMISTIC 으로 낙관적 락을 구현할 수 있으며, Entity 객체에 @Version 필드가 있어야 한다.&lt;/li&gt;
&lt;li&gt;But, 동시성 제어를 낙관적 락으로 하기에는 한계가 있다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;충돌시 예외 처리를 직접 구현해야 한다.&lt;/li&gt;
&lt;li&gt;재시도를 해야한다면 DB I/O가 발생하여 부하가 증가한다.&lt;/li&gt;
&lt;li&gt;FK가 존재하는 테이블을 수정할 경우 데드락이 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;JPA를 사용한다면 LockMode.PESSIMSTIC으로 구현할 수 있으며,&amp;nbsp;다른 트랜잭션은 BLOCKING 된다.&lt;/li&gt;
&lt;li&gt;그래서 timeout을 설정하지 않으면 DB에 설정된 시간동안 다음 트랜잭션이 대기하게 된다.&lt;/li&gt;
&lt;li&gt;동시성을 확실히 보장할 수 있다. But, 요청이 Blocking 되어 성능이 저하될 수 있고, 여러 테이블에 Blocking이 된다면 데드락이 발생할 수 있다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;e.g. A가 테이블 a의 lock 획득, B가 테이블 b의 lock 획득, A가 테이블 b의 lock 획득 시도 (실패), B가 테이블 a의 lock 획득 시도 (실패)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;분산락&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;경쟁 상황(Race Condition)이 발생할 때, 데이터의 정합성을 지키기 위해 사용한다.&lt;/li&gt;
&lt;li&gt;Java에서는 'synchronized'라는 키워드를 통해 하나의 스레드만 접근할 수 있도록 동기화 기능을 제공하지만, 다중 서버에서는 synchronized 만으로 동시성 이슈를 해결할 수 없기 때문에 분산락을 사용한다.&lt;/li&gt;
&lt;li&gt;Redis, MySQL, Zookeeper 등을 이용해 구현할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis의 Redisson 라이브러리를 사용한 이유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Named Lock을 사용하기 위해서는 별도의 커넥션 풀을 관리해야 하고, 락에 관련된 부하를 RDBMS에서 받아야 하기 때문에 Redis가 더 효율적이라고 생각했다.&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;Redisson vs Lettuce&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redisson은 별도의 Lock Interface를 지원하기 때문에, 락을 설정할 수 있는 메서드를 사용하여 timeout 등을 쉽게 설정할 수 있다.&lt;/li&gt;
&lt;li&gt;Lettuce는 setnx, setex 명령어를 이용해 지속적으로 락이 해제되었는지 확인해야하는 스핀락 방식으로 동작하지만, Redisson은 Pub/Sub 방식을 이용하기 때문에 요청이 많아져도 Redis가 받는 부하가 커지지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redisson을 사용하기로 결정하고, 필요한 메서드 마다 lock을 적용하기 쉽도록 어노테이션 기반으로 &lt;b&gt;AOP&lt;/b&gt;를 이용해 분산락 컴포넌트를 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1709294878416&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface StockLock {
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1709294861261&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Aspect
@Component
@RequiredArgsConstructor
public class StockLockAspect {

  private final RedissonClient redissonClient;

  @Around(&quot;@annotation(com.nayoon.stock_service.common.lock.StockLock)&quot;)
  public Object applyStockLock(ProceedingJoinPoint joinPoint) throws Throwable {
    Long productId = (Long) joinPoint.getArgs()[0];

    RLock lock = redissonClient.getLock(String.format(&quot;stock:productId:%d&quot;, productId));
    try {
      boolean available = lock.tryLock(100, 10, TimeUnit.SECONDS);
      if (!available) {
        throw new RuntimeException(&quot;Failed to acquire lock for product: &quot; + productId);
      }
      return joinPoint.proceed();
    } finally {
      lock.unlock();
    }
  }

}&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;그리고 사용할 메서드 위에 @StockLock 어노테이션을 사용하면 해당 메서드에 Redisson이 적용된다.&lt;/p&gt;</description>
      <category>TIL/Trouble Shooting</category>
      <category>lettuce</category>
      <category>lock</category>
      <category>redisson</category>
      <category>분산락</category>
      <author>dbssk</author>
      <guid isPermaLink="true">https://developer-rabbit.tistory.com/275</guid>
      <comments>https://developer-rabbit.tistory.com/275#entry275comment</comments>
      <pubDate>Fri, 1 Mar 2024 20:52:13 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] Lowest  Common Ancestor</title>
      <link>https://developer-rabbit.tistory.com/258</link>
      <description>&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;Lowest Common Ancestor&lt;/h3&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 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;동작 순서&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;루트(root)부터 시작하여 두 대상 노드의 값을 비교합니다.&lt;/li&gt;
&lt;li&gt;현재 노드의 값이 두 대상 노드의 값보다 크면, LCA는 현재 노드의 왼쪽 서브트리에 있을 것입니다. 따라서 왼쪽 자식 노드로 재귀 호출합니다.&lt;/li&gt;
&lt;li&gt;현재 노드의 값이 두 대상 노드의 값보다 작으면, LCA는 현재 노드의 오른쪽 서브트리에 있을 것입니다. 따라서 오른쪽 자식 노드로 재귀 호출합니다.&lt;/li&gt;
&lt;li&gt;두 대상 노드의 값이 현재 노드의 값과 같거나, 현재 노드의 값이 두 대상 노드의 값 사이에 있으면, 현재 노드가 LCA가 됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;파이썬 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;다음은 이진 트리에서 두 노드의 Lowest Common Ancestor를 찾는 재귀적인 알고리즘의 예시 코드입니다:&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1708623219288&quot; class=&quot;reasonml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def find_lca(root, node1, node2):
    if root is None:
        return None
    
    if root.val &amp;gt; node1.val and root.val &amp;gt; node2.val:
        return find_lca(root.left, node1, node2)
    elif root.val &amp;lt; node1.val and root.val &amp;lt; node2.val:
        return find_lca(root.right, node1, node2)
    else:
        return root

# 예시 이진 트리 생성
#      6
#    /   \
#   2     8
#  / \   / \
# 0   4 7   9
#    / \
#   3   5
root = TreeNode(6)
root.left = TreeNode(2)
root.right = TreeNode(8)
root.left.left = TreeNode(0)
root.left.right = TreeNode(4)
root.right.left = TreeNode(7)
root.right.right = TreeNode(9)
root.left.right.left = TreeNode(3)
root.left.right.right = TreeNode(5)

node1 = TreeNode(0)
node2 = TreeNode(5)

# LCA 찾기
lca = find_lca(root, node1, node2)
print(&quot;Lowest Common Ancestor:&quot;, lca.val) # 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Computer Science/알고리즘</category>
      <author>dbssk</author>
      <guid isPermaLink="true">https://developer-rabbit.tistory.com/258</guid>
      <comments>https://developer-rabbit.tistory.com/258#entry258comment</comments>
      <pubDate>Fri, 9 Feb 2024 18:09:07 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] Morris Traversal</title>
      <link>https://developer-rabbit.tistory.com/252</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; letter-spacing: 0px;&quot;&gt;Morris Traversal for Preorder&lt;/span&gt;&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;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; letter-spacing: 0px;&quot;&gt;트리를 순회하는 데 사용되는 다양한 알고리즘이 있습니다. 그 중에서 Morris Traversal 알고리즘은 공간 복잡도를 O(1)로 유지하면서 순회할 수 있는 효율적인 방법으로 스택을 사용하지 않고도 &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Preorder &lt;/span&gt; Traversal를 수행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; letter-spacing: 0px;&quot;&gt;따라서 메모리 사용에 제약이 있는 환경이거나 공간 복잡도를 최소화해야 하는 상황에서 유용하게 사용될 수 있습니다. 또한 추가 데이터 구조 없이 순회해야 하는 경우에도 유용하게 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;동작 순서&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;현재 노드를 기준으로, 왼쪽 서브트리를 순회합니다.&lt;/li&gt;
&lt;li&gt;왼쪽 서브트리에서 현재 노드의 바로 이전 노드를 찾습니다.&lt;/li&gt;
&lt;li&gt;이전 노드의 오른쪽 자식을 현재 노드로 설정합니다.&lt;/li&gt;
&lt;li&gt;현재 노드를 방문합니다.&lt;/li&gt;
&lt;li&gt;현재 노드를 오른쪽 자식으로 이동합니다.&lt;/li&gt;
&lt;/ol&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;파이썬 예시&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Morris Traversal 알고리즘을 사용하여 이진 트리를 &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Preorder &lt;/span&gt;순회하는 예시 코드입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1708622487426&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def morris_preorder_traversal(root):
    current = root
    while current:
        if current.left is None:
            print(current.val)  # 현재 노드를 방문
            current = current.right
        else:
            # 왼쪽 서브트리에서 현재 노드의 바로 이전 노드를 찾음
            predecessor = current.left
            while predecessor.right and predecessor.right != current:
                predecessor = predecessor.right
            
            if predecessor.right is None:
                print(current.val)  # 현재 노드를 방문
                predecessor.right = current
                current = current.left
            else:
                predecessor.right = None
                current = current.right

# 예시 이진 트리 생성
#      1
#    /   \
#   2     3
#  / \   / \
# 4   5 6   7
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)
root.right.left = TreeNode(6)
root.right.right = TreeNode(7)

# Morris Traversal로 Preorder 순회하여 출력
print(&quot;Morris Preorder Traversal 결과:&quot;)
morris_preorder_traversal(root)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqjbah/btsFbUfRypt/TjpKnRihCuCjg5dcRpKxo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqjbah/btsFbUfRypt/TjpKnRihCuCjg5dcRpKxo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqjbah/btsFbUfRypt/TjpKnRihCuCjg5dcRpKxo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbqjbah%2FbtsFbUfRypt%2FTjpKnRihCuCjg5dcRpKxo1%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;500&quot; height=&quot;224&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;출처 :&lt;a style=&quot;color: #0070d1; text-align: start;&quot; href=&quot;https://www.geeksforgeeks.org/morris-traversal-for-preorder/&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/a&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/morris-traversal-for-preorder/&quot;&gt;https://www.geeksforgeeks.org/morris-traversal-for-preorder/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Computer Science/알고리즘</category>
      <author>dbssk</author>
      <guid isPermaLink="true">https://developer-rabbit.tistory.com/252</guid>
      <comments>https://developer-rabbit.tistory.com/252#entry252comment</comments>
      <pubDate>Sat, 20 Jan 2024 11:28:35 +0900</pubDate>
    </item>
    <item>
      <title>스프링 부트 디자인 패턴 (Spring Boot Design Patterns)</title>
      <link>https://developer-rabbit.tistory.com/251</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Design Pattern에 대한 스터디를 준비하다가 Medium 에서 좋은 글을 발견해서 정리해보려고 합니다.&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;a href=&quot;https://medium.com/stackademic/top-7-spring-boot-design-patterns-unveiled-4a2569f8d324&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/stackademic/top-7-spring-boot-design-patterns-unveiled-4a2569f8d324&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1704971135990&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Top 7 Spring Boot Design Patterns Unveiled&quot; data-og-description=&quot;Spring Boot, built on top of the Spring framework, incorporates various design patterns to enhance the development, scalability&amp;hellip;&quot; data-og-host=&quot;blog.stackademic.com&quot; data-og-source-url=&quot;https://medium.com/stackademic/top-7-spring-boot-design-patterns-unveiled-4a2569f8d324&quot; data-og-url=&quot;https://blog.stackademic.com/top-7-spring-boot-design-patterns-unveiled-4a2569f8d324&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b4xo6x/hyU2ko62YF/3wviFmqxfSrXrcJYpOdNs0/img.png?width=679&amp;amp;height=279&amp;amp;face=277_60_350_140,https://scrap.kakaocdn.net/dn/20VnC/hyU2mAtYvI/YhlRp2i6OVSPa5U6BBwcrK/img.png?width=1358&amp;amp;height=842&amp;amp;face=0_0_1358_842,https://scrap.kakaocdn.net/dn/IgQtZ/hyU2ePXX2R/matIrlhzohkJtl2Nlw4Fok/img.jpg?width=700&amp;amp;height=394&amp;amp;face=192_56_254_123&quot;&gt;&lt;a href=&quot;https://medium.com/stackademic/top-7-spring-boot-design-patterns-unveiled-4a2569f8d324&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/stackademic/top-7-spring-boot-design-patterns-unveiled-4a2569f8d324&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b4xo6x/hyU2ko62YF/3wviFmqxfSrXrcJYpOdNs0/img.png?width=679&amp;amp;height=279&amp;amp;face=277_60_350_140,https://scrap.kakaocdn.net/dn/20VnC/hyU2mAtYvI/YhlRp2i6OVSPa5U6BBwcrK/img.png?width=1358&amp;amp;height=842&amp;amp;face=0_0_1358_842,https://scrap.kakaocdn.net/dn/IgQtZ/hyU2ePXX2R/matIrlhzohkJtl2Nlw4Fok/img.jpg?width=700&amp;amp;height=394&amp;amp;face=192_56_254_123');&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;Top 7 Spring Boot Design Patterns Unveiled&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot, built on top of the Spring framework, incorporates various design patterns to enhance the development, scalability&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.stackademic.com&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;h2 data-ke-size=&quot;size26&quot;&gt;스프링 부트에서 여러 디자인 패턴들을 사용하는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 모듈화 및 재사용성&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;스프링 부트의 DI, AOP와 같은 패턴이 느슨한 결합을 구현하여 애플리케이션 전체에서 재사용할 수 있는 컴포넌트를 만듭니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 개발 단순화&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;스프링 부트에서는 데이터베이스 액세스, RESTful API, 보안 등과 같은 기능을 개발하는 것을 단순화하는 기능을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 유지보수 및 테스트&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MVC 패턴을 통해 개별 컴포넌트를 독립적으로 테스트할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 확장성 및 성능&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;팩토리 패턴과 같은 생성(creational) 패턴의 경우 객체 생성을 효율적으로 관리할 수 있게 도와줍니다.&lt;/li&gt;
&lt;li&gt;스프링 부트에서는 @Builder 어노테이션을 사용하여 쉽게 객체를 생성하고 값을 넣을 수 있는데 생성 패턴 중 하나인 Builder 패턴을 쉽게 사용할 수 있도록 구현되어 있는 것입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;70&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blhbTQ/btsDkxGEoDg/b71OtlqAkvVlwXUJkDveZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blhbTQ/btsDkxGEoDg/b71OtlqAkvVlwXUJkDveZ1/img.png&quot; data-alt=&quot;@Builder 어노테이션을 클릭하면 나오는 설명이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blhbTQ/btsDkxGEoDg/b71OtlqAkvVlwXUJkDveZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblhbTQ%2FbtsDkxGEoDg%2Fb71OtlqAkvVlwXUJkDveZ1%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;966&quot; height=&quot;70&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;70&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;@Builder 어노테이션을 클릭하면 나오는 설명이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 유연성과 확장성&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전략(strategy) 패턴을 적용하면 런타임에 알고리즘이나 구현을 선택할 수 있으므로 시스템이 변화에 더 잘 대처할 수 있습니다.&lt;/li&gt;
&lt;li&gt;스프링 부트 자체가 직접적으로 strategy 패턴을 사용하지는 않습니다.&lt;br /&gt;그러나 스프링 프레임워크는 IoC(Inversion of Control) 컨테이너를 기반으로 객체의 생성, 관리, 의존성 주입을 담당하는데, 의존성 주입(Dpendency Injection, DI)을 통해 객체 간의 결합도를 낮추고 유연성을 확보할 수 있습니다.&lt;br /&gt;DI 구현 방식중 하나로 스프링 프레임워크는 빈(Bean)을 등록하고 이를 조립할 때 일종의 전략을 사용합니다.&lt;br /&gt;또한, 스프링 부트는 프로퍼티 설정, 프로파일, 컨버터 등 다양한 기능에서도 전략 패턴을 활용하여 유연성을 부여합니다.&lt;br /&gt;그러므로 스프링 부트는 전반적으로 IoC 및 다양한 기능에서 전략 패턴의 원리를 적용하고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 표준화&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;5번에서 설명한 IoC를 사용하여 일관된 방식으로 빈을 관리하고 의존성을 주입할 수 있게 해주며, 이는 모든 개발자들에게 표준화된 구조를 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 협업&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;/ul&gt;</description>
      <category>Spring</category>
      <category>DesignPattern</category>
      <category>springboot</category>
      <category>디자인패턴</category>
      <category>스프링부트</category>
      <author>dbssk</author>
      <guid isPermaLink="true">https://developer-rabbit.tistory.com/251</guid>
      <comments>https://developer-rabbit.tistory.com/251#entry251comment</comments>
      <pubDate>Thu, 11 Jan 2024 21:08:54 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스][Lv.2][Java][DP] 2xn 타일링</title>
      <link>https://developer-rabbit.tistory.com/250</link>
      <description>&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;div style=&quot;background-color: #ffffff; color: #263747; text-align: left;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12900&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12900&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1703284364524&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;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12900&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dBpdYV/hyUTE0HaKz/Xnz0cYWgiNK1Q1dzkmOW1K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bo8gJy/hyUTBv791i/XMqka9qBsRCdvrtOhAxXtK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12900&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12900&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dBpdYV/hyUTE0HaKz/Xnz0cYWgiNK1Q1dzkmOW1K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bo8gJy/hyUTBv791i/XMqka9qBsRCdvrtOhAxXtK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 설명&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #263747; text-align: left;&quot;&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;가로 길이가 2이고 세로의 길이가 1인 직사각형모양의 타일이 있습니다. 이 직사각형 타일을 이용하여 세로의 길이가 2이고 가로의 길이가 n인 바닥을 가득 채우려고 합니다. 타일을 채울 때는 다음과 같이 2가지 방법이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit; color: #000000;&quot;&gt;타일을 가로로 배치 하는 경우&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit; color: #000000;&quot;&gt;타일을 세로로 배치 하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;예를들어서 n이 7인 직사각형은 다음과 같이 채울 수 있습니다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBy970/btsCwgMU9GA/O5oMtcJciGku1x1qBkOFK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBy970/btsCwgMU9GA/O5oMtcJciGku1x1qBkOFK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBy970/btsCwgMU9GA/O5oMtcJciGku1x1qBkOFK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBy970%2FbtsCwgMU9GA%2FO5oMtcJciGku1x1qBkOFK1%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;430&quot; height=&quot;126&quot; data-origin-width=&quot;430&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;직사각형의 가로의 길이 n이 매개변수로 주어질 때, 이 직사각형을 채우는 방법의 수를 return 하는 solution 함수를 완성해주세요.&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;b&gt;제한사항&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit; color: #000000;&quot;&gt;가로의 길이 n은 60,000이하의 자연수 입니다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit; color: #000000;&quot;&gt;경우의 수가 많아 질 수 있으므로, 경우의 수를 1,000,000,007으로 나눈 나머지를 return해주세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;풀이&lt;/h3&gt;
&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot_20231223_072530_Samsung Notes.jpg&quot; data-origin-width=&quot;1627&quot; data-origin-height=&quot;1237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v15yw/btsCAj8Ityy/zXgTqlMRXxTeHKRbAN00k0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v15yw/btsCAj8Ityy/zXgTqlMRXxTeHKRbAN00k0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v15yw/btsCAj8Ityy/zXgTqlMRXxTeHKRbAN00k0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv15yw%2FbtsCAj8Ityy%2FzXgTqlMRXxTeHKRbAN00k0%2Fimg.jpg&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;1627&quot; height=&quot;1237&quot; data-filename=&quot;Screenshot_20231223_072530_Samsung Notes.jpg&quot; data-origin-width=&quot;1627&quot; data-origin-height=&quot;1237&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1703284414189&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    public int solution(int n) {
        int[] dp = new int[n + 1];
        Arrays.fill(dp, -1);
        return countCombinations(n, dp);
    }
    
    private int countCombinations(int remaining, int[] dp) {
        if (remaining &amp;lt; 0) {
            return 0;
        }
        
        if (remaining == 0) {
            return 1;
        }
        
        // 이미 계산된 값이 있는 경우
        if (dp[remaining] != -1) {
            return dp[remaining];
        }
        
        // 계산된 값이 없는 경우 재귀 -&amp;gt; 1을 사용한 경우 + 2를 사용한 경우
        dp[remaining] = countCombinations(remaining -1, dp) + countCombinations(remaining -2, dp);
        dp[remaining] %= 1000000007;
        return dp[remaining];
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;시간 복잡도&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(n)&lt;/p&gt;</description>
      <category>Programmers/Lv.2</category>
      <category>dp</category>
      <category>java</category>
      <category>LV.2</category>
      <category>동적계획법</category>
      <category>프로그래머스</category>
      <author>dbssk</author>
      <guid isPermaLink="true">https://developer-rabbit.tistory.com/250</guid>
      <comments>https://developer-rabbit.tistory.com/250#entry250comment</comments>
      <pubDate>Sat, 23 Dec 2023 07:47:01 +0900</pubDate>
    </item>
    <item>
      <title>[TIL][Spring] javax.xml.bind.DatatypeConverter 에러</title>
      <link>https://developer-rabbit.tistory.com/248</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt; 문제&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;OAuth2 로그인 구현 중 아래와 같은 에러 발생&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;981&quot; data-origin-height=&quot;50&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uOP85/btsClI3TpGv/1zjNjNVz4iB82nMXnR7bL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uOP85/btsClI3TpGv/1zjNjNVz4iB82nMXnR7bL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uOP85/btsClI3TpGv/1zjNjNVz4iB82nMXnR7bL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuOP85%2FbtsClI3TpGv%2F1zjNjNVz4iB82nMXnR7bL0%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;981&quot; height=&quot;50&quot; data-origin-width=&quot;981&quot; data-origin-height=&quot;50&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;❗원인&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;38&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NPXbQ/btsCq628sXi/f6pkGpzElGvdHKJ38ASrVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NPXbQ/btsCq628sXi/f6pkGpzElGvdHKJ38ASrVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NPXbQ/btsCq628sXi/f6pkGpzElGvdHKJ38ASrVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNPXbQ%2FbtsCq628sXi%2Ff6pkGpzElGvdHKJ38ASrVK%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;1055&quot; height=&quot;38&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;38&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같은 에러메세지가 있었다. 해당 코드는 아래와 같이 생겼다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SdEHu/btsCr8zBPVI/Vf25UKjM70W8Kke64MRrmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SdEHu/btsCr8zBPVI/Vf25UKjM70W8Kke64MRrmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SdEHu/btsCr8zBPVI/Vf25UKjM70W8Kke64MRrmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSdEHu%2FbtsCr8zBPVI%2FVf25UKjM70W8Kke64MRrmk%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;932&quot; height=&quot;437&quot; data-origin-width=&quot;932&quot; data-origin-height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉, 'io.jsonwebtoken.impl.Base64Codec' 클래스에서 'DatatypeConverter' 클래스를 사용해야하는데 해당 클래스룰 찾지 못해 에러가 발생하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt; 해결방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@jiri.caga/java-lang-classnotfoundexception-javax-xml-bind-datatypeconverter-in-java-17-solved-499d0ea776d0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@jiri.caga/java-lang-classnotfoundexception-javax-xml-bind-datatypeconverter-in-java-17-solved-499d0ea776d0&lt;/a&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 11 이상에서 JAXB가 JDK에서 제거되었다고 한디. 그러면서 해결방법으로 간단하게 의존성을 추가하라고 되어있어 아래 코드를 추가하였고 OAuth2 로그인이 잘 되는 것도 확인하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1703137296827&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// jaxb
implementation 'javax.xml.bind:jaxb-api:2.3.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;+ java 17, 'io.jsonwebtoken:jjwt:0.9.1' 버전을 사용하였습니다.&lt;/p&gt;</description>
      <category>TIL</category>
      <category>spring</category>
      <category>TIL</category>
      <author>dbssk</author>
      <guid isPermaLink="true">https://developer-rabbit.tistory.com/248</guid>
      <comments>https://developer-rabbit.tistory.com/248#entry248comment</comments>
      <pubDate>Thu, 21 Dec 2023 14:42:31 +0900</pubDate>
    </item>
    <item>
      <title>[TIL][SQL] @Modifying 어노테이션</title>
      <link>https://developer-rabbit.tistory.com/246</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;❓@Modifying 어노테이션이란?&lt;/h2&gt;
&lt;pre id=&quot;code_1699415915575&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Modifying(clearAutomatically = true, flushAutomatically = true)
@Transactional
@Query(&quot;UPDATE Restaurant r SET r.averageRating = :averageRating WHERE r.id = :restaurantId&quot;)
void updateAverageRating(@Param(&quot;restaurantId&quot;) Long restaurantId, @Param(&quot;averageRating&quot;) double averageRating);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수정 쿼리를 수행하는 메서드에 붙인다.&lt;/li&gt;
&lt;li&gt;JPA에서 SLECT 쿼리가 아닌 UPDATE, DELETE, INSERT 등과 같은 수정 작업을 수행하는 메서드에 대한 표시&lt;/li&gt;
&lt;li&gt;clearAutomatically : 수정 쿼리 실행 후 영속성 컨텍스트를 자동으로 초기화하여 변경된 엔티티에 대한 변경사항을 DB에서 가져오도록 한다.&lt;/li&gt;
&lt;li&gt;flushAutomatically : 쿼리 실행 전에 영속성 컨텍스트를 flush하여 변경 사항을 DB에 동기화한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt; if @Modifying을 사용하지 않는다면?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring Data JPA는 updateAverageRating 메서드를 조회 쿼리로 간주하고 트랜잭션을 관리하지 않을 것이다.&lt;/li&gt;
&lt;li&gt;따라서 업데이트가 발생할 때, 트랜잭션 관리 및 데이터베이스 변경 사항 플러싱을 수동으로 해줘야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL</category>
      <category>jpa</category>
      <category>Modifying</category>
      <category>sql</category>
      <category>update</category>
      <author>dbssk</author>
      <guid isPermaLink="true">https://developer-rabbit.tistory.com/246</guid>
      <comments>https://developer-rabbit.tistory.com/246#entry246comment</comments>
      <pubDate>Wed, 8 Nov 2023 12:58:42 +0900</pubDate>
    </item>
    <item>
      <title>[TIL][SQL] 연관 데이터 없을 때 조회하기 (Join vs Left Join)</title>
      <link>https://developer-rabbit.tistory.com/245</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt; 문제&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;주 테이블의 상세 정보를 가져오는 코드에서 연관 데이터가 없으면 주 테이블의 정보도 반환되지 않는 문제 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;❗원인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;주 테이블 id로 연관 테이블을 조회할 때 join을 사용&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Query(&quot;SELECT r FROM Restaurant r join fetch r.ratingList WHERE r.id = :id&quot;)
Optional&amp;lt;Restaurant&amp;gt; findByIdWithRatingsUsingFetchJoin(@Param(&quot;id&quot;) Long id);

default Restaurant getById(Long id) {
	return findByIdWithRatingsUsingFetchJoin(id)
				.orElseThrow(() -&amp;gt; new CustomException(ErrorCode.NOT_FOUND));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt; 해결방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;left join을 사용하자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Join&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;일반적으로 &lt;b&gt;Inner Join&lt;/b&gt;을 수행&lt;/li&gt;
&lt;li&gt;만약 주 테이블(&amp;rsquo;&lt;b&gt;Restaurant&lt;/b&gt;&amp;rsquo;)과 연결 테이블(&amp;rsquo;&lt;b&gt;Rating&lt;/b&gt;&amp;rsquo;)사이에 일치하는 데이터가 없을 경우, 해당 주 테이블의 레코드는 결과 집합에서 제외&lt;/li&gt;
&lt;li&gt;이로 인해 &amp;lsquo;&lt;b&gt;Restaurant&lt;/b&gt;&amp;rsquo;가 &amp;lsquo;&lt;b&gt;ratingList&lt;/b&gt;&amp;rsquo;와 관련된 데이터가 없는 경우 &amp;lsquo;NoResultException&amp;rsquo; 또는 비어있는 결과가 발생할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Left Join&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&amp;lsquo;&lt;b&gt;Restaurant&lt;/b&gt;&amp;rsquo;와 &amp;lsquo;&lt;b&gt;Rating&lt;/b&gt;&amp;rsquo; 사이에 일치하는 데이터가 없더라도 주 테이블(&amp;rsquo;&lt;b&gt;Restaurant&lt;/b&gt;&amp;rsquo;)의 레코드는 결과 집합에 포함&lt;/li&gt;
&lt;li&gt;&amp;lsquo;&lt;b&gt;Rating&lt;/b&gt;&amp;rsquo;과 관련된 데이터가 없는 경우, &amp;lsquo;&lt;b&gt;Rating&lt;/b&gt;&amp;rsquo; 엔티티 관련 부분은 &amp;lsquo;&lt;b&gt;null&lt;/b&gt;&amp;rsquo;로 설정됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &amp;lsquo;&lt;b&gt;join&lt;/b&gt;&amp;rsquo;을 사용하면 연결된 데이터가 없을 때 결과가 발생하지 않고, &amp;lsquo;&lt;b&gt;left join&lt;/b&gt;&amp;rsquo;을 사용하면 연결된 데이터가 없더라도 주 테이블(&amp;rsquo;Restaurant&amp;rsquo;)의 데이터는 반환된다.&lt;/p&gt;</description>
      <category>TIL</category>
      <category>join</category>
      <category>LEFTJOIN</category>
      <category>sql</category>
      <author>dbssk</author>
      <guid isPermaLink="true">https://developer-rabbit.tistory.com/245</guid>
      <comments>https://developer-rabbit.tistory.com/245#entry245comment</comments>
      <pubDate>Wed, 8 Nov 2023 12:41:26 +0900</pubDate>
    </item>
    <item>
      <title>[OS] 프로세스 (Process)</title>
      <link>https://developer-rabbit.tistory.com/244</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로세스 (Process)&lt;/h2&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;HDD/SDD에 있던 프로그램이 인스턴스화되어 메모리(RAM)에 올라가면 프로세스가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로세스 상태 (Process State)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;states_modified.png&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;483&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/states-of-a-process-in-operating-systems/&quot; target=&quot;_blank&quot; title=&quot;GeeksForGeeks&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuYYdz/btsyMzHHBgl/HvcUi9VhiPfTyPnmuVakX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuYYdz%2FbtsyMzHHBgl%2FHvcUi9VhiPfTyPnmuVakX1%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;856&quot; height=&quot;483&quot; data-filename=&quot;states_modified.png&quot; data-origin-width=&quot;856&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;New(=Create) : 생성 상태&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;프로세스가 생성된 상태 (이지만 아직 메인 메모리에 올라가지는 않았다.)&lt;/li&gt;
&lt;li&gt;fork() 또는 exec() 함수를 통해 생성되며, 이때, PCB가 할당된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;fork() : 부모 프로세스의 주소 공간을 그대로 복사하여, 새로운 자식 프로세스를 생성한다.&lt;br /&gt;exec() : 새롭게 프로세스를 생성한다.&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Ready : 대기 상태&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;메인 메모리 공간에 로드되어 CPU에서 실행을 기다리고 있는 상태&lt;/li&gt;
&lt;li&gt;Dispatcher 또는 Short-term scheduler에 의해 CPU로 컨텍스트 스위칭되기를 기다리는 상태&lt;/li&gt;
&lt;li&gt;대기하는 프로세스는 여러 개 일 수 있으며, 이를 관리하기 위해 Ready queue 또는 Run queue 가 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;다른 이벤트가 발생하기를 기다리는 프로세스(정보 로드 또는 인터넷 연결을 기다리는 경우)는 Ready queue에 포함되지 않는다.&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Ready Suspended : 대기 중단 상태&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;메모리 부족으로 일시 중단된 상태&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Running : 실행 상태&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;CPU에서 프로세스의 명령어가 실행되는 상태&lt;/li&gt;
&lt;li&gt;해당 프로세스는 커널 모드 또는 사용자 모드 중 하나에서 실행될 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널 모드&lt;/b&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;사용자 모드에서 system call이 발생하면 커널 모드로 전환된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용자 모드&lt;/b&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;그러나 운영 체제에 system call을 통해 서비스를 요청하면, 시스템은 사용자 모드에서 커널 모드로 전환하여 요청을 수행한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;각 프로세스에 대한 가상 주소 공간이 있어 다른 프로세스에 영향을 미치지 않는다.&lt;/li&gt;
&lt;li&gt;하드웨어 장치에 직접 액세스하는 것이 허용되지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;a href=&quot;https://developer-rabbit.tistory.com/entry/OS-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EC%BD%9C-System-Call&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;시스템 콜이란?&lt;/a&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Blocked(=Waiting) : 중단 상태&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;외부 상태 변경 또는 특정 이벤트 발생을 기다리는 상태&lt;/li&gt;
&lt;li&gt;&lt;b&gt;I/O 대기&lt;/b&gt; : 외부 I/O 장치(ex. 하드 디스크, 프린터 등)와 상호작용해야 하는 경우, 그 장치가 사용중이거나 사용 불가능한 경우에는 프로세스가 중단될 수 있다. 이때, 프로세스는 해당 I/O 작업이 완료될 때까지 기다리며 다른 작업을 수행하지 않는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용자 입력 대기&lt;/b&gt; : 프로세스가 사용자로부터 특정 입력을 기다리는 경우, 입력이 발생할 때까지 중단된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;임계 영역 진입 대기&lt;/b&gt; : 프로세스가 공유 데이터나 리소스에 접근해야 하는데 해당 리소스가 다른 프로세스에 의해 사용 중인 경우, 프로세스가 중단될 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시스템 호출 대기&lt;/b&gt; : 프로세스가 운영 체제의 특정 서비스 또는 기능을 사용하려면, system call을 통해 운영 체제에 요청을 보내야하는데, 이때 프로세스는 system call의 완료를 기다리며 중단된다.&lt;/li&gt;
&lt;li&gt;이벤트가 발생하거나 입출력 작업이 완료되면 &lt;b&gt;Ready&lt;/b&gt; 상태로 전환된다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Blocked Suspended : 일시 중단 상태&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Blocked 상태에서 프로세스가 실행되려고 했지만 메모리 부족으로 일시 중단된 상태&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Terminated : 종료 상태&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;프로세스의 실행이 완료되어 종료된 상태&lt;/li&gt;
&lt;li&gt;부모 프로세스가 자식 프로세스를 강제로 종료시키는 경우도 있다.&lt;/li&gt;
&lt;li&gt;운영체제는 프로세스의 자원을 해제하고 PCB를 제거하여 메모리 공간을 회수한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로세스 주소 공간(=메모리 구조)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 프로세스는 독립된 메모리 공간을 할당 받는데 4가지 부분으로 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;program_in_memory2.webp&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;475&quot;&gt;&lt;a href=&quot;https://gabrieletolomei.wordpress.com/miscellanea/operating-systems/in-memory-layout/&quot; target=&quot;_blank&quot; title=&quot;Garbriele Tolomei&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dG07b9/btsyNosqbQ6/haDIKJmoKk7Ol5RNxWMKAK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdG07b9%2FbtsyNosqbQ6%2FhaDIKJmoKk7Ol5RNxWMKAK%2Fimg.webp&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;500&quot; height=&quot;475&quot; data-filename=&quot;program_in_memory2.webp&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;475&quot;/&gt;&lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Text (Code segment)&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;프로세스의 실행 가능한 코드가 저장되는 영역&lt;/li&gt;
&lt;li&gt;공유 가능하며, 자주 실행되는 프로그램에 대해 메모리에 하나의 복사만 유지한다.&lt;/li&gt;
&lt;li&gt;일반적으로 읽기/실행 전용이다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Data (BSS segment, Data segment)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;전역 변수, 정적 변수, 상수 등 초기화된 데이터가 저장되는 영역&lt;/li&gt;
&lt;li&gt;프로세스의 실행 도중에 값이 변경될 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BSS segment&amp;nbsp;&lt;/b&gt;: 실행 시작 전에 0으로 초기화 또는 어떠한 값으로도 초기화 되어 있지 않은 변수가 저장되는 영역&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Data segment&amp;nbsp;&lt;/b&gt;: 0이 아닌 값으로 초기화 된 변수가 저장되는 영역&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Heap&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;프로그램 실행 중에 동적으로 할당된 변수들을 관리하는 영역&lt;/li&gt;
&lt;li&gt;주로 동적으로 생성된 데이터 구조나 객체가 저장된다. (ex. vector, linked list, hash, priority queue, etc)&lt;/li&gt;
&lt;li&gt;malloc()/free() 함수를 통해 관리되며, 시스템 호출(brk() 및 sbrk())를 사용하여 크기를 조절할 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Stack&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;지역 변수, 매개변수, 함수 호출 정보, 임시 데이터 등 함수 호출에 필요한 모든 데이터를 저장하는 영역으로 동적 할당된다.&lt;/li&gt;
&lt;li&gt;각 함수 호출에 대한 스택 프레임이 생성되며, 매개변수, 복귀 주소, 지역 변수 등이 포함된다.&lt;/li&gt;
&lt;li&gt;스택 포인터 레지스터가 스택의 최상위를 추적하며, 스택이 힙 포인터와 만나거나 RLIMIT_STACK에 지정된 한계에 도달하면 사용 가능한 여유 메모리가 소진된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;PCB (Process Control Block)&lt;/h2&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;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;메타데이터란?&lt;br /&gt;데이터에 대한 데이터로 정보의 특성, 구조, 특징 또는 다른 데이터 요소를 설명하거나 식별하는 정보를 의미한다.&lt;br /&gt;주어진 데이터 집합을 분석하고 관리하는 데 도움을 주며, 데이터를 효과적으로 이해, 조직 및 활용하는데 필수적이다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PCB의 구조&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;프로세스 식별자(Process Id)&amp;nbsp;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;각 프로세스에는 고유한 식별자가 할당된다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스를 식별하고 구분하기 위해 사용&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;만약 자식 프로세스가 있다면 자식 프로세스 ID도 저장된다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;프로세스 상태(Process State)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스의 현재 상태를 나타낸다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;new(create), ready, running, waiting(blocked), terminated가 있다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;스케줄링 및 운영체제의 상태 관리에 사용&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;프로그램 카운터(Program Counter)&amp;nbsp;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;현재 프로세스가 다음에 실행할 명령어의 주소를 가리키는 레지스터 값&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스가 중단되었다가 다시 실행될 때, 이전 상태로 복원하기 위해 필요하다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;레지스터(Registers)&amp;nbsp;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스의 레지스터 값들을 저장한다. 레지스터에는 프로세스의 실행 상태와 관련된 정보가 포함된다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;ex) 범용 레지스터, 스택 포인터, 프로그램 상태 레지스터 등의 값&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스 상태 전환이나 중단/복원 시에 레지스터 값을 유지하기 위해 필요하다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;스케줄링 정보(Scheduling Information)&amp;nbsp;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스의 우선순위, 스케줄링 알고리즘에 필요한 정보 등을 저장한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;스케줄링 알고리즘이 결정되는 데 사용되며, 운영체제가 프로세스를 효율적으로 관리할 수 있도록 도와준다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;메모리 관리 정보(Memory Related Information)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스의 메모리 할당과 관련된 메모리 영역의 범위, 페이지 테이블, 세그먼트 테이 등의 정보를 저장한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;메모리 관련 유틸리티가 메모리 할당 및 해제를 관리하는 데 사용&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;계정 정보(Accounting Information)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스와 관련된 계정 정보를 저장한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;ex) CPU 사용량, 실행 시간, 입출력 작업 통계 등&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;이러한 정보는 성능 모니터링, 로그 기록, 자원 사용 축적 등에 사용된다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;I/O 관련 상태 정보(Status Information related to I/O)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스와 관련된 입출력 장치의 상태 정보를 저장한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;ex) 현재 열린 파일, I/O 대기열, 입출력 상태 등&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;입출력 작업 관리와 관련된 운영체제 기능을 지원하기 위해 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PCB 사용&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Context Switching (컨텍스트 스위칭)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #353638;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;다중 프로세스 환경에서 CPU가 한 프로세스에서 다른 프로세스로 전환하는 과정&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #353638;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #353638;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Context Switching이 발생하는 상황&lt;/span&gt;&lt;/span&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;&lt;b&gt;프로세스 스케줄링&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;현재 실행 중인 프로세스를 중지하고 다른 프로세스를 실행해야 하는 경우&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer-rabbit.tistory.com/entry/OS-%EC%9D%B8%ED%84%B0%EB%9F%BD%ED%8A%B8Interrupt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;인터럽트&lt;/b&gt;&lt;/a&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;현재 실행 중인 프로세스를 중지하고 인터럽트 처리를 위한 다른 프로세스를 실행해야 하는 경우&lt;/li&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Context Switching 과정&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;현재 실행 중인 프로세스/스레드의 상태 저장&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 현재 실행 중인 프로세스/스레드의 레지스터 값, 프로그램 카운터, 상태 정보 등을 해당 프로세스의 PCB에 저장&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;다음 실행할 프로세스/스레드 정보 로드&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 다음으로 실행할 프로세스/스레드의 PCB에서 해당 프로세스의 레지스터 값, 프로그램 카운터, 상태 정보 등을 CPU에 로드&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;프로세스/스레드 상태 전환&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 현재 실행 중인 프로세스/스레드를 waiting 상태로 전환하고, 다음으로 실행할 프로세스/스레를 ready 또는 running 상태로 전환&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot;&gt;&lt;b&gt;이전 프로세스/스레 복원&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 컨텍스트 스위칭이 완료되면 CPU는 다음에 실행할 프로세스/스레드로 이동하고, 해당 작업의 프로그램 카운터(PC) 값부터 실행을 재개&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Context Switching 비용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;비용 = 컨텍스트 스위칭이 일어날 때 발생하는 유휴 시간(idle time)과 캐시미스&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스가 스레드보다 많이 든다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;스레드는 stack을 제외한 모든 메모리를 공유하기 때문에 컨텍스트 스위칭이 일어나도 stack 영역만 변경하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;캐시미스란?&lt;br /&gt;CPU의 캐시 메모리에서 필요한 데이터나 명령어를 찾을 수 없는 상황&lt;br /&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;2. 메모리와 CPU 레지스터 간 정보 전환&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대기 중이거나 준비 중인 프로세스의 PCB는 메모리에 유지된다. 그리고 해당 프로세스가 실행되기 위해 선택되면 PCB의 정보가 CPU 레지스터로 올라간다.&lt;/li&gt;
&lt;li&gt;즉, ready/waiting &amp;rarr; 메모리, running &amp;rarr; CPU 레지스터에 위치한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PCB 관리 방식&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;일반적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;주기억장치(RAM)&lt;/b&gt;에 저장되며, 각 프로세스마다 PCB가 할당되고 주소를 통해 연결리스트 형태로 관리된다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;PCB List Head&lt;/b&gt;에 PCB들이 생성될 때마다 연결 리스트에 추가된다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;연결 리스트는 PCB의 주소를 통해 각 PCB가 연결되어 있어, PCB의 삽입 및 삭제 작업이 용이하다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스가 생성되면 해당 프로세스에 대한 PCB가 생성되고, 프로세스가 종료되면 해당 PCB는 제거된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;멀티프로세스&lt;/h2&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;한 번에 많은 서로 다른 작업을 처리할 때 사용 (ex. 웹 서버에서 여러 요청을 동시에 처리)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Context Switching이 발생하면 캐시에 존재하는 모든 데이터를 리셋하고 다시 캐시 정보를 불러와야 한다. 즉, Context Switching의 오버헤드가 커서 비용이 크다.&lt;/li&gt;
&lt;li&gt;프로세스 간의 통신에 복잡한 IPC를 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;IPC (Inter Process Communication)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스는 독립적으로 실행되므로 다른 프로세스와 통신을 위해 운영체제의 커널 영역에서 IPC 기능을 제공한다.&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;IPC 종류&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 공유 메모리 (Shared Memory)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 프로세스가 동일한 메모리 영역에 접근할 수 있게하는 것&lt;/li&gt;
&lt;li&gt;프로세스가 커널에 공유 메모리 할당을 요청하면, 커널은 해당 프로세스에 메모리 공간을 할당해 주며, 이후 어떤 프로세스든 해당 메모리 영역에 접근할 수 있다.&lt;/li&gt;
&lt;li&gt;중개자(메시지 큐의 큐) 없이 바로 메모리에 접근할 수 있기 때문에 IPC 중에 가장 빠르다.&lt;/li&gt;
&lt;li&gt;그러나 동일한 메모리 영역을 여러 프로세스가 공유하기 때문에 동기화가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 소켓&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스 간의 네트워크 통신을 위해 사용되는 방식&lt;/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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 익명 파이프 (Anonnymous PIPE)&lt;br /&gt;&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;img1.daumcdn.png&quot; data-origin-width=&quot;328&quot; data-origin-height=&quot;61&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsZbCC/btsyHyKBDR2/hKxZPdPCQqXWob90C2inR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsZbCC/btsyHyKBDR2/hKxZPdPCQqXWob90C2inR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsZbCC/btsyHyKBDR2/hKxZPdPCQqXWob90C2inR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsZbCC%2FbtsyHyKBDR2%2FhKxZPdPCQqXWob90C2inR0%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;500&quot; height=&quot;93&quot; data-filename=&quot;img1.daumcdn.png&quot; data-origin-width=&quot;328&quot; data-origin-height=&quot;61&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이파는 두 개의 프로세스를 연결&amp;nbsp;&lt;/li&gt;
&lt;li&gt;하나의 프로세스는 데이터를 쓰기만, 다른 하나는 읽기만 할 수 있다. (FIFO)&lt;/li&gt;
&lt;li&gt;한 쪽 방향으로만 통신이 가능하기 때문에&amp;nbsp;&lt;b&gt;단방향 통신&lt;/b&gt; 또는&amp;nbsp;&lt;b&gt;Half-Duplex(반이중) 통신&lt;/b&gt;이라고 한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 명명된 파이프 (Named PIPE)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;Named Pipe는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;부모 프로세스와 관계없이&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;다른 프로세스 간에 통신 및 다른 네트워크상의 컴퓨터와도 통신이 가능하다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;파일 시스템에 특정 이름을 부여하여 다른 프로세스가 해당 이름을 통해 파이프에 접근할 수 있다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;Named PIPE도 PIPE와 같이 읽기/쓰기가 동시에 가능하지 않다. 하지만 통신선로가 파일로 존재하므로 하나를 읽기 전용으로 열고 다른 하나를 쓰기 전용으로 열어서 &lt;b&gt;전이중 통신&lt;/b&gt;을 구현할 수 있다. 결국 PIPE와 같이 두 개의 FIFO 파일이 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 메시지 큐&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;img1.daumcdn.jpg&quot; data-origin-width=&quot;475&quot; data-origin-height=&quot;84&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tGAgS/btsyJypxzr9/lteClh2LdWk4toAaezsXxK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tGAgS/btsyJypxzr9/lteClh2LdWk4toAaezsXxK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tGAgS/btsyJypxzr9/lteClh2LdWk4toAaezsXxK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtGAgS%2FbtsyJypxzr9%2FlteClh2LdWk4toAaezsXxK%2Fimg.jpg&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;475&quot; height=&quot;84&quot; data-filename=&quot;img1.daumcdn.jpg&quot; data-origin-width=&quot;475&quot; data-origin-height=&quot;84&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;선입선출 자료구조인 Queue를 이용하는 방식&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;커널에서 관리되는 메모리 공간을 통해 프로세스 간 통신한다.
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: circle;&quot;&gt;송신 프로세스는 자신의 주소 공간에서 메시지 큐의 주소 공간으로 메시지를 복사하고, 메시지 큐는 자신의 주소 공간에 복사된 메시지를 수신 프로세스의 주소 공간으로 복사한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;메시지 큐는 클라이언트와 동기 방식으로 많은 데이터 통신을 수행하면 &lt;b&gt;병목 현상&lt;/b&gt;이 발생할 수 있으므로, 서버의 성능 저하를 방지하기 해 메시지 처리를 위임하여 순차적으로 처리하는 방식을 사용한다. 대용량 데이터 처리, 채팅 서비스 등에 사용된다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;다양한 프로세스가 동시에 데이터를 다룰 수 있다는 장점이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 메모리 맵 (Memory Map)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;공유 메모리와 마찬가지로 메모리를 공유한다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;차이점은 Memory Map의 경우&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;파일을 메모리에 맵핑&lt;/b&gt;하여 메모리 영역에 연결한다는 것이다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;프로세스가 파일을 읽거나 쓰기 위해서는 저장매체에서 메모리로 데이터를 이동해야 하는데, 이때 메모리 맵을 사용하면 파일을 메모리에 직접 맵핑함으로써 이동 과정을 줄이고, 파일을 메모리처럼 다룰 수 있다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;이를 통해 대용량 파일을 읽을 때 파일 전체를 메모리에 맵핑하여 읽기 작업을 진행할 수 있다. 이는 파일을 조각조각 나누어 읽는 방식보다 훨씬 효율적이다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;또한, 여러 프로세스가 동일한 파일을 메모리 맵으로 연결하여 데이터를 공유할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;[참고]&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/states-of-a-process-in-operating-systems/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.geeksforgeeks.org/states-of-a-process-in-operating-systems/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://gabrieletolomei.wordpress.com/miscellanea/operating-systems/in-memory-layout/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://gabrieletolomei.wordpress.com/miscellanea/operating-systems/in-memory-layout/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/process-table-and-process-control-block-pcb/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.geeksforgeeks.org/process-table-and-process-control-block-pcb/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Computer Science/Operating System</category>
      <category>PCB</category>
      <category>Process</category>
      <category>프로세스</category>
      <author>dbssk</author>
      <guid isPermaLink="true">https://developer-rabbit.tistory.com/244</guid>
      <comments>https://developer-rabbit.tistory.com/244#entry244comment</comments>
      <pubDate>Thu, 19 Oct 2023 11:00:36 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스][Lv.2][Java][Heap] 더 맵게</title>
      <link>https://developer-rabbit.tistory.com/243</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42626&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42626&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697068295751&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;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42626&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nEl7U/hyUdU4ksv3/sTKJssGOVmgYwyjBZ0zVY0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/lYLV0/hyT9Eowxz6/IiSUgQycu19BL9rbYDGYnK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42626&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42626&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nEl7U/hyUdU4ksv3/sTKJssGOVmgYwyjBZ0zVY0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/lYLV0/hyT9Eowxz6/IiSUgQycu19BL9rbYDGYnK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 설명&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #263747; text-align: left;&quot;&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;매운 것을 좋아하는 Leo는 모든 음식의 스코빌 지수를 K 이상으로 만들고 싶습니다. 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 Leo는 스코빌 지수가 가장 낮은 두 개의 음식을 아래와 같이 특별한 방법으로 섞어 새로운 음식을 만듭니다.&lt;/p&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;background-color: #e9ecf3; color: #44576c;&quot;&gt;&lt;code&gt;섞은 음식의 스코빌 지수 = 가장 맵지 않은 음식의 스코빌 지수 + (두 번째로 맵지 않은 음식의 스코빌 지수 * 2)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;Leo는 모든 음식의 스코빌 지수가 K 이상이 될 때까지 반복하여 섞습니다.&lt;br /&gt;Leo가 가진 음식의 스코빌 지수를 담은 배열 scoville과 원하는 스코빌 지수 K가 주어질 때, 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 섞어야 하는 최소 횟수를 return 하도록 solution 함수를 작성해주세요.&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;b&gt;제한 사항&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: inherit; color: #000000;&quot;&gt;scoville의 길이는 2 이상 1,000,000 이하입니다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit; color: #000000;&quot;&gt;K는 0 이상 1,000,000,000 이하입니다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit; color: #000000;&quot;&gt;scoville의 원소는 각각 0 이상 1,000,000 이하입니다.&lt;/li&gt;
&lt;li style=&quot;list-style-type: inherit; color: #000000;&quot;&gt;모든 음식의 스코빌 지수를 K 이상으로 만들 수 없는 경우에는 -1을 return 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;풀이&lt;/h3&gt;
&lt;pre id=&quot;code_1697068310616&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    public int solution(int[] scoville, int K) {
        int answer = 0;
        PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;();
        
        for (int s : scoville) {
            pq.offer(s);
        }
        
        while(pq.peek() &amp;lt; K) {
            int first = pq.poll();
            int second = pq.poll();
            int mix = first + (second * 2);
            pq.offer(mix);
            answer++;
            
            if (pq.size() == 1 &amp;amp;&amp;amp; pq.peek() &amp;lt; K) {
                return -1;
            }
        }
        
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시간 복잡도&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;(): 우선순위 큐를 초기화하는 데 O(1)의 시간이 소요된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. for (int s : scoville) pq.offer(s): scoville 배열의 모든 요소를 우선순위 큐에 넣는데 O(N * log(N))의 시간이 소요된다. 이는 각 원소를 큐에 삽입할 때 log(N) 시간이 걸리는데, 총 N번 수행되기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. while(pq.peek() &amp;lt; K): 이 루프는 pq.peek() (가장 작은 Scoville 지수)가 K보다 작은 경우에 동작한다. 루프의 조건은 힙에서 가장 작은 값 확인에 O(1)의 시간이 걸리며, 루프 내부의 작업은 아래와 같이 동작한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;int first = pq.poll();: 우선순위 큐에서 가장 작은 Scoville 지수를 추출하는데 O(log(N))의 시간이 걸린다.&lt;/li&gt;
&lt;li&gt;int second = pq.poll();: 두 번째로 작은 Scoville 지수를 추출하는데도 O(log(N))의 시간이 걸린다.&lt;/li&gt;
&lt;li&gt;int mix = first + (second * 2);: Scoville 지수를 섞는 연산은 상수 시간이 소요된다.&lt;/li&gt;
&lt;li&gt;pq.offer(mix);: Scoville 지수를 다시 우선순위 큐에 삽입하는데 O(log(N))의 시간이 걸린다.&lt;/li&gt;
&lt;li&gt;answer++;: 단순한 증가 연산으로 상수 시간이 소요된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. if (pq.size() == 1 &amp;amp;&amp;amp; pq.peek() &amp;lt; K) return -1;: 큐의 크기와 peek 연산이 모두 상수 시간이 소요된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 위 코드의 시간 복잡도는 주로 우선순위 큐 동작으로 인해 결정된다. 각 루프 반복에서 우선순위 큐에서의 poll() 및 offer() 연산이 O(log(N))의 시간을 필요로 하며, 이러한 루프는 최대 N번 반복됩니다. 따라서 전체 시간 복잡도는 O(N * log(N))이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programmers/Lv.2</category>
      <category>Heap</category>
      <category>java</category>
      <category>LV.2</category>
      <category>프로그래머스</category>
      <category>힙</category>
      <author>dbssk</author>
      <guid isPermaLink="true">https://developer-rabbit.tistory.com/243</guid>
      <comments>https://developer-rabbit.tistory.com/243#entry243comment</comments>
      <pubDate>Thu, 12 Oct 2023 11:00:37 +0900</pubDate>
    </item>
  </channel>
</rss>