<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>gani.log</title>
        <link>https://velog.io/</link>
        <description>나는야 머찐 개발자 </description>
        <lastBuildDate>Wed, 21 Jun 2023 09:52:22 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>gani.log</title>
            <url>https://velog.velcdn.com/images/slr-09/profile/0da1cd53-8963-448e-a210-cb3a2b07c484/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. gani.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/slr-09" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[크루스칼 알고리즘]]></title>
            <link>https://velog.io/@slr-09/%EC%B5%9C%EC%86%8C-%EC%8B%A0%EC%9E%A5-%ED%8A%B8%EB%A6%AC</link>
            <guid>https://velog.io/@slr-09/%EC%B5%9C%EC%86%8C-%EC%8B%A0%EC%9E%A5-%ED%8A%B8%EB%A6%AC</guid>
            <pubDate>Wed, 21 Jun 2023 09:52:22 GMT</pubDate>
            <description><![CDATA[<h2 id="신장-트리란">신장 트리란?</h2>
<p>신장 트리는 그래프에서 모든 노드를 포함하면서 사이클이 존재하지 않는 부분 그래프를 의미합니다. 
모든 노드가 포함되어 서로 연결되면서 사이클이 존재하지 않는다는 조건은 트리의 조건이기도 합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/226edd70-a4ac-48e7-b7e2-8e2cb71d0c8d/image.png" alt=""></p>
<h2 id="최소-신장-트리">최소 신장 트리</h2>
<p>최소한의 비용으로 구성되는 신장 트리를 찾아야 할 때 어떻게 해야 할까요? </p>
<p>N개의 도시가 존재한다고 가정할 때 두 도시 사이에 도로를 놓아 전체 도시가 연결될 수 있게 도로를 설치한다고 생각할 수 있습니다. 즉, 두 도시 A,B를 선택했을 때 A에서 B로 이동하는 경로가 반드시 존재하도록 도로를 설치합니다. </p>
<p>이때 사용할 수 있는 알고리즘이 바로 크루스칼 알고리즘입니다. </p>
<h2 id="크루스칼-알고리즘">크루스칼 알고리즘</h2>
<p>크루스칼 알고리즘은 대표적인 최소 신장 트리 알고리즘이며, 그리디 알고리즘으로 분류됩니다. </p>
<h3 id="동작-과정">동작 과정</h3>
<ol>
<li>간선 데이터를 비용에 따라 오름차순으로 정렬합니다. </li>
<li>간선을 하나씩 확인하며 현재의 간선이 사이클을 발생시키는지 확인합니다. 
 1) 사이클이 발생하지 않는 경우 최소 신장 트리에 포함시킵니다. 
 2) 사이클이 발생하는 경우 최소 신장 트리에 포함시키지 않습니다. </li>
<li>모든 간선에 대해 2번의 과정을 반복합니다. </li>
</ol>
<h3 id="동작-예시">동작 예시</h3>
<p>[초기 단계] 그래프의 모든 간선 정보에 대하여 오름차순 정렬을 수행합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/14393347-23e0-45c8-bc90-e51850ec64d8/image.png" alt=""></p>
<p>[Step 1] 아직 처리하지 않은 간선 중에서 가장 짧은 간선인 (3,4)를 선택하여 처리합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/bdcda2fc-415e-4b6f-b772-3189232bdcaa/image.png" alt="">
[Step 2] 아직 처리하지 않은 간선 중 가장 짧은 간선인 (4,7)을 선택하여 처리합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/9a4d0d29-5644-4234-950f-ababfb625578/image.png" alt="">
[Step 3] 아직 처리하지 않은 간선 중 가장 짧은 간선인 (4,6)을 선택하여 처리합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/2deaac9b-39c9-4998-a18c-2470d8bf022f/image.png" alt="">
[Step 4] 아직 처리하지 않은 간선 중 가장 짧은 간선인 (6,7)을 선택하여 처리합니다. 
6번 노드와 7번 노드는 이미 같은 집합에 속해있으므로 간선을 포함한다면 사이클이 생깁니다. 따라서 해당 간선은 무시하고 넘어갑니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/f9a3b441-4de8-4d6b-b589-e53b5e9fa577/image.png" alt="">
[Step 5] 아직 처리하지 않은 간선 중 가장 짧은 간선인 (1,2)을 선택하여 처리합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/b099bc56-a698-4f81-b2e9-c92a8a52a147/image.png" alt="">
이 과정을 반복하면 다음과 같은 결과를 얻게 됩니다. </p>
<p><img src="https://velog.velcdn.com/images/slr-09/post/ff61e1f0-9300-40cc-a3fe-905712f37ae1/image.png" alt="">
결과로 얻은  최소 신장 트리에 포함되어있는 간선의 비용을 모두 더하면, 그 값이 최종 비용에 해당합니다.  </p>
<h2 id="구현">구현</h2>
<pre><code>import sys
input = sys.stdin.readline

v,e = map(int,input().split())
parent = [i for i in range(v+1)]
graph=[]
result = 0

for _ in range(e):
  a,b,c = map(int,input().split())
  graph.append((c,a,b))

# 비용 순으로 정렬
graph.sort()

# 특정 원소가 속한 집합을 찾을 때까지 
def find_parent(parent,x):
  if parent[x] != x:
    parent[x] = find_parent(parent,parent[x])
  return parent[x]

# 두 노드가 속한 집합 합치기
def union_parent(parent,a,b):
  a = find_parent(parent,a)
  b = find_parent(parent,b)
  if a&lt;b:
    parent[b] = a
  else:
    parent[a] = b

for i in graph:
  cost,a,b = i
  # 사이클이 발생하지 않는 경우에만 집합에 포함
  if find_parent(parent,a)!=find_parent(parent,b):
    union_parent(parent,a,b)
    result += cost

print(result)</code></pre><h3 id="성능-분석">성능 분석</h3>
<p>크루스칼 알고리즘은 간선의 개수가 E개일 때, O(ElogE)의 시간 복잡도를 가집니다. 
크루스칼 알고리즘에서 가장 많은 시간을 요구하는 곳은 간선을 정렬하는 부분입니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[벨만 포드 알고리즘]]></title>
            <link>https://velog.io/@slr-09/%EB%B2%A8%EB%A7%8C-%ED%8F%AC%EB%93%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@slr-09/%EB%B2%A8%EB%A7%8C-%ED%8F%AC%EB%93%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Mon, 19 Jun 2023 07:00:05 GMT</pubDate>
            <description><![CDATA[<p>최단 경로 문제에서 모든 간선의 비용이 양수라면 <a href="https://velog.io/@slr-09/%EC%B5%9C%EB%8B%A8-%EA%B2%BD%EB%A1%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC">다익스트라 최단 경로 알고리즘</a>을 사용하면 됩니다. </p>
<p>그렇다면 음수 간선이 포함되는 경우에는 어떻게 문제를 해결해야 할까요?</p>
<p>단순히 음수 간선이 포함되는 것만으로는 다익스트라 알고리즘을 이용하여 문제를 해결할 수 있습니다. 하지만 음수 간선의 순환이 포함된다면 최단 거리가 음의 무한인 노드가 발생할 것입니다. </p>
<p>이 경우에 사용하는 방법이 벨만 포드 알고리즘입니다. 
벨만 포드 알고리즘은 다익스트라 알고리즘을 알고 있다는 가정 하에 설명합니다. </p>
<h3 id="최단-경로-문제-분류">최단 경로 문제 분류</h3>
<p> 최단 경로 문제는 다음과 같이 분류할 수 있습니다. </p>
<ol>
<li>모든 간선이 양수인 경우 </li>
<li>음수 간선이 있는 경우 
a. 음수 간선 순환이 없는 경우 
b. 음수 간선 순환이 있는 경우 </li>
</ol>
<p>벨만 포드 최단 경로 알고리즘은 음의 간선이 포함된 상황에서도 사용할 수 있습니다.  또한, 음수 간선의 순환을 감지할 수 있습니다. 
벨만 포드의 기본 시간 복잡도는 O(VE)로 다익스트라 알고리즘에 비해 느립니다. </p>
<h2 id="벨만-포드-알고리즘">벨만 포드 알고리즘</h2>
<p>동작은 다음과 같습니다. </p>
<ol>
<li>출발 노드를 설정합니다. </li>
<li>최단 거리 테이블을 초기화합니다. </li>
<li>다음의 과정을 N-1번 반복합니다. 
 1) 전체 간선 E개를 하나씩 확인합니다. 
 2) 각 간선을 거쳐 다른 노드로 가는 비용을 계산하여 최단 거리 테이블을 갱신합니다. </li>
</ol>
<p>만약 음수 간선 순환이 존재하는지 체크하고 싶다면 3번의 과정을 한 번 더 수행합니다. 
이때 최단 거리 테이블이 갱신된다면 음수 간선 순환이 존재하는 것입니다. </p>
<h2 id="구현">구현</h2>
<pre><code>import sys
input = sys.stdin.readline
INF = int(1e9) # 무한을 의미하는 값으로 10억을 설정

# 노드의 개수, 간선의 개수를 입력받기
n, m = map(int, input().split())
# 모든 간선에 대한 정보를 담는 리스트 만들기
edges = []
# 최단 거리 테이블을 모두 무한으로 초기화
distance = [INF] * (n + 1)

# 모든 간선 정보를 입력받기
for _ in range(m):
    a, b, c = map(int, input().split())
    # a번 노드에서 b번 노드로 가는 비용이 c라는 의미
    edges.append((a, b, c))

def bf(start):
    # 시작 노드에 대해서 초기화
    distance[start] = 0
    # 전체 n - 1번의 라운드(round)를 반복
    for i in range(n):
        # 매 반복마다 &quot;모든 간선&quot;을 확인하며
        for j in range(m):
            cur_node = edges[j][0]
            next_node = edges[j][1]
            edge_cost = edges[j][2]
            # 현재 간선을 거쳐서 다른 노드로 이동하는 거리가 더 짧은 경우
            if distance[cur_node] != INF and distance[next_node] &gt; distance[cur_node] + edge_cost:
                distance[next_node] = distance[cur_node] + edge_cost
                # n번째 라운드에서도 값이 갱신된다면 음수 순환이 존재
                if i == n - 1:
                    return True
    return False

# 벨만 포드 알고리즘을 수행
negative_cycle = bf(1) # 1번 노드가 시작 노드

if negative_cycle:
    print(&quot;-1&quot;)
else:
    # 1번 노드를 제외한 다른 모든 노드로 가기 위한 최단 거리를 출력
    for i in range(2, n + 1):
        # 도달할 수 없는 경우, -1을 출력
        if distance[i] == INF:
            print(&quot;-1&quot;)
        # 도달할 수 있는 경우 거리를 출력
        else:
            print(distance[i])</code></pre><h3 id="벨만-포드-알고리즘-vs-다익스트라-알고리즘">벨만 포드 알고리즘 vs 다익스트라 알고리즘</h3>
<ol>
<li>다익스트라 알고리즘    <ul>
<li>매번 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드를 선택합니다. </li>
<li>음수 간선이 없다면 최적의 해를 찾을 수 있습니다. </li>
</ul>
</li>
<li>벨만 포드 알고리즘 <ul>
<li>매번 모든 간선을 전부 확인합니다. </li>
<li><blockquote>
<p>따라서 다익스트라 알고리즘에서의 최적의 해를 항상 포함합니다. </p>
</blockquote>
</li>
<li>다익스트라 알고리즘에 비해 시간이 오래 걸리지만 음수 간선 순환을 탐지할 수 있습니다. </li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[다익스트라 알고리즘]]></title>
            <link>https://velog.io/@slr-09/%EC%B5%9C%EB%8B%A8-%EA%B2%BD%EB%A1%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC</link>
            <guid>https://velog.io/@slr-09/%EC%B5%9C%EB%8B%A8-%EA%B2%BD%EB%A1%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC</guid>
            <pubDate>Mon, 19 Jun 2023 06:45:05 GMT</pubDate>
            <description><![CDATA[<h2 id="다익스트라-최단-경로-알고리즘">다익스트라 최단 경로 알고리즘</h2>
<ul>
<li>특정한 노드에서 출발하여 다른 모든 노드로 가는 최단 경로를 계산합니다. </li>
<li>다익스트라 최단 경로 알고리즘은 음의 간선이 없을 때 정상적으로 동작합니다. </li>
<li>다익스트라 최단 경로 알고리즘은 그리디 알고리즘으로 분류됩니다. <ul>
<li>매 상황에서 가장 비용이 적은 노드를 선택해 임의의 과정을 반복합니다. </li>
</ul>
</li>
</ul>
<h2 id="동작-과정">동작 과정</h2>
<ol>
<li>출발 노드를 설정합니다. </li>
<li>최단 경로 테이블을 초기화합니다. </li>
<li>방문하지 않은 노드 중에서 최단 거리가 가장 짧은 노드를 선택합니다. </li>
<li>해당 노드를 거쳐 다른 노드로 가는 비용을 계산하여 최단 거리 테이블을 갱신합니다. </li>
<li>3번과 4번 과정을 반복합니다. </li>
</ol>
<h2 id="동작-예시">동작 예시</h2>
<p>[초기 상태] 그래프를 준비하고 출발 노드를 설정합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/3faa0fa1-8dc8-4e54-a14a-4e50bd04a541/image.png" alt="">
[Step 1] 방문하지 않은 노드 중에서 최단 거리가 가장 짧은 노드인 1번 노드를 처리합니다. 
1번 노드에 인접한 노드를 확인하여 최단 경로 테이블을 갱신합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/9b1d1a60-0076-4695-8c2f-8705801813b8/image.png" alt="">
[Step 2] 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드인 4번 노드를 처리합니다. </p>
<p><img src="https://velog.velcdn.com/images/slr-09/post/88f8432c-2684-45d8-814e-4132ab0f63f4/image.png" alt="">
[Step 3] 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드인 2번 노드를 처리합니다. 거리가 같은 노드가 있다면 일반적으로 번호가 낮은 노드부터 처리합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/5f7f39ed-c8c8-4baf-b9bc-2f58799bb0f4/image.png" alt="">
[Step 4] 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드인 5번 노드를 처리합니다.
<img src="https://velog.velcdn.com/images/slr-09/post/9cdbd8a7-85b6-4c62-bc6a-c593541283c8/image.png" alt="">
[Step 5] 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드인 3번 노드를 처리합니다.
<img src="https://velog.velcdn.com/images/slr-09/post/ff2a808b-b6e1-4864-b7cf-547466410a32/image.png" alt="">
[Step 5] 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드인 6번 노드를 처리합니다.
<img src="https://velog.velcdn.com/images/slr-09/post/9071bc00-01f6-4e6f-9fec-733f92ba409c/image.png" alt=""></p>
<h3 id="다익스트라-알고리즘의-특징">다익스트라 알고리즘의 특징</h3>
<ul>
<li>매 상황에서 방문하지 않은 노드 중 가장 비용이 적은 노드를 선택해 임의의 과정을 반복합니다. -&gt; 그리디 알고리즘</li>
<li>단계를 거치며 <strong>한 번 처리된 노드의 최단 거리는 고정</strong>되어 더 이상 바뀌지 않습니다. </li>
<li>다익스트라 알고리즘을 수행한 뒤에 테이블에 각 노드까지의 최단 거리 정보가 저장됩니다. </li>
</ul>
<h3 id="성능-분석">성능 분석</h3>
<p>위 동작 과정대로 탐색한다면 O(V)번에 걸쳐서 최단 거리가 가장 짧은 노드를 매번 선형 탐색해야 합니다. 따라서 전체 시간 복잡도는 O(V^2)입니다. </p>
<blockquote>
<p>일반적으로 코딩 테스트의 최단 경로 문제에서 전체 노드의 개수가 5,000개 이하라면 이 코드로 문제를 해결할 수 있습니다. 
하지만 노드의 개수가 10,000개를 넘어가는 문제라면 어떻게 해야 할까요?</p>
</blockquote>
<p>이 문제를 해결하기 위해 힙(Heap) 자료구조를 이용합니다. 
힙 자료구조를 이용하여 단계마다 방문하지 않은 노드 중 최단 거리가 가장 짧은 노드를 선택합니다. 
다익스트라 알고리즘이 동작하는 기본 원리는 동일합니다. </p>
<ul>
<li>현재 가장 가까운 노드를 저장해 놓기 위해 힙 자료구조를 추가적으로 이용한다는 점이 다릅니다.</li>
<li>현재의 최단 거리가 가장 짧은 노드를 선택해야 하므로 최소 힙을 사용합니다. <h2 id="구현-방법">구현 방법</h2>
[최소 힙 이용]<pre><code>import heapq
import sys
input = sys.stdin.readline
INF = int(1e9) # 무한을 의미하는 값으로 10억을 설정
</code></pre></li>
</ul>
<h1 id="노드의-개수-간선의-개수를-입력받기">노드의 개수, 간선의 개수를 입력받기</h1>
<p>n, m = map(int, input().split())</p>
<h1 id="시작-노드-번호를-입력받기">시작 노드 번호를 입력받기</h1>
<p>start = int(input())</p>
<h1 id="각-노드에-연결되어-있는-노드에-대한-정보를-담는-리스트를-만들기">각 노드에 연결되어 있는 노드에 대한 정보를 담는 리스트를 만들기</h1>
<p>graph = [[] for i in range(n + 1)]</p>
<h1 id="최단-거리-테이블을-모두-무한으로-초기화">최단 거리 테이블을 모두 무한으로 초기화</h1>
<p>distance = [INF] * (n + 1)</p>
<h1 id="모든-간선-정보를-입력받기">모든 간선 정보를 입력받기</h1>
<p>for _ in range(m):
    a, b, c = map(int, input().split())
    # a번 노드에서 b번 노드로 가는 비용이 c라는 의미
    graph[a].append((b, c))</p>
<p>def dijkstra(start):
    q = []
    # 시작 노드로 가기 위한 최단 경로는 0으로 설정하여, 큐에 삽입
    heapq.heappush(q, (0, start))
    distance[start] = 0
    while q: # 큐가 비어있지 않다면
        # 가장 최단 거리가 짧은 노드에 대한 정보 꺼내기
        dist, now = heapq.heappop(q)
        # 현재 노드가 이미 처리된 적이 있는 노드라면 무시
        if distance[now] &lt; dist:
            continue
        # 현재 노드와 연결된 다른 인접한 노드들을 확인
        for i in graph[now]:
            cost = dist + i[1]
            # 현재 노드를 거쳐서, 다른 노드로 이동하는 거리가 더 짧은 경우
            if cost &lt; distance[i[0]]:
                distance[i[0]] = cost
                heapq.heappush(q, (cost, i[0]))</p>
<h1 id="다익스트라-알고리즘을-수행">다익스트라 알고리즘을 수행</h1>
<p>dijkstra(start)</p>
<h1 id="모든-노드로-가기-위한-최단-거리를-출력">모든 노드로 가기 위한 최단 거리를 출력</h1>
<p>for i in range(1, n + 1):
    # 도달할 수 없는 경우, 무한(INFINITY)이라고 출력
    if distance[i] == INF:
        print(&quot;INFINITY&quot;)
    # 도달할 수 있는 경우 거리를 출력
    else:
        print(distance[i])
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[트리 순회 알고리즘]]></title>
            <link>https://velog.io/@slr-09/%ED%8A%B8%EB%A6%AC-%EC%88%9C%ED%9A%8C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@slr-09/%ED%8A%B8%EB%A6%AC-%EC%88%9C%ED%9A%8C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Sun, 18 Jun 2023 10:44:56 GMT</pubDate>
            <description><![CDATA[<p>트리의 순회는 트리 자료구조에 포함된 노드를 특정한 방법으로 한 번씩 방문하는 방법을 의미합니다. </p>
<p>대표적인 트리 순회 방법은 전위 순회, 중위 순회, 후위 순회가 있습니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/e9251c55-4057-459f-901d-f8397d5c02e1/image.png" alt=""></p>
<p>위 그림의 트리를 예제로 구현해보겠습니다. </p>
<p>트리 구현을 위해 다음과 같은 클래스를 정의합니다. </p>
<pre><code>class Node:
    def __init__(self, data, left, right):
    self.data = data
    self.left = left
    self.right = right</code></pre><pre><code>n = int(input())
tree = {}

for i in range(n):
    data, left, right = input().split()
    if left == &quot;None&quot;:
        left = None
    if right == &quot;None&quot;:
        right = None
    tree[data] = Node(data, left, right)

# 전위 순회 실행 
pre_order(tree[&#39;A&#39;]) # A는 시작 노드 
</code></pre><h3 id="전위-순회pre-order-traverse">전위 순회(pre-order traverse)</h3>
<p>: 루트를 먼저 방문합니다. </p>
<pre><code>def pre_order(node):
    print(node.data, end=&#39; &#39;)
  if node.left != None:
    in_order(tree[node.left])
  if node.right != None:
    in_order(tree[node.right])</code></pre><h3 id="중위-순회in-order-traverse">중위 순회(in-order traverse)</h3>
<p>: 왼쪽 자식을 방문한 뒤에 루트를 방문합니다. </p>
<pre><code>def in_order(node):
  if node.left != None:
    in_order(tree[node.left])
  print(node.data, end=&#39; &#39;)
  if node.right != None:
    in_order(tree[node.right])</code></pre><h3 id="후위-순회post-order-traverse">후위 순회(post-order traverse)</h3>
<p>: 오른쪽 자식을 방문한 뒤에 루트를 방문합니다. </p>
<pre><code>def post_order(node):
  if node.left != None:
    in_order(tree[node.left])
  if node.right != None:
    in_order(tree[node.right])
  print(node.data, end=&#39; &#39;)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[전략(Strategy) 패턴]]></title>
            <link>https://velog.io/@slr-09/%EC%A0%84%EB%9E%B5Strategy-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@slr-09/%EC%A0%84%EB%9E%B5Strategy-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Sun, 18 Jun 2023 09:47:27 GMT</pubDate>
            <description><![CDATA[<h2 id="전략strategy-패턴이란">전략(Strategy) 패턴이란?</h2>
<blockquote>
<p>전략 패턴은 정책(policy) 패턴이라고도 하며, 객체의 행위를 바꾸고 싶은 경우 &#39;직접&#39; 수정하지 않고 전략이라고 부르는 &#39;캡슐화한 알고리즘&#39;을 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴입니다. </p>
</blockquote>
<pre><code>컨텍스트 : 프로그래밍에서의 컨텍스트는 상황, 맥락, 문맥을 의미하며 개발자가 어떠한 작업을 
         완료하는데 필요한 모든 정보를 말한다. </code></pre><h3 id="예시">예시</h3>
<p>우리가 어떤 아이템을 살 때 LUNACard로 사는 것과 KAKAOCard로 사는 것을 구현한 예제입니다. 
결제 방식의 &#39;전략&#39;만 바꿔서 두 가지 방식으로 결제하는 구현 방식입니다. </p>
<pre><code>import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
interface PaymentStrategy { 
    public void pay(int amount);
} 

class KAKAOCardStrategy implements PaymentStrategy {
    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;

    public KAKAOCardStrategy(String nm, String ccNum, String cvv, String expiryDate){
        this.name=nm;
        this.cardNumber=ccNum;
        this.cvv=cvv;
        this.dateOfExpiry=expiryDate;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount +&quot; paid using KAKAOCard.&quot;);
    }
} 

class LUNACardStrategy implements PaymentStrategy {
    private String emailId;
    private String password;

    public LUNACardStrategy(String email, String pwd){
        this.emailId=email;
        this.password=pwd;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + &quot; paid using LUNACard.&quot;);
    }
} 

class Item { 
    private String name;
    private int price; 
    public Item(String name, int cost){
        this.name=name;
        this.price=cost;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }
} 

class ShoppingCart { 
    List&lt;Item&gt; items;

    public ShoppingCart(){
        this.items=new ArrayList&lt;Item&gt;();
    }

    public void addItem(Item item){
        this.items.add(item);
    }

    public void removeItem(Item item){
        this.items.remove(item);
    }

    public int calculateTotal(){
        int sum = 0;
        for(Item item : items){
            sum += item.getPrice();
        }
        return sum;
    }

    // 전략에 따라 결제 방식이 달라짐 
    public void pay(PaymentStrategy paymentMethod){
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}  

public class HelloWorld{
    public static void main(String []args){
        ShoppingCart cart = new ShoppingCart();

        Item A = new Item(&quot;kundolA&quot;,100);
        Item B = new Item(&quot;kundolB&quot;,300);
        // 카트에 아이템 추가 
        cart.addItem(A);
        cart.addItem(B);

        // pay by LUNACard
        cart.pay(new LUNACardStrategy(&quot;kundol@example.com&quot;, &quot;pukubababo&quot;));
        // pay by KAKAOBank
        cart.pay(new KAKAOCardStrategy(&quot;Ju hongchul&quot;, &quot;123456789&quot;, &quot;123&quot;, &quot;12/01&quot;));
    }
}
/*
400 paid using LUNACard.
400 paid using KAKAOCard.
*/</code></pre><h3 id="passport의-전략-패턴">passport의 전략 패턴</h3>
<p>전략 패턴을 활용한 라이브러리로는 passport가 있습니다. 
<a href="https://www.passportjs.org/">https://www.passportjs.org/</a></p>
<p>passport는 Node.js에서 인증 모듈을 구현할 때 쓰는 미들웨어 라이브러리로, 여러 가지 &#39;전략&#39;을 기반으로 인증할 수 있게 합니다. 예를 들어 서비스 내의 회원가입된 id, pw를 기반으로 인증하는 LocalStrategy 전략과 소셜 로그인 서비스를 기반으로 인증하는 OAuth 전략 등을 지원합니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[팩토리(Factory) 패턴]]></title>
            <link>https://velog.io/@slr-09/%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@slr-09/%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Sun, 18 Jun 2023 09:37:14 GMT</pubDate>
            <description><![CDATA[<h2 id="팩토리factory-패턴이란">팩토리(Factory) 패턴이란?</h2>
<p>팩토리 패턴(factory pattern)은 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴이자 상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정하는 패턴입니다. </p>
<p>상위 클래스와 하위 클래스가 분리되기 때문에 느슨한 결합을 가지며 상위 클래스에서는 인스턴스 생성 방식에 대해 전혀 알 필요가 없기 때문에 더 많은 유연성을 갖게 됩니다. 
그리고 객체 생성 로직이 따로 떼어져 있기 때문에 코드를 리팩터링하더라도 한 곳만 고칠 수 있게 되니 유지 보수성이 증가됩니다. </p>
<h3 id="자바스크립트의-팩토리-패턴">자바스크립트의 팩토리 패턴</h3>
<p>커피 팩토리를 기반으로 커피를 생산하는 코드를 보겠습니다. </p>
<pre><code>// 상위 클래스 
class CoffeeFactory {
    static createCoffee(type) {
        const factory = factoryList[type]
        return factory.createCoffee()
    }
}   

// 하위 클래스 
class Latte {
    constructor() {
        this.name = &quot;latte&quot;
    }
}
//하위 클래스 
class Espresso {
    constructor() {
        this.name = &quot;Espresso&quot;
    }
} 

class LatteFactory extends CoffeeFactory{
    static createCoffee() {
        return new Latte()
    }
}
class EspressoFactory extends CoffeeFactory{
    static createCoffee() {
        return new Espresso()
    }
}
const factoryList = { LatteFactory, EspressoFactory } 


const main = () =&gt; {
    // 라떼 커피를 주문한다.  
    const coffee = CoffeeFactory.createCoffee(&quot;LatteFactory&quot;)  
    // 커피 이름을 부른다.  
    console.log(coffee.name) // latte
}
main()</code></pre><p>CoffeeFactory라는 상위 클래스가 중요한 뼈대를  결정하고 하위 클래스인 LatteFactory가 구체적인 내용을 결정하고 있습니다. </p>
<p>참고로 이는 의존성 주입이라고도 볼 수 있습니다. CoffeeFactory에서 LatteFactory의 인스턴스를 생성하는 것이 아닌 LatteFactory에서 생성한 인스턴스를 CoffeeFactory에 주입하고 있기 때문입니다. </p>
<p>또한, static 키워드를 통해 createCoffee() 메서드를 선언함으로써 클래스를 기반으로 객체를 만들지 않고 호출이 가능해 메모리 할당을 한 번만 할 수 있는 장점이 있습니다. </p>
<h3 id="자바의-팩토리-패턴">자바의 팩토리 패턴</h3>
<p>이를 자바로 구현하면 다음과 같습니다. </p>
<pre><code>enum CoffeeType {
    LATTE,
    ESPRESSO
}

abstract class Coffee {
    protected String name;

    public String getName() {
        return name;
    }
}

class Latte extends Coffee {
    public Latte() {
        name = &quot;latte&quot;;
    }
}

class Espresso extends Coffee {
    public Espresso() {
        name = &quot;Espresso&quot;;
    }
}

class CoffeeFactory {
    public static Coffee createCoffee(CoffeeType type) {
        switch (type) {
            case LATTE:
                return new Latte();
            case ESPRESSO:
                return new Espresso();
            default:
                throw new IllegalArgumentException(&quot;Invalid coffee type: &quot; + type);
        }
    }
}

public class Main {
    public static void main(String[] args) { 
        Coffee coffee = CoffeeFactory.createCoffee(CoffeeType.LATTE); 
        System.out.println(coffee.getName()); // latte
    }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[싱글톤(Singleton) 패턴 ]]></title>
            <link>https://velog.io/@slr-09/%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@slr-09/%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Sun, 18 Jun 2023 09:09:07 GMT</pubDate>
            <description><![CDATA[<h2 id="싱글톤singleton-패턴이란">싱글톤(Singleton) 패턴이란?</h2>
<p>싱글톤 패턴(singleton pattern)은 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴으로, 보통 데이터베이스 연결 모듈에 많이 사용됩니다. </p>
<p>하나의 인스턴스를 다른 모듈들이 공유하며 사용하기 떄문에 인스턴스를 생성할 때 드는 비용이 줄어들지만, 의존성이 높아진다는 단점이 있습니다. </p>
<pre><code>객체 : 소프트웨어 세계에 구현할 대상 
클래스 : 구현을 위한 설계도
인스턴스 : 설계도에 따라 소프트웨어 세계에 구현된 실체 </code></pre><h3 id="데이터베이스-연결-모듈">데이터베이스 연결 모듈</h3>
<pre><code>// js
// DB 연결을 하는 것이기 때문에 비용이 더 높은 작업 
const URL = &#39;mongodb://localhost:27017/kundolapp&#39; 
const createConnection = url =&gt; ({&quot;url&quot; : url})    
class DB {
    constructor(url) {
        if (!DB.instance) { 
            DB.instance = createConnection(url)
        }
        return DB.instance
    }
    connect() {
        return this.instance
    }
}
const a = new DB(URL)
const b = new DB(URL) 
console.log(a === b) // true</code></pre><p>이렇게 DB.instance라는 하나의 인스턴스를 기반으로 a, b를 생성합니다. 
이를 통해 데이터베이스 연결에 관한 인스턴스 생성 비용을 아낄 수 있습니다. </p>
<h3 id="싱글톤-패턴의-단점">싱글톤 패턴의 단점</h3>
<p>싱글톤 패턴은 TDD(Test Driven Development)를 할 때 걸림돌이 됩니다. TDD를 할 때 단위 테스트를 주로 하는데, 단위 테스트는 서로 독립적이어야 하며 테스트를 어떤 순서로든 실행할 수 있어야 합니다. </p>
<p>하지만 싱글톤 패턴은 하나의 인스턴스를 기반으로 구현하는 패턴이므로 각 테스트마다 &#39;독립적인&#39; 인스턴스를 만들기가 어렵습니다. </p>
<h3 id="의존성-주입">의존성 주입</h3>
<p>싱글톤 패턴은 모듈 간의 결합을 강하게 만들 수 있다는 단점이 있습니다. 이때 의존성 주입(DI, Dependency Injection)을 통해 모듈 간의 결합을 좀 더 느슨하게 만들어 해결할 수 있습니다. </p>
<pre><code>의존성(종속성) : A가 B에 의존성이 있다는 것은 B의 변경 사항을 A도 따라야 한다는 것</code></pre><p><img src="https://velog.velcdn.com/images/slr-09/post/413d6274-91bf-48e9-a7ca-a0b9e1de5883/image.png" alt="">
위 그림처럼 의존성 주입자(dependency injector)가 중간에 의존성을 가로채 메인 모듈이 간접적으로 의존성을 주입하는 방식입니다. </p>
<p>이를 통해 메인 모듈(상위 모듈)은 하위 모듈에 대한 의존성이 떨어지게 됩니다. 
이를 &#39;디커플링이 된다&#39;고도 합니다. </p>
<h4 id="의존성-주입의-장점">의존성 주입의 장점</h4>
<ul>
<li>모듈들을 쉽게 교체할 수 있는 구조가 되어 테스팅하기 쉬움</li>
<li>마이그레이션하기 수월함</li>
<li>구현할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어주기 때문에 
애플리케이션 의존성 방향이 일관됨</li>
<li>애플리케이션을 쉽게 추론 가능</li>
<li>모듈 간의 관계들이 조금 더 명확해짐 </li>
</ul>
<pre><code>마이그레이션 : 데이터나 소프트웨어를 한 시스템에서 다른 시스템으로 이동하는 것</code></pre><h4 id="의존성-주입의-단점">의존성 주입의 단점</h4>
<ul>
<li>모듈들이 더 분리되므로 클래스 수가 늘어가 복잡성 증가 </li>
<li>약간의 런타임 페널티 생김 </li>
</ul>
<h4 id="의존성-주입-원칙">의존성 주입 원칙</h4>
<ul>
<li>상위 모듈은 하위 모듈에서 어떠한 것도 가져오지 않아야 함 </li>
<li>상위 모듈과 하위 모듈 모두 추상화에 의존해야 함 </li>
<li>이때 추상화는 세부 사항에 의존하지 말아야 함 </li>
</ul>
<p>의존성을 주입할 때는 위 세 가지 원칙을 지켜주면서 만들어야 합니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 12865번 평범한 배낭 (Python)]]></title>
            <link>https://velog.io/@slr-09/%EB%B0%B1%EC%A4%80-12865%EB%B2%88-%ED%8F%89%EB%B2%94%ED%95%9C-%EB%B0%B0%EB%82%AD-Python</link>
            <guid>https://velog.io/@slr-09/%EB%B0%B1%EC%A4%80-12865%EB%B2%88-%ED%8F%89%EB%B2%94%ED%95%9C-%EB%B0%B0%EB%82%AD-Python</guid>
            <pubDate>Sat, 17 Jun 2023 06:36:11 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<p>이 문제는 아주 평범한 배낭에 관한 문제이다.</p>
</blockquote>
<p>한 달 후면 국가의 부름을 받게 되는 준서는 여행을 가려고 한다. 세상과의 단절을 슬퍼하며 최대한 즐기기 위한 여행이기 때문에, 가지고 다닐 배낭 또한 최대한 가치 있게 싸려고 한다.</p>
<blockquote>
</blockquote>
<p>준서가 여행에 필요하다고 생각하는 N개의 물건이 있다. 각 물건은 무게 W와 가치 V를 가지는데, 해당 물건을 배낭에 넣어서 가면 준서가 V만큼 즐길 수 있다. 아직 행군을 해본 적이 없는 준서는 최대 K만큼의 무게만을 넣을 수 있는 배낭만 들고 다닐 수 있다. 준서가 최대한 즐거운 여행을 하기 위해 배낭에 넣을 수 있는 물건들의 가치의 최댓값을 알려주자.</p>
<h2 id="입력">입력</h2>
<p>첫 줄에 물품의 수 N(1 ≤ N ≤ 100)과 준서가 버틸 수 있는 무게 K(1 ≤ K ≤ 100,000)가 주어진다. 두 번째 줄부터 N개의 줄에 거쳐 각 물건의 무게 W(1 ≤ W ≤ 100,000)와 해당 물건의 가치 V(0 ≤ V ≤ 1,000)가 주어진다.</p>
<p>입력으로 주어지는 모든 수는 정수이다.</p>
<h2 id="출력">출력</h2>
<p>한 줄에 배낭에 넣을 수 있는 물건들의 가치합의 최댓값을 출력한다.</p>
<hr>
<h2 id="풀이">풀이</h2>
<p>물건의 수 N, 버틸 수 있는 무게 K에 대하여 N*K의 2차원 배열을 이용한다. 
d[n][k]는 n번째 물건까지 살펴보았을 때, 무게가 k인 배낭의 최대 가치이다. </p>
<p>물건을 배낭에 담을 때,</p>
<ol>
<li>허용 무게가 넣을 물건의 무게보다 작다면 넣지 않는다. </li>
<li>그렇지 않다면, 두 가지 중 더 높은 가치를 선택한다.</li>
</ol>
<ul>
<li>현재 넣을 물건의 무게만큼 배낭에서 뺀 후 현재 물건을 넣는다. </li>
<li>이전 배낭을 그대로 유지한다. </li>
</ul>
<p>위 과정을 코드로 나타내면 다음과 같다. 
현재 담을 물건의 인덱스를 i, 현재 가방 허용 용량이 j, 현재 담을 물건의 무게를 weight, 가치 value라고 할 때,</p>
<pre><code>if j&lt;weight 
    -&gt; d[i][j] = d[i-1][j]
else 
    -&gt; d[i][j] = max(d[i-1][j], d[i-1][j-weight]+value)</code></pre><h2 id="소스코드">소스코드</h2>
<pre><code>import sys
input = sys.stdin.readline

n,k = map(int,input().split())
d = [[0]*(k+1) for _ in range(n+1)]
we = [[0,0]]
for _ in range(n):
  we.append(list(map(int,input().split())))

for i in range(1,n+1):
  for j in range(1,k+1):
    w,v = we[i][0], we[i][1]

    if j&lt;w:
      d[i][j] = d[i-1][j]
    else:
      d[i][j] = max(d[i-1][j], d[i-1][j-w]+v) 

print(d[n][k])</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 2749번 피보나치 수 3 (Python)]]></title>
            <link>https://velog.io/@slr-09/%EB%B0%B1%EC%A4%80-2749%EB%B2%88-%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98-%EC%88%98-3-Python</link>
            <guid>https://velog.io/@slr-09/%EB%B0%B1%EC%A4%80-2749%EB%B2%88-%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98-%EC%88%98-3-Python</guid>
            <pubDate>Fri, 16 Jun 2023 18:02:02 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<p>피보나치 수는 0과 1로 시작한다. 0번째 피보나치 수는 0이고, 1번째 피보나치 수는 1이다. 그 다음 2번째 부터는 바로 앞 두 피보나치 수의 합이 된다.</p>
</blockquote>
<p>이를 식으로 써보면 Fn = Fn-1 + Fn-2 (n ≥ 2)가 된다.</p>
<blockquote>
</blockquote>
<p>n=17일때 까지 피보나치 수를 써보면 다음과 같다.
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597</p>
<blockquote>
</blockquote>
<p>n이 주어졌을 때, n번째 피보나치 수를 구하는 프로그램을 작성하시오.</p>
<h2 id="입력">입력</h2>
<p>첫째 줄에 n이 주어진다. n은 1,000,000,000,000,000,000보다 작거나 같은 자연수이다.</p>
<h2 id="출력">출력</h2>
<p>첫째 줄에 n번째 피보나치 수를 1,000,000으로 나눈 나머지를 출력한다.</p>
<hr>
<h2 id="아이디어">아이디어</h2>
<p>이 문제에서 n의 값은 매우 크기 때문에 <code>피사노 주기</code>라는 방법을 활용한다. </p>
<p>피사노 주기는 피보나치 수를 K로 나눈 나머지는 항상 주기를 갖게된다는 원리이다.</p>
<p>주기의 길이가 P 일 때, N번째 피보나치 수를 M으로 나눈 나머지는 N%P번째 피보나치 수를 M을 나눈 나머지와 같다. </p>
<p><code>M = 10^k</code> 일 때, <code>k&gt;2</code> 라면 주기는 항상 <code>15*10^(k-1)</code> 이다.</p>
<h2 id="소스코드">소스코드</h2>
<pre><code>import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**6)
Q = 1000000

n = int(input())
p = 15*Q//10  # 나머지 주기
d = [0]*(p+1)
d[1] = 1

for i in range(2,p):
  d[i] = d[i-1]+d[i-2]
  d[i] %= Q

print(d[n%p])</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[계수 정렬 알고리즘]]></title>
            <link>https://velog.io/@slr-09/%EA%B3%84%EC%88%98-%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@slr-09/%EA%B3%84%EC%88%98-%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Fri, 16 Jun 2023 08:19:20 GMT</pubDate>
            <description><![CDATA[<h2 id="계수-정렬">계수 정렬</h2>
<ul>
<li>특정한 조건이 부합할 때만 사용할 수 있지만 매우 빠르게 동작하는 알고리즘입니다. <ul>
<li>계수 정렬은 데이터의 크기 범위가 제한되어 정수 형태로 표현할 수 있을 때 사용 가능합니다. </li>
</ul>
</li>
<li>데이터의 개수가 N, 데이터(양수) 중 최대값이 K일 때, 최악의 경우에도 수행 시간 O(N+K)를 보장합니다. </li>
</ul>
<h2 id="동작-예시">동작 예시</h2>
<p>정렬할 데이터 : 7 5 9 0 3 1 6 2 9 1 4 8 0 5 2</p>
<p>[Step 0] 가장 작은 데이터부터 가장 큰 데이터까지의 범위가 모두 담길 수 있도록 리스트를 생성합니다. </p>
<p><img src="https://velog.velcdn.com/images/slr-09/post/45f8b0ed-f0ef-4338-b20c-71b42b56c8d3/image.png" alt=""></p>
<p>[Step 1] 데이터를 하나씩 확인하며 데이터의 값과 동일한 인덱스의 데이터를 1씩 증가시킵니다. 
결과적으로 최종 리스트에는 각 데이터가 몇 번 등장했는지 그 횟수가 기록됩니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/2944d361-de25-40b2-abb8-33e20e8b0414/image.png" alt=""></p>
<p>[Step 2] 결과를 확인할 때는 리스트의 첫 번째 데이터부터 하나씩 그 값 만큼 반복하여 인덱스를 출력합니다. </p>
<p>출력 결과 : 0 0 1 1 2 2 3 4 5 5 6 7 8 9 9</p>
<h2 id="소스코드">소스코드</h2>
<pre><code># 모든 원소의 값이 0보다 크거나 같다고 가정 
array = [7, 5, 9, 0, 3, 1, 6, 2, 9, 1, 4, 8, 0, 5, 2]
# 모든 범위를 포함하는 리스트 선언(모든 값은 0으로 초기화)
count = [0] * (max(array)+1)

for i in range(len(array)):
    count[array[i]] += 1

for i in range(len(count)):
    for j in range(count[i]):
        print(i, end=&quot; &quot;)</code></pre><h2 id="복잡도">복잡도</h2>
<p>계수 정렬의 시간 복잡도와 공간 복잡도는 모두 O(N+K)입니다. </p>
<ul>
<li>계수 정렬은 때에 따라서 심각한 비효율성을 초래할 수 있습니다. <ul>
<li>데이터가 0과 999,999로 단 두개만 존재하는 경우 </li>
</ul>
</li>
<li>동일한 값을 가지는 데이터가 여러 개 등장할 때 효과적으로 사용할 수 있습니다. </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[퀵 정렬 알고리즘]]></title>
            <link>https://velog.io/@slr-09/%ED%80%B5-%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@slr-09/%ED%80%B5-%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Fri, 16 Jun 2023 08:06:18 GMT</pubDate>
            <description><![CDATA[<h2 id="퀵-정렬">퀵 정렬</h2>
<blockquote>
<p>기준 데이터를 설정하고 그 기준보다 작은 데이터의 위치를 바꾸는 방법입니다. </p>
</blockquote>
<p>일반적인 상황에서 가장 많이 사용되는 정렬 알고리즘입니다. 
병합 정렬과 더불어 대부분의 프로그래밍 언어의 정렬 라이브러리의 근간이 되는 알고리즘입니다. 
가장 기본적인 퀵 정렬은 첫 번째 데이터를 기준 데이터(Pivot)로 설정합니다.</p>
<h2 id="동작-예시">동작 예시</h2>
<p>[Step 0] 현재 피벗의 값은 5입니다. 왼쪽에서부터 5보다 큰 데이터를 선택하므로 7이 선택되고, 오른쪽에서부터 5보다 작은 데이터를 선택하므로 4가 선택됩니다. 이제 이 두 데이터의 위치를 서로 변경합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/e2e63532-077d-4dfd-acf8-90b181ac4bcf/image.png" alt="">
[Step 1] 현재 피벗의 값은 5입니다. 왼쪽에서부터 5보다 큰 데이터를 선택하므로 9가 선택되고, 오른쪽에서부터 5보다 작은 데이터를 선택하므로 2가 선택됩니다. 이제 이 두 데이터의 위치를 서로 변경합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/bf3ef31a-0258-4c11-919a-b80cfa3e4543/image.png" alt="">
[Step 2] 현재 피벗의 값은 5입니다. 왼쪽에서부터 5보다 큰 데이터를 선택하므로 6이 선택되고, 오른쪽에서부터 5보다 작은 데이터를 선택하므로 1이 선택됩니다.
단, 이처럼 위치가 엇갈리는 경우 피벗과 작은 데이터의 위치를 서로 변경합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/1cfd912b-2ddc-4935-8514-57bba5879107/image.png" alt="">
[분할 완료] 이제 5의 왼쪽에 있는 데이터는 모두 5보다 작고, 오른쪽에 있는 데이터는 5보다 크다는 특징이 있습니다. 
이렇게 피벗을 기준으로 데이터를 나누는 작업을 분할(Divide)이라고 합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/5d3679f2-f42d-4d56-896b-09f87db4d0e7/image.png" alt="">
[왼쪽 데이터 묶음] 왼쪽에 있는 데이터에 대해서 마찬가지로 정렬을 수행합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/e2899906-99f3-489c-a199-04180232eca9/image.png" alt=""></p>
<p>이러한 과정을 반복하면 전체 데이터에 대해 정렬이 수행됩니다. </p>
<h2 id="시간-복잡도">시간 복잡도</h2>
<p>퀵 정렬은 평균의 경우 O(NlogN)의 시간복잡도를 가집니다. 
<code>너비 X 높이 = N x logN = NlogN</code>
<img src="https://velog.velcdn.com/images/slr-09/post/2abd169d-00ea-490c-b114-17fe30b603fa/image.png" alt=""></p>
<p>하지만 최악의 경우 O(N^2)의 시간복잡도를 가집니다. </p>
<h2 id="소스코드">소스코드</h2>
<p>[일반적인 방식]</p>
<pre><code>array = [5, 7, 9, 0, 3, 1, 6, 2, 4, 8]

def quick_sort(array, start, end):
    if start &gt;= end:
        return 
    pivot = start
    left = start + 1
    right = end
    while (left &lt;= right):
        # 피벗보다 큰 데이터를 찾을 때까지 반복
        while(left &lt;= end and array[left] &lt;= array[pivot]):
            left += 1
        # 피벗보다 작은 데이터를 찾을 때까지 반복
        while(right &gt; start and array[right] &gt;= array[pivot]):
            right += 1
        if (left &gt; right)    # 엇갈렸다면 피벗과 작은 데이터 교체
            array[right], pivot = pivot, array[right]
        else:    # 엇갈리지 않았다면 작은 데이터와 큰 데이터를 교체 
            array[left], array[right] = array[right], array[left]
    # 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬 수행 
    quick_sort(array, start, right-1)
    quick_sort(array, right+1, end)

quick_sort(array, 0, len(array)-1)
print(array)

# 실행 결과 
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]</code></pre><p>[파이썬의 장점을 살린 방식]</p>
<pre><code>array = [5, 7, 9, 0, 3, 1, 6, 2, 4, 8]

def quick_sort(array):
    if len(array) &lt;= 1:
        return array
    pivot = array[0]
    tail = array[1:]

    left_side = [x for x in tail if x &lt;= pivot]
    right_side = [x for x in tail if x &gt; pivot]

    return quick_sort(left_side) + [pivot] + quick_sort(right_side)

print(quick_sort(array))

# 실행 결과 
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[삽입 정렬 알고리즘]]></title>
            <link>https://velog.io/@slr-09/%EC%82%BD%EC%9E%85-%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@slr-09/%EC%82%BD%EC%9E%85-%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Fri, 16 Jun 2023 07:44:42 GMT</pubDate>
            <description><![CDATA[<h2 id="삽입-정렬">삽입 정렬</h2>
<blockquote>
<p>처리되지 않은 데이터를 하나씩 골라 <strong>적절한 위치에 삽입</strong>합니다. </p>
</blockquote>
<p>삽입 정렬은 선택 정렬에 비해 구현 난이도가 높은 편이지만, 일반적으로 더 효율적으로 동작합니다. </p>
<h2 id="동작-예시">동작 예시</h2>
<p>[Step 0] 첫 번째 데이터 7은 그 자체로 정렬이 되어있다고 판단하고, 두 번째 데이터인 5가 어떤 위치로 들어갈지 판단합니다. 7의 왼쪽으로 들어가거나 오른쪽으로 들어가거나 두 경우만 존재합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/7d6c55fb-1893-4d8f-8c33-c076046ed24a/image.png" alt="">
[Step 1] 이어서 9가 어떤 위치로 들어갈지 판단합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/7de61281-87e4-4a1d-a883-e96be39e5089/image.png" alt="">
[Step 2] 이어서 0이 어떤 위치로 들어갈지 판단합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/8375ad73-3d97-4ff6-88e2-ababfcf5b484/image.png" alt="">
[Step 3] 이어서 3이 어떤 위치로 들어갈지 판단합니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/8da9da56-74dd-46a6-bb81-2acd413044eb/image.png" alt="">
이러한 과정을 반복하면 다음과 같이 정렬이 완료됩니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/71be42c5-a85d-47dc-8e9c-003364fee0b4/image.png" alt=""></p>
<h2 id="소스코드">소스코드</h2>
<pre><code>array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]

for i in range(1,len(array)):
    for j in range(i,0,-1):    # 인덱스 i부터 1까지 1씩 감소하며 반복
        if array[j] &lt; array[j-1]:    # 한 칸 씩 왼쪽으로 이동
            array[j], array[j-1] = array[j-1], array[j]
        else:    # 자기보다 작은 데이터를 만나면 break
            break
print(array)

# 실행 결과 
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]</code></pre><h2 id="시간-복잡도">시간 복잡도</h2>
<p>삽입 정렬의 시간 복잡도는 O(N^2)이며, 선택 정렬과 마찬가지로 반복문이 2번 중첩되어 사용됩니다. </p>
<p>삽입 정렬은 현재 리스트 데이터가 거의 정렬되어 있는 상태라면 매우 빠르게 동작합니다. 
최선의 경우 O(N)의 시간복잡도를 가집니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[선택 정렬 알고리즘]]></title>
            <link>https://velog.io/@slr-09/%EC%84%A0%ED%83%9D-%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@slr-09/%EC%84%A0%ED%83%9D-%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Fri, 16 Jun 2023 07:32:49 GMT</pubDate>
            <description><![CDATA[<h2 id="선택-정렬">선택 정렬</h2>
<blockquote>
<p>처리되지 않은 데이터 중에서 가장 작은 데이터를 선택해 맨 앞에 있는 데이터와 바꾸는 것을 반복합니다.</p>
</blockquote>
<h2 id="동작-예시">동작 예시</h2>
<p>[Step 0] 처리되지 않은 데이터 중 가장 작은 0을 선택해 가장 앞인 7과 바꿉니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/233c0630-cbda-45d8-b94d-68a13398ac94/image.png" alt="">
[Step 1] 처리되지 않은 데이터 중 가장 작은 1을 선택해 가장 앞인 5와 바꿉니다.
<img src="https://velog.velcdn.com/images/slr-09/post/90bc1007-c817-4af5-a781-89aefb4e1ee9/image.png" alt="">
[Step 2] 처리되지 않은 데이터 중 가장 작은 2을 선택해 가장 앞인 9와 바꿉니다.
<img src="https://velog.velcdn.com/images/slr-09/post/8671050a-925d-43fc-a83c-1a5e7be5486a/image.png" alt="">
[Step 3] 처리되지 않은 데이터 중 가장 작은 3을 선택해 가장 앞인 7과 바꿉니다.
<img src="https://velog.velcdn.com/images/slr-09/post/880c6f4f-2639-496f-8881-b2d8a0183362/image.png" alt="">
이러한 과정을 반복하면 다음과 같이 정렬이 완료됩니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/3088be2d-02bc-452a-ac13-ba1c8f8fbf3f/image.png" alt=""></p>
<h2 id="소스코드">소스코드</h2>
<pre><code>array = [7,5,9,0,3,1,6,2,4,8]

for i in range(len(array)):
    min_idx = i
    for j in range(i+1,len(array)):
        if array[min_idx] &gt; array[j]:
            min_idx = j
    array[i], array[min_idx] = array[min_idx],array[i]

print(array)

# 실행 결과 
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]</code></pre><h2 id="시간-복잡도">시간 복잡도</h2>
<p>선택 정렬은 N번 만큼 가장 작은 수를 찾아서 맨 앞으로 보내야 합니다. </p>
<p>전체 연산 횟수는 <code>N + (N-1) + (N-2) + ... + 2</code>와 같고 이는 빅오 표기법에 따라 <code>O(N^2)</code>라고 작성합니다. 1</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[이진 탐색 알고리즘]]></title>
            <link>https://velog.io/@slr-09/%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89</link>
            <guid>https://velog.io/@slr-09/%EC%9D%B4%EC%A7%84-%ED%83%90%EC%83%89</guid>
            <pubDate>Fri, 16 Jun 2023 05:59:39 GMT</pubDate>
            <description><![CDATA[<h2 id="이진-탐색">이진 탐색</h2>
<blockquote>
<p>정렬되어 있는 리스트에서 탐색 범위를 절반씩 좁혀가며 데이터를 탐색하는 방법입니다. </p>
</blockquote>
<p>이진 탐색은 시작점, 끝점, 중간점을 이용하여 탐색 범위를 설정합니다. </p>
<h3 id="예시">예시</h3>
<p>이미 정렬된 10개의 데이터 중 값이 4인 원소를 찾는 예시를 살펴봅시다. 
<img src="https://velog.velcdn.com/images/slr-09/post/e05ed29c-fa66-45a8-8d64-be3112eae0a4/image.png" alt=""></p>
<p>[Step 1] 시작점 : 0, 끝점 : 9, 중간점 : 4 (소수점 이하 제거)
이때 중간점인 8이 4보다 크므로 끝점을 3으로 바꿉니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/5f233528-fb4e-4151-a150-0ddb0661c1a9/image.png" alt=""></p>
<p>[Step 2] 시작점 : 0, 끝점 : 3, 중간점 : 1 (소수점 이하 제거)</p>
<p><img src="https://velog.velcdn.com/images/slr-09/post/b9271760-95cc-49c9-aca5-319f3111bba0/image.png" alt=""></p>
<p>[Step 2] 시작점 : 2, 끝점 : 3, 중간점 : 2 (소수점 이하 제거)
<img src="https://velog.velcdn.com/images/slr-09/post/2493bb0a-1a33-486e-8696-59d300d35221/image.png" alt=""></p>
<p>이렇게 탐색 범위를 절반씩 줄여가며 탐색하는 방법을 이진 탐색이라고 합니다. </p>
<h2 id="시간-복잡도">시간 복잡도</h2>
<p>단계마다 탐색 범위를 2로 나누는 것과 동일하므로 밑이 2인 로그, <code>log2 N</code>에 비례합니다. </p>
<h2 id="소스코드">소스코드</h2>
<p>위 예시의 이진 탐색 함수 코드는 다음과 같습니다. </p>
<pre><code># 이진 탐색
def binary_search(array, target, start, end):
    if start &gt; end:
        return None
    mid = (start+end)//2

    # 찾은 경우 
    if array[mid] == target:
        return mid
    # 중간점이 찾고자하는 값보다 큰 경우 왼쪽 탐색 
    elif array[mid] &gt; target:
        return binary_search(array, target, start, mid-1)
    # 중간점이 찾고자하는 값보다 작은 경우 오른쪽 탐색 
    else:
        return binary_search(array, target, mid+1, end)</code></pre><h2 id="라이브러리">라이브러리</h2>
<ul>
<li><code>bisect_left(a,x)</code> : 정렬된 순서를 유지하면서 배열 a에 x를 삽입할 가장 왼쪽 인덱스 반환</li>
<li><code>bisect_right(a,x)</code> : 정렬된 순서를 유지하면서 배열 a에 x를 삽입할 가장 오른쪽 인덱스 반환</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 1167번 트리의 지름 (Python)]]></title>
            <link>https://velog.io/@slr-09/%EB%B0%B1%EC%A4%80-1167%EB%B2%88-%ED%8A%B8%EB%A6%AC%EC%9D%98-%EC%A7%80%EB%A6%84-Python</link>
            <guid>https://velog.io/@slr-09/%EB%B0%B1%EC%A4%80-1167%EB%B2%88-%ED%8A%B8%EB%A6%AC%EC%9D%98-%EC%A7%80%EB%A6%84-Python</guid>
            <pubDate>Thu, 15 Jun 2023 16:02:26 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<p>트리의 지름이란, 트리에서 임의의 두 점 사이의 거리 중 가장 긴 것을 말한다. 트리의 지름을 구하는 프로그램을 작성하시오.</p>
</blockquote>
<h2 id="입력">입력</h2>
<p>트리가 입력으로 주어진다. 먼저 첫 번째 줄에서는 트리의 정점의 개수 V가 주어지고 (2 ≤ V ≤ 100,000)둘째 줄부터 V개의 줄에 걸쳐 간선의 정보가 다음과 같이 주어진다. 정점 번호는 1부터 V까지 매겨져 있다.</p>
<p>먼저 정점 번호가 주어지고, 이어서 연결된 간선의 정보를 의미하는 정수가 두 개씩 주어지는데, 하나는 정점번호, 다른 하나는 그 정점까지의 거리이다. 예를 들어 네 번째 줄의 경우 정점 3은 정점 1과 거리가 2인 간선으로 연결되어 있고, 정점 4와는 거리가 3인 간선으로 연결되어 있는 것을 보여준다. 각 줄의 마지막에는 -1이 입력으로 주어진다. 주어지는 거리는 모두 10,000 이하의 자연수이다.</p>
<h2 id="출력">출력</h2>
<p>첫째 줄에 트리의 지름을 출력한다.</p>
<hr>
<h2 id="아이디어">아이디어</h2>
<p>먼저, 이 문제를 풀기 위해서는 트리의 지름을 구하는 방법을 알아야 한다. </p>
<p>트리의 지름은 다음과 같이 구할 수 있다. </p>
<ol>
<li>임의의 정점 하나에 대해 가장 먼 정점을 구한다. </li>
<li>새로 구한 정점에 대해 가장 먼 정점을 한 번 더 구한다. </li>
<li>2번 과정에서 나온 두 정점의 거리가 트리의 지름이 된다. </li>
</ol>
<p>이렇게 2번의 dfs를 통해 트리의 지름을 구할 수 있다. </p>
<h2 id="풀이">풀이</h2>
<p>[틀린 풀이] 
이 풀이는 2%에서 틀렸다고 나왔다. </p>
<pre><code>import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**5)

v=int(input())
graph = [[] for _ in range(v+1)]

# 틀린 위치
for j in range(v):
  n = list(map(int,input().split()[1:-1]))
  for i in range(0,len(n)-1,2):
    graph[j+1].append((n[i],n[i+1]))
# 여기까지

visited=[False]*(v+1)
dist=[0]*(v+1)

def dfs(x):
  visited[x] = True
  for i in graph[x]:
    if not visited[i[0]]:
      dist[i[0]] = dist[x]+i[1]
      dfs(i[0])

# 첫 번째 dfs
dfs(1)
m = dist.index(max(dist))

visited=[False]*(v+1)
dist=[0]*(v+1)

# 두 번째 dfs
dfs(m)
print(max(dist))</code></pre><p>예시 입력을 보면 2~v+1의 줄에서 첫 번째 숫자는 정점의 번호를 의미한다. 
이 번호가 주어질 필요가 없다고 생각했는데 입력 조건을 자세히 들여다보면 입력되는 정점의 순서가 고정되지 않았다는 사실을 알 수 있었다. 따라서 정점 번호는 꼭 필요한 조건이었다. </p>
<p>[맞은 풀이]</p>
<pre><code>import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**5)

v=int(input())
graph = [[] for _ in range(v+1)]
# 고친 부분
for _ in range(v):
  n = list(map(int,input().split()[:-1]))
  for i in range(1,len(n)-1,2):
    graph[n[0]].append((n[i],n[i+1]))
# 여기까지

visited=[False]*(v+1)
dist=[0]*(v+1)

def dfs(x):
  visited[x] = True
  for i in graph[x]:
    if not visited[i[0]]:
      dist[i[0]] = dist[x]+i[1]
      dfs(i[0])

dfs(1)
m = dist.index(max(dist))
visited=[False]*(v+1)
dist=[0]*(v+1)
dfs(m)
print(max(dist))</code></pre><ul>
<li>참고하면 좋을 반례들
<a href="https://www.acmicpc.net/board/view/67245">https://www.acmicpc.net/board/view/67245</a></li>
</ul>
<p>++ 참고로 dfs같이 재귀함수를 이용하는 경우에, 파이썬은 재귀가 1000으로 제한되어 있어서 <code>sys.setresursionlimit()</code>를 꼭 설정해주어야 한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CPU 스케줄링 알고리즘]]></title>
            <link>https://velog.io/@slr-09/CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@slr-09/CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Wed, 14 Jun 2023 04:28:45 GMT</pubDate>
            <description><![CDATA[<p>CPU 스케줄러는 CPU 스케줄링 알고리즘에 따라 프로세스에서 해야 하는 일을 스레드 단위로 CPU에 할당합니다. </p>
<p>프로그램이 실행될 때는 CPU 스케줄링 알고리즘이 어떤 프로그램에 CPU 소유권을 줄 것인지 결정합니다. 이 알고리즘은 CPU 이용률은 높게, 주어진 시간에 많은 일을 하게, 준비 큐에 있는 프로세스는 적게, 응답 시간은 짧게 설정하는 것을 목표로 합니다. </p>
<h2 id="비선점형-방식">비선점형 방식</h2>
<p>비선점형 방식(non-preemptive)은 프로세스가 스스로 CPU 소유권을 포기하는 방식이며, 강제로 프로세스를 중지하지 않습니다. 따라서 컨텍스트 스위칭으로 인한 부하가 적습니다. </p>
<h3 id="fcfsfirst-come-first-served">FCFS(First Come, First Served)</h3>
<p>FCFS(First Come, First Served)는 가장 먼저 온 것을 가장 먼저 처리하는 알고리즘입니다. 
길게 수행되는 프로세스 때문에 &#39;준비 큐에서 오래 기다리는 현상(convoy effect)&#39;이 발생하는 단점이 있습니다. </p>
<h3 id="sjfshortest-job-first">SJF(Shortest Job First)</h3>
<p>SJF(Shortest Job First)는 실행 시간이 가장 짧은 프로세스를 가장 먼저 실행하는 알고리즘입니다. 
긴 시간을 가진 프로세스가 실행되지 않는 현상(starvation)이 일어나며 평균 시간이 가장 짧습니다. 하지만 실제로는 실행 시간을 알 수 없기 때문에 과거의 실행했던 시간을 토대로 추측해서 사용합니다. </p>
<h3 id="우선순위">우선순위</h3>
<p>오래된 작업일수록 &#39;우선순위를 높이는 방법(aging)&#39;을 통해 긴 시간을 가진 프로세스가 실행되지 않는 단점을 보안한 알고리즘입니다. </p>
<hr>
<h2 id="선점형-방식">선점형 방식</h2>
<p>선점형 방식(preemptive)은 지금 사용하고 있는 프로세스를 알고리즘에 의해 중단시켜 버리고 강제로 다른 프로세스에 CPU 소유권을 할당하는 방식으로 현대 운영체제가 쓰는 방식입니다. </p>
<h3 id="라운드-로빈">라운드 로빈</h3>
<p>라운드 로빈(RR, Round Robin)은 각 프로세스는 동일한 할당 시간을 주고 그 시간 안에 끝나지 않으면 다시 준비 큐의 뒤로 가는 알고리즘으로 우선순위 스케줄링의 일종입니다. </p>
<p>일반적을 전체 작업 시간은 길어지지만 평균 응답 시간은 짧아진다는 특징이 있습니다. 또한, 이 알고리즘은 로드밸런서에서 트래픽 분산 알고리즘으로도 쓰입니다. </p>
<h3 id="srfshortest-remaining-time-first">SRF(Shortest Remaining Time First)</h3>
<p>SJF는 중간에 실행 시간이 더 짧은 작업이 들어와도 기존 짧은 작업을 모두 수행한 후 그 다음 짧은 작업을 이어나가는데, SRF는 중간에 더 짧은 작업이 들어오면 수행하던 프로세스를 중지하고 해당 프로세스를 수행하는 알고리즘입니다. </p>
<h3 id="다단계-큐">다단계 큐</h3>
<p>다단계 큐는 우선순위에 따른 준비 큐를 여러 개 사용하고, 큐마다 다른 스케줄링 알고리즘을 적용한 것을 말합니다. 큐 간의 프로세스 이동이 안되므로 스케줄링 부담이 적지만 유연성이 떨어지는 특징이 있습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로세스와 스레드 (2)]]></title>
            <link>https://velog.io/@slr-09/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C-2</link>
            <guid>https://velog.io/@slr-09/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C-2</guid>
            <pubDate>Fri, 09 Jun 2023 12:20:38 GMT</pubDate>
            <description><![CDATA[<h1 id="멀티프로세싱">멀티프로세싱</h1>
<p>멀티프로세싱은 여러 개의 프로세스, 즉 멀티프로세스를 통해 동시에 두 가지 이상의 일을 수행할 수 있는 것을 말합니다. 이를 통해 하나 이상의 일을 병렬로 처리할 수 있으며 특정 프로세스의 메모리, 프로세스 중 일부에 문제가 발생되더라도 다른 프로세스를 이용해서 처리할 수 있으므로 신뢰성이 높은 강점이 있습니다. </p>
<h3 id="웹-브라우저">웹 브라우저</h3>
<p>웹 브라우저는 멀티프로세스 구조를 가지고 있습니다. </p>
<h4 id="구조">구조</h4>
<ul>
<li>브라우저 프로세스 : 주소 표시줄, 북마크 막대, 뒤로 가기 버튼 등을 담당하며 네트워크 요청이나 파일 접근 같은 권한을 담당합니다. </li>
<li>렌더러 프로세스 : 웹 사이트가 보이는 부분의 모든 것을 제어합니다. </li>
<li>플러그인 프로세스 : 웹 사이트에서 사용하는 플러그인을 제어합니다. </li>
<li>GPU 프로세스 : GPU를 이용해서 화면을 그리는 부분을 제어합니다. </li>
</ul>
<h3 id="ipc">IPC</h3>
<p>IPC(Inter Process Communication)는 프로세스끼리 데이터를 주고받고 공유 데이터를 관리하는 메커니즘을 뜻하며, 멀티프로세스는 IPC가 가능합니다. </p>
<p>IPC의 종류로는 공유 메모리, 파일, 소켓, 익명 파이프, 명명 파이프, 메시지 큐가 있습니다. 이들은 모두 메모리가 완전히 공유되는 스레드보다는 속도가 떨어집니다. </p>
<h4 id="공유-메모리">공유 메모리</h4>
<p>공유 메모리(shared memory)는 여러 프로세스에 동일한 메모리 블록에 대한 접근 권한이 부여되어 프로세스가 서로 통신할 수 있도록 공유 메모리를 생성해서 통신하는 것을 말합니다. </p>
<p>공유 메모리를 통해 여러 프로세스가 하나의 메모리를 공유할 수 있으며, 메모리 자체를 공유하기 때문에 불필요한 데이터 복사의 오버헤드가 발생하지 않아 가장 빠릅니다. 같은 메모리 영역을 여러 프로세스가 공유하기 때문에 동기화가 필요합니다. </p>
<h4 id="파일">파일</h4>
<p>파일은 디스크에 저장된 데이터 또는 파일 서버에서 제공한 데이터를 말합니다. </p>
<h4 id="소켓">소켓</h4>
<p>동일한 컴퓨터의 다른 프로세스나 네트워크의 다른 컴퓨터로 네트워크 인터페이스를 통해 전송하는 데이터를 의미하며 TCP와 UDP가 있습니다. </p>
<h4 id="익명-파이프">익명 파이프</h4>
<p>익명 파이프(unamed pipe)는 프로세스 간에 FIFO 방식으로 읽히는 임시 공간이 파이프를 기반으로 데이터를 주고받으며, 단방향 방식의 읽기 전용, 쓰기 전용 파이프를 만들어서 작동하는 방식입니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/0a2399a8-cb2a-49d3-887c-db58eea397a5/image.png" alt="">
이는 부모, 자식 프로세스 간에만 사용할 수 있습니다.</p>
<h4 id="명명된-파이프">명명된 파이프</h4>
<p>명명된 파이프(named pipe)는 파이프 서버와 하나 이상의 파이프 클라이언트 간의 통신을 위한 명명된 단방향 또는 양방향 파이프를 말합니다. 클라이언트/서버 통신을 위한 별도의 파이프를 제공하며, 여러 파이프를 동시에 사용할 수 있습니다. 컴퓨터의 프로세스끼리 또는 다른 네트워크 상의 컴퓨터와도 통신을 할 수 있습니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/d8f405f7-caf7-4bb3-9e1f-40e561b228db/image.png" alt=""></p>
<h4 id="메시지-큐">메시지 큐</h4>
<p>메시지 큐는 메시지를 큐 데이터 구조 형태로 관리하는 것을 의미합니다. 이는 커널의 전역변수 형태 등 커널에서 전역적으로 관리되며 다른 IPC 방식에 비해서 사용 방법이 매우 직관적이고 간단하며 다른 코드의 수정 없이 단지 몇 줄의 코드를 추가시켜 간단하게 메시지 큐에 접근할 수 있는 장점이 있습니다. </p>
<hr>
<h1 id="스레드와-멀티스레딩">스레드와 멀티스레딩</h1>
<h2 id="스레드">스레드</h2>
<p>스레드는 프로세스의 실행 가능한 가장 작은 단위입니다. 프로세스는 여러 스레드를 가질 수 있습니다. </p>
<p>프로세스는 코드, 데이터, 스택, 힙을 각각 생성하고 스레드는 그 중 코드, 데이터, 힙을  스레드끼리 서로 공유합니다. 그 외의 영역은 각각 생성됩니다. </p>
<h2 id="멀티스레딩">멀티스레딩</h2>
<p>멀티스레딩은 프로세스 내 작업을 여러 개의 스레드로 처리하는 기법이며 스레드끼리 서로 자원을 공유하기 때문에 효율성이 높습니다. 예를 들어 웹 요청을 처리할 때 스레드를 사용하는 웹 서버의 경우 훨씬 적은 리소스를 소비하며, 한 스레드가 중단되어도 다른 스레드는 실행 상태일 수 있기 때문에 중단되지 않은 빠른 처리가 가능합니다. 
또한, 동시성에도 큰 장점이 있습니다. 하지만 한 스레드에 문제가 생기면 다른 스레드에도 영향을 끼쳐 프로세스에 영향을 줄 수 있습니다. </p>
<pre><code>동시성 : 서로 독립적인 작업들을 단위로 나누고 동시에 실행되는 것처럼 보여주는 것 </code></pre><hr>
<h1 id="공유-자원과-임계-영역">공유 자원과 임계 영역</h1>
<h2 id="공유-자원">공유 자원</h2>
<p>공유 자원(shared resource)은 시스템 안에서 각 프로세스, 스레드가 함께 접근할 수 있는 자원(모니터, 프린터, 메모리, 파일, 데이터 등)이나 변수 등을 의미합니다. 이 공유 자원을 두 개 이상의 프로세스가 동시에 읽거나 쓰는 상황을 경쟁 상태(race condition)라고 합니다. </p>
<h2 id="임계-영역">임계 영역</h2>
<p>임계 영역(critical section)은 둘 이상의 프로세스, 스레드가 공유 자원에 접근할 때 순서 등의 이유로 결과가 달라지는 코드 영역을 말합니다. </p>
<p>임계 영역을 해결하기 위한 방법은 크게 뮤텍스, 세마포어, 모니터 세 가지가 있으며, 이 방법 모두 상호 배제, 한정 대기, 융통성이란 조건을 만족합니다. </p>
<pre><code>상호 배제 : 한 프로세스가 임계 영역에 들어갔을 때 다른 프로세스는 들어갈 수 없다. 

한정 대기 : 특정 프로세스가 영원히 임계 영역에 들어가지 못하면 안된다. 

융통성 : 한 프로세스가 다른 프로세스의 일을 방해해서는 안된다. </code></pre><h3 id="뮤텍스">뮤텍스</h3>
<p>뮤텍스(mutex)는 프로세스나 스레드가 공유 자원을 lock()을 통해 잠금 설정하고 사용한 후에는 unlock()을 통해 잠금 해제하는 객체입니다. 뮤텍스는 잠금 또는 잠금 해제라는 상태만을 가집니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/84cdb806-d24a-45b3-9786-6a89a54b7d5a/image.png" alt=""></p>
<h3 id="세마포어">세마포어</h3>
<p>세마포어(semaphore)는 일반화된 뮤텍스입니다. 간단한 정수 값과 두 가지 함수 wait(P 함수) 및 signal(V 함수)로 공유 자원에 대한 접근을 처리합니다. 
wait()는 자신의 차례가 올 때까지 기다리는 함수이며, signal()은 다음 프로세스로 순서를 넘겨주는 함수입니다. </p>
<p>세마포어에는 조건 변수가 없고 프로세스나 스레드가 세마포어 값을 수정할 때 다른 프로세스나 스레드는 동시에 세마포어 값을 수정할 수 없습니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/d28c0b64-7b70-43d3-b71c-a742cb9eb893/image.png" alt=""></p>
<h4 id="바이너리-세마포어">바이너리 세마포어</h4>
<p>바이너리 세마포어는 0과 1의 두 가지 값만 가질 수 있는 세마포어입니다. 구현의 유사성으로 인해 뮤텍스는 바이너리 세마포어라고 할 수 있지만 뮤텍스는 잠금을 기반으로 상호배제가 일어나는 &#39;잠금 메커니즘&#39;이고, 세마포어는 신호를 기반으로 상호 배제가 일어나는 &#39;신호 메커니즘&#39;입닏다. </p>
<h4 id="카운팅-세마포어">카운팅 세마포어</h4>
<p>카운팅 세마포어는 여러 개의 값을 가질 수 있는 세마포어이며, 여러 자원에 대한 접근을 제어하는 데 사용됩니다. </p>
<h3 id="모니터">모니터</h3>
<p>모니터는 둘 이상의 스레드는 프로세스가 공유 자원에 안전하게 접근할 수 있도록 <strong>공유 자원을 숨기고</strong> 해당 접근에 대해 인터페이스만 제공합니다. </p>
<p>모니터는 모니터큐를 통해 공유 자원에 대한 작업들을 순차적으로 처리합니다. </p>
<p>모니터는 세마포어보다 구현하기 쉬우며 모니터에서 상호 배제는 자동인 반면, 세마포어에서는 상호 배제를 명시적으로 구현해야 하는 차이점이 있습니다. </p>
<hr>
<h1 id="교착-상태">교착 상태</h1>
<p>교착 상태(deadlock)는 두 개 이상의 프로세스들이 서로가 가진 자원을 기다리며 중단된 상태를 말합니다. 
예를 들어 프로세스 A가 프로세스 B의 어떤 자원을 요청할 때 프로세스 B도 프로세스 A가 점유하고 있는 자원을 요청하는 것이죠. 이에 대한 원인과 해결 방법은 다음과 같습니다. </p>
<h2 id="교착-상태의-원인">교착 상태의 원인</h2>
<ul>
<li>상호 배제 : 한 프로세스가 자원을 독점하고 있으며 다른 프로세스들은 접근이 불가능합니다. </li>
<li>점유 대기 : 특정 프로세스가 점유한 자원을 다른 프로세스가 요청하는 상태입니다. </li>
<li>비선점 : 다른 프로세스의 자원을 강제적으로 가져올 수 없습니다. </li>
<li>환형 대기 : 프로세스 2개가 서로의 자원을 요구하는 상황을 말합니다. </li>
</ul>
<h2 id="교착-상태의-해결-방법">교착 상태의 해결 방법</h2>
<ol>
<li>자원을 할당할 때 애초에 조건이 성립되지 않도록 설계합니다. </li>
<li>교착 상태 가능성이 없을 때만 자원 할당되며, 프로세스당 요청할 자원들의 최대치를 통해 자원 할당 가능 여부를 파악하는 &#39;은행원 알고리즘&#39;을 씁니다. </li>
<li>교착 상태가 발생하면 사이클이 있는지 찾아보고 이에 관련된 프로세스를 한 개씩 지웁니다. </li>
<li>교착 상태는 매우 드물게 일어나기 때문에 이를 처리하는 비용이 더 커서 교착 상태가 발생하면 사용자가 작업을 종료합니다. </li>
</ol>
<pre><code>은행원 알고리즘 
: 총 자원의 양과 현재 할당한 자원의 양을 기준으로 안정 또는 불안정으로 나누고 
  안정 상태로 가도록 자원을 할당하는 알고리즘 </code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[프로세스와 스레드 (1)]]></title>
            <link>https://velog.io/@slr-09/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C-1</link>
            <guid>https://velog.io/@slr-09/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C-1</guid>
            <pubDate>Fri, 09 Jun 2023 12:20:28 GMT</pubDate>
            <description><![CDATA[<p>프로세스(process)는 컴퓨터에서 실행되고 있는 프로그램을 말하며 CPU 스케줄링의 대상이 되는 작업(task)이라는 용어와 거의 같은 의미로 쓰입니다. 
스레드는 프로세스 내 작업의 흐름을 지칭합니다. </p>
<p>프로그램이 메모리에 올라가면 프로세스가 되는 인스턴스화가 일어나고, 이후 운영체제의 CPU 스케줄러에 따라 CPU가 프로세스를 실행합니다. </p>
<h2 id="프로세스와-컴파일-과정">프로세스와 컴파일 과정</h2>
<p>[프로그램의 컴파일 과정]
<img src="https://velog.velcdn.com/images/slr-09/post/fa995d2e-006f-4ac4-a9a6-c744e86a5848/image.png" alt=""></p>
<h3 id="전처리">전처리</h3>
<p>소스 코드의 주석을 제거하고 헤더 파일을 병합하여 매크로를 치환합니다. </p>
<h3 id="컴파일러">컴파일러</h3>
<p>오류 처리, 코드 최적화 작업을 하며 어셈블리어로 변환합니다. </p>
<h3 id="어셈블러">어셈블러</h3>
<p>어셈블리어는 목적 코드(object code)로 변환됩니다. </p>
<h3 id="링커">링커</h3>
<p>프로그램 내에 있는 라이브러리 함수 또는 다른 파일들과 목적 코드를 결합하여 실행 파일을 만듭니다. 실행 파일의 확장자는 <code>.exe</code> 또는 <code>.out</code>이라는 확장자를 갖습니다. </p>
<h4 id="정적-라이브러리와-동적-라이브러리">정적 라이브러리와 동적 라이브러리</h4>
<p>라이브러리는 정적 라이브러리와 동적 라이브러리로 나뉩니다. </p>
<p>정적 라이브러리는 프로그램 빌드 시 라이브러리가 제공하는 모든 코드를 실행 파일에 넣는 방식으로 라이브러리를 쓰는 방법입니다. 시스템 환경 등 외부 의존도가 낮은 장점이 있지만 코드 중복 등 메모리 효율성이 떨어지는 단점이 있습니다. </p>
<p>동적 라이브러리는 프로그램 실행 시 필요할 때만 DLL이라는 함수 정보를 통해 참조하여 라이브러리를 쓰는 방법입니다. 메모리 효율성에서의 장점을 지니지만 외부 의존도가 높아진다는 단점이 있습니다. </p>
<hr>
<h2 id="프로세스의-상태">프로세스의 상태</h2>
<p>프로세스의 상태는 여러 가지 상태 값을 갖습니다. </p>
<h3 id="생성-상태">생성 상태</h3>
<p>생성 상태(create)는 프로세스가 생성된 상태를 의미하며 fork() 또는 exec() 함수를 통해 생성합니다. 이때 PCB가 할당됩니다. </p>
<h4 id="fork">fork()</h4>
<p>fork()는 부모 프로세스의 주소 공간을 그대로 복상하여 새로운 자식 프로세스를 생성하는 함수입니다. </p>
<h4 id="exec">exec()</h4>
<p>exec()는 새롭게 프로세스를 생성하는 함수입니다. </p>
<h3 id="대기-상태">대기 상태</h3>
<p>대기 상태(ready)는 메모리 공간이 충분하면 메모리를 할당받고 아니면 아닌 상태로 대기하고 있으며 CPU 스케줄러로부터 CPU 소유권이 넘어오기를 기다리는 상태입니다. </p>
<h3 id="대기-중단-상태">대기 중단 상태</h3>
<p>대기 중단 상태(ready suspended)는 메모리 부족으로 일시 중단된 상태입니다. </p>
<h3 id="실행-상태">실행 상태</h3>
<p>실행 상태(running)는 CPU 소유권과 메모리를 할당받고 인스트럭션을 수행 중인 상태를 의미합니다. 이를 CPU burst가 일어났다고도 표현합니다. </p>
<h3 id="중단-상태">중단 상태</h3>
<p>중단 상태(blocked)는 어떤 이벤트가 발생한 이후 기다리며 프로세스가 차단된 상태입니다. I/O 디바이스에 의한 인터럽트로 이런 현상이 많이 발생하기도 합니다. </p>
<h3 id="일시-중단-상태">일시 중단 상태</h3>
<p>일시 중단 상태(blocked suspended)는 대기 중단과 유사합니다. 중단된 상태에서 프로세스가 실행되려고 했지만 메모리 부족으로 일시 중단된 상태입니다. </p>
<h3 id="종료-상태">종료 상태</h3>
<p>종료 상태(terminated)는 메모리와 CPU 소유권을 모두 놓고 가는 상태를 말합니다. 
종료는 자연스럽게 종료되는 것도 있지만 부모 프로세스가 자식 프로세스를 강제시키는 비자발적 종료(abort)로 종료되는 것도 있습니다. 자식 프로세스에서 할당된 자원의 한계치를 넘어서거나 부모 프로세스가 종료되거나 사용자가 <code>process.kill</code> 등 여러 명령어로 프로세스를 종료시킬 때 발생합니다. </p>
<hr>
<h2 id="프로세스의-메모리-구조">프로세스의 메모리 구조</h2>
<p><img src="https://velog.velcdn.com/images/slr-09/post/b911a278-6f1e-48b1-aabe-5063c5f2c94f/image.png" alt="">
위에서부터 스택, 힙, 데이터 영역(BSS segment, Data segment), 코드 영역으로 나눠집니다. 스택은 위 주소부터 할당되고 힙은 아래 주소부터 할당됩니다. </p>
<h3 id="스택과-힙">스택과 힙</h3>
<p>스택과 힙은 동적 할당이 되며, 동적 할당은 런타임 단계에서 메모리를 할당받는 것을 말합니다. 스택은 지역 변수, 매개변수, 실행되는 함수에 의해 늘어나거나 줄어드는 메모리 영역입니다. 함수가 호출될 때마다 호출될 때의 환경 등 특정 정보가 스택에 계속해서 저장됩니다. 
또한, 재귀 함수가 호출된다고 했을 때 새로운 스택 프레임이 매번 사용되기 때문에 함수 내의 변수 집합이 해당 함수의 다른 인스턴스 변수를 방해하지 않습니다. </p>
<p>힙은 동적으로 할당되는 변수들을 담습니다. malloc(), free() 함수를 통해 관리할 수 있으며 동적으로 관리되는 자료 구조의 경우 힙 영역을 사용합니다. </p>
<h3 id="데이터-영역과-코드-영역">데이터 영역과 코드 영역</h3>
<p>이 영역은 정적 할당되는 영역입니다. 정적 할당은 컴파일 단계에서 메모리를 할당하는 것을 말합니다. 데이터 영역은 BSS segment와 Data segment, code/text segment로 나뉘어서 저장됩니다. </p>
<p>BSS segment는 전역 변수 또는 static, const로 선언되어 있고 0으로 초기화 또는 초기화가 어떠한 값으로도 되어있지 않은 변수들이 이 메모리 영역에 할당됩니다. 
Data segment는 전역 변수 또는 static, const로 선언되어 있고 0이 아닌 값으로 초기화된 변수가 이 메모리 영역에 할당됩니다. 
code segment는 프로그램의 코드가 들어갑니다. </p>
<hr>
<h2 id="pcb">PCB</h2>
<blockquote>
<p>PCB(Process Control Block)는 운영체제에서 프로세스에 대한 메타데이터를 저장한 데이터를 말하며 프로세스 제어 블록이라고도 합니다. 
프로세스의 상태 정보를 저장하는 구조체이며 프로세스의 상태 관리와 문맥교환을 위해 필요합니다. </p>
</blockquote>
<p>PCB는 프로세스 생성 시 만들어지며 주기억장치에 유지됩니다. </p>
<p>PCB에 데이터가 저장되는 과정은 다음과 같습니다. 
프로그램이 실행되면 프로세스가 생성되고 프로세스 주소 값들이 스택, 힙 등의 구조로 메모리가 할당됩니다. 그리고 이 프로세스의 메타데이터들이 PCB에 저장되어 관리됩니다. 이는 프로세스의 중요한 정보를 포함하고 있기 때문에 일반 사용자가 접근하지 못하도록 커널 스택의 가장 앞부분에서 관리됩니다. </p>
<pre><code>메타데이터 : 데이터에 관한 구조화된 데이터이자 데이터를 설명하는 작은 데이터</code></pre><h3 id="pcb의-구조">PCB의 구조</h3>
<p>PCB는 프로세스 스케줄링 상태, 프로세스 ID 등의 다음과 같은 정보로 이루어져 있습니다. </p>
<ul>
<li>프로세스 스케줄링 상태 : 준비, 대기, 실행 등의 상태</li>
<li>프로세스 ID(PID) : 프로세스 ID, 해당 프로세스의 자식 프로세스 ID</li>
<li>프로세스 권한 : 컴퓨터 자원 또는 I/O 디바이스에 대한 권한 정보</li>
<li>프로그램 카운터 : 프로세스에서 실행해야 할 다음 명령어의 주소에 대한 포인터 </li>
<li>CPU 레지스터 : 프로세스를 실행하기 위해 저장해야 할 레지스터에 대한 정보 </li>
<li>CPU 스케줄링 정보 : CPU 스케줄러에 의해 중단된 시간 등에 대한 정보 </li>
<li>계정 정보 : 프로세스 실행에 사용된 CPU 사용량, 실행한 유저의 정보 </li>
<li>I/O 상태 정보 : 프로세스에 할당된 I/O 디바이스 목록 </li>
</ul>
<h3 id="컨텍스트-스위칭">컨텍스트 스위칭</h3>
<p>컨텍스트 스위칭(context switching)은 앞서 설명한 PCB를 교환하는 과정을 말합니다. 한 프로세스에 할당된 시간이 끝나거나 인터럽트에 의해 발생합니다. 
컴퓨터는 많은 프로그램을 동시에 실행하는 것처럼 보이지만 어떠한 시점에서 실행되고 있는 프로세스는 단 한 개이며, 많은 프로세스가 동시에 구동되는 것처럼 보이는 것은 다른 프로세스와의 컨텍스트 스위칭이 아주 빠른 속도로 실행되기 때문입니다. 
<img src="https://velog.velcdn.com/images/slr-09/post/27c40c8e-14f1-40a3-9179-cd1f9511dbd1/image.png" alt="">
위 그림을 보면 P0이 실행하다 멈추게 되면 운영체제는 프로세스 P0의 PCB를 먼저 저장을 합니다. 실행중이던 프로세스 P0이 대기 상태가 되면 프로세스 P1을 로드하여 실행합니다. 이후 프로세스 P1이 멈추게 되면 똑같이 P1의 PCB를 저장하고 프로세스 P0의 PCB를 로드합니다. </p>
<p>정리하면 컨텍스트 스위칭이란 CPU가 이전에 실행 중이던 프로세스 상태 및 정보를 PCB에 저장하고, 다음에 실행할 프로세스의 상태 및 정보를 PCB에서 읽어 레지스터에 옮기는 과정이라고 할 수 있습니다. </p>
<p>컨텍스트 스위칭이 일어날 때 유휴 시간(idle time)이 발생하고 컨텍스트 스위칭에는 캐시미스가 발생합니다. </p>
<pre><code>유휴 시간 : 컴퓨터가 작동 가능한데도 작업을 하지 않는 시간
캐시미스 : 구성 요소 또는 애플리케이션이 처리하도록 요청한 데이터가 캐시 메모리에 없는 상태</code></pre><h4 id="비용-캐시미스">비용: 캐시미스</h4>
<p>컨텍스트 스위칭이 일어날 때 프로세스가 가지고 있는 메모리 주소가 그대로 있으면 잘못된 주소 변환이 생기므로 캐시클리어 과정을 겪게 되고 이 때문에 캐시미스가 발생합니다. </p>
<h4 id="스레드에서의-컨텍스트-스위칭">스레드에서의 컨텍스트 스위칭</h4>
<p>컨텍스트 스위칭은 스레드에서도 일어나며 스레드는 스택 영역을 제외한 모든 메모리를 공유하기 때문에 비용이 더 적고 시간도 더 적게 걸립니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 1629번 곱셈 (Python)]]></title>
            <link>https://velog.io/@slr-09/%EB%B0%B1%EC%A4%80-1629%EB%B2%88-%EA%B3%B1%EC%85%88-Python</link>
            <guid>https://velog.io/@slr-09/%EB%B0%B1%EC%A4%80-1629%EB%B2%88-%EA%B3%B1%EC%85%88-Python</guid>
            <pubDate>Fri, 09 Jun 2023 06:46:18 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<p>자연수 A를 B번 곱한 수를 알고 싶다. 단 구하려는 수가 매우 커질 수 있으므로 이를 C로 나눈 나머지를 구하는 프로그램을 작성하시오.</p>
</blockquote>
<h2 id="입력">입력</h2>
<p>첫째 줄에 A, B, C가 빈 칸을 사이에 두고 순서대로 주어진다. A, B, C는 모두 2,147,483,647 이하의 자연수이다.</p>
<h2 id="출력">출력</h2>
<p>첫째 줄에 A를 B번 곱한 수를 C로 나눈 나머지를 출력한다.</p>
<hr>
<h2 id="아이디어">아이디어</h2>
<p>이 문제를 풀기 위해서는 나머지 분배 법칙을 알고있어야 한다. </p>
<pre><code>나머지 분배 법칙 
(A + B) % p = ((A % p) + (B % p)) % p
(A * B) % p = ((A % p) * (B % p)) % p
(A - B) % p = ((A % p) - (B % p) + p) % p</code></pre><p>문제의 예시를 사용하여 a=10, b=11, c=12라고 하자. 
구하고자 하는 것은 (10^11)%12이고 이 식을 다음과 같은 과정으로 바꿀 수 있다. </p>
<pre><code>(10^5 x 10^5 x 10)%12 
= ((10^5%12) x (10^5%12) x (10%12))%12
= {((10^2%12) x (10^2%12) x (10%12))%12 
  x ((10^2%12) x (10^2%12) x (10%12))%12 x (10%12)}%12</code></pre><h2 id="코드">코드</h2>
<pre><code>import sys
input = sys.stdin.readline

a,b,c = map(int,input().split())

def f(x,n):
  if n==1:
    return x%c
  t = f(x,n//2)
  if n%2==0:
    return (t*t)%c
  else:
    return (t*t*x)%c

print(f(a,b))</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[BFS 알고리즘]]></title>
            <link>https://velog.io/@slr-09/BFS-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@slr-09/BFS-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Mon, 05 Jun 2023 07:31:13 GMT</pubDate>
            <description><![CDATA[<h2 id="bfsbreadth-first-search">BFS(Breadth-First Search)</h2>
<blockquote>
<p>BFS는 너비 우선 탐색이라고도 부르며, 그래프에서 가까운 노드부터 우선적으로 탐색하는 알고리즘입니다. </p>
</blockquote>
<h2 id="동작-과정">동작 과정</h2>
<p>BFS는 큐 자료구조를 이용하며, 구체적인 동작 과정은 다음과 같습니다. </p>
<ol>
<li>탐색 시작 노드를 큐에 삽입하고 방문 처리를 합니다. </li>
<li>큐에서 노드를 꺼낸 후 해당 노드의 인접 노드 중 방문하지 않은 노드를 모두 큐에 삽입하고 방문 처리를 합니다. </li>
<li>더 이상 2번 과정을 수행할 수 없을 때까지 반복합니다. </li>
</ol>
<h2 id="동작-예시">동작 예시</h2>
<p>[Step 0] 그래프를 준비합니다. (방문 기준 : 번호가 낮은 인접 노드부터)</p>
<ul>
<li>시작 노드 1
<img src="https://velog.velcdn.com/images/slr-09/post/1f455201-be02-4eab-a133-2d77c183675b/image.png" alt=""></li>
</ul>
<p><img src="https://velog.velcdn.com/images/slr-09/post/30482b56-116e-4e4a-bb29-01977ec0d1be/image.png" alt=""></p>
<p>[Step 1] 시작 노드인 1을 큐에 삽입하고 방문 처리를 합니다.</p>
<p>[Step 2] 큐에서 노드 1을 꺼내 방문하지 않은 인접 노드 2,3,8을 큐에 삽입하고 방문 처리를 합니다. </p>
<p>[Step 3] 큐에서 노드 2를 꺼내 방문하지 않은 인접 노드 7을 큐에 삽입하고 방문 처리를 합니다. 
[Step 4] 큐에서 노드 3을 꺼내 방문하지 않은 인접 노드 4,5을 큐에 삽입하고 방문 처리를 합니다.</p>
<p>[Step 5] 큐에서 노드 8을 꺼내고 방문하지 않은 인접 노드가 없으므로 무시합니다. </p>
<p>이러한 과정을 반복했을 때 전체 노드의 탐색 순서(스택에 들어간 순서)는 다음과 같습니다.</p>
<pre><code>1 -&gt; 2 -&gt; 3 -&gt; 8 -&gt; 7 -&gt; 4 -&gt; 5 -&gt; 6</code></pre><hr>
<h3 id="구현-예시">구현 예시</h3>
<p>[python]</p>
<pre><code>from collections import deque

# bfs 메서드 정의 
def bfs(graph, start, visited):
    # 큐 구현을 위해 deque 라이브러리 사용
    queue = deque([start])
    # 현재 노드를 방문 처리
    visited[start] = True
    # 큐가 빌 때까지 반복
    while queue:
        # 큐에서 하나의 원소를 뽑아 출력
        v = queue.popleft()
        print(v,end=&#39; &#39;)
        # 아직 방문하지 않은 인접한 원소들을 큐에 삽입 
        for i in graph[v]:
            if not visited[i]:
                queue.append(i)
                visited[i] = True</code></pre><pre><code># 각 노드가 연결된 정보를 표현
graph =[
    [],
    [2,3,8],
    [1,7],
    [1,4,5],
    [3,5],
    [3,4],
    [7],
    [2,6,8],
    [1,7]
]

# 각 노드가 방문된 정보를 표현
visited = [False]*9

# bfs 함수 호출
bfs(graph, 1, visited)</code></pre>]]></description>
        </item>
    </channel>
</rss>