<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>코딩 잘하고 싶어</title>
    <link>https://codingwell.tistory.com/</link>
    <description>개발 일지 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Sat, 11 Apr 2026 10:22:07 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>통통푸딩</managingEditor>
    <image>
      <title>코딩 잘하고 싶어</title>
      <url>https://tistory1.daumcdn.net/tistory/3775817/attach/88e1046482d74431a60b7919b08fd5f7</url>
      <link>https://codingwell.tistory.com</link>
    </image>
    <item>
      <title>[백준] 1106번 - 호텔(Java)</title>
      <link>https://codingwell.tistory.com/192</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DP문제가 아직도 너무 어려워서, 여러 문제를 풀어보며 실력을 키우려고한다.&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;문제&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1106&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1106&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;풀이&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;아직도 점화식을 세우는 게 너무 어렵다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 문제도 막 어려운 편은 아닌 것 같은데, 풀지 못해서 인터넷을 참고하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이런식으로 감을 익히고 많은 문제를 풀다보면, 스스로 잘 풀어낼 수 있지 않을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 문제에서 점화식을 세우지 못하기도 했지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;문제 조건을 간과한 점도 있다. 약간의 함정(?)이라 할 수 있는데..&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;i&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;&quot;호텔의 고객을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;적어도&lt;/b&gt; &lt;b&gt;C명&lt;/b&gt; &lt;/span&gt;늘이기 위해 형택이가 투자해야 하는 돈의 최솟값을 구하는 것&quot; 이라는 조건이 있다.&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;여기서 &lt;b&gt;&quot;적어도&quot;&lt;/b&gt; 라는 말을 잘 캐치해야한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;꼭 C명을 딱 맞추는 것이 아니라, 그 이상이어도 더 최솟값이라면 그것을 선택해야한다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그래서 점화식을 세우고 계산할 때, C + 100명까지 계산해야한다. (C + 100인 이유는 도시에서 얻을 수 있는 고객의 수가 100명이 최대)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;dp[i] 배열은 i명을 추가하기 위한 최솟값이라고 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(dp 배열을 선언할 때도, dp = new int[C + 101] 로 선언해야한다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;dp 배열은 0 인덱스를 제외한 모든 인덱스 값을 최대값으로 선언해준다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇게 되면, 점화식은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;각 도시를 돌며, 현재 도시에서 얻을 수 있는 고객의 수 ~ C + 101까지 구해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739089284583&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for(int i=customerCnt; i&amp;lt;C+101; i++) {
	dp[i] = Math.min(dp[i], cost + dp[i - customerCnt]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그냥 dp[i]를 선택하면, 현재 도시를 선택하지 않는 것이고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;cost + dp[i - customerCnt]를 선택하게 되면, 현재 도시를 선택하는 것이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;lt;코드&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1739089631214&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

class Main {
	static int C, N;
	static int[][] promotionInfo;
	static int[] dp;

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine(), &quot; &quot;);
		StringBuilder sb = new StringBuilder();

		C = Integer.parseInt(st.nextToken());
		N = Integer.parseInt(st.nextToken());
		promotionInfo = new int[N][2];
		dp = new int[C+101];

		for (int i = 0; i &amp;lt; N; i++) {
			st = new StringTokenizer(br.readLine());
			int cost = Integer.parseInt(st.nextToken());
			int customerCnt = Integer.parseInt(st.nextToken());
			promotionInfo[i][0] = cost;
			promotionInfo[i][1] = customerCnt;
		}

		for (int i = 1; i &amp;lt;= C+100; i++) {
			dp[i] = 123456789;
		}

		for (int i = 0; i &amp;lt; N; i++) {
			int cost = promotionInfo[i][0];
			int customerCnt = promotionInfo[i][1];
			for (int j = customerCnt; j &amp;lt; C + 101; j++) {
				dp[j] = Math.min(dp[j], cost + dp[j - customerCnt]);
			}
		}

		int result = Integer.MAX_VALUE;
		for (int i = C; i &amp;lt; C + 101; i++) {
			result = Math.min(result, dp[i]);
		}

		br.close();
		System.out.print(result);
	}

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/Algorithm</category>
      <author>통통푸딩</author>
      <guid isPermaLink="true">https://codingwell.tistory.com/192</guid>
      <comments>https://codingwell.tistory.com/192#entry192comment</comments>
      <pubDate>Sun, 9 Feb 2025 17:27:49 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 부대복귀 (Java)</title>
      <link>https://codingwell.tistory.com/191</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;막 어려운 문제라기보다는,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;생각의 전환을 잘 하고 싶어서 글을 적게 된 문제이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132266?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/132266?language=java&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1710329052881&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/132266?language=java&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJ6dxv/hyVAA4z0NB/HWJ3hQIqu6wXr7aUOOWqNK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/swcNV/hyVADmHXmp/vtWRak04BkL57w5aUFlWmK/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/132266?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/132266?language=java&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJ6dxv/hyVAA4z0NB/HWJ3hQIqu6wXr7aUOOWqNK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/swcNV/hyVADmHXmp/vtWRak04BkL57w5aUFlWmK/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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;내가 푼 풀이&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;처음에는 dfs + dp를 이용해서 문제를 풀려고 했었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이전에 갔던 길이라면, 최단거리를 다시 구할 필요가 없기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이렇게 하니 답은 나왔지만, 시간 초과가 떠서 맞지 못했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;아래는 그 dfs 코드이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이미 최단거리를 구했던 곳이라면 더이상 가지않고 최단거리를 반환하여 바로 구할수 있도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710329276829&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private int dfs(int cur, int cnt, boolean[] visited, int dest) {
    if(cur == dest) {
        return cnt;
    }
    if(dp[cur] &amp;gt; 0) {
        return dp[cur] + cnt;
    }

    int minVal = Integer.MAX_VALUE;
    for (Integer next : roadList[cur]) {
        if(visited[next]) continue;

        visited[next] = true;
        minVal = Math.min(minVal, dfs(next, cnt+1, visited, dest));
        visited[next] = false;
    }

    if(minVal == Integer.MAX_VALUE) {
        dp[cur] = minVal;
    } else {
        dp[cur] = minVal - cnt;
    }
    return minVal;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그렇지만 이 코드는 결론적으로 시간초과가 났다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;방법들을 살펴보다가 다익스트라를 통해서 푼 것들을 발견했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;다른 사람의 풀이&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;다익스트라는 한 정점에서 다른 모든 정점으로 가는 최단경로를 구하는 것이기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이 문제는 모든 부대원이 강철부대 지점인 한 정점으로 간다는 점에서 다익스트라를 쓰기에 적합하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;거꾸로 도착 지점인 강철부대 지점을 기준으로 하여 구하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이렇게 반대로 생각하면 쉽게 풀 수 있는 문제인데, 이 생각을 하지 못했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이 생각을 하고 나면, 다익스트라를 알고 있다면 풀기에는 어렵지 않다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1710329631425&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

class Main {
	List&amp;lt;Integer&amp;gt;[] roadList;
	int[] d;

	public int[] solution(int n, int[][] roads, int[] sources, int destination) {
		int[] answer = new int[sources.length];
		roadList = new List[n+1];
		d = new int[n+1];
		Queue&amp;lt;int[]&amp;gt; pq = new PriorityQueue&amp;lt;int[]&amp;gt;((o1, o2) -&amp;gt; Integer.compare(o1[1], o2[1]));

		for (int i = 0; i &amp;lt;= n; i++) {
			roadList[i] = new ArrayList&amp;lt;&amp;gt;();
			d[i] = Integer.MAX_VALUE;
		}

		for (int[] road : roads) {
			roadList[road[0]].add(road[1]);
			roadList[road[1]].add(road[0]);
		}

		d[destination] = 0;
		pq.add(new int[]{destination, 0});

		while(!pq.isEmpty()) {
			int[] x = pq.poll();

			if(d[x[0]] &amp;lt; x[1]) continue;

			for (Integer next : roadList[x[0]]) {
				if(d[next] &amp;gt; (d[x[0]] + 1)) {
					pq.add(new int[]{next, d[x[0]] + 1});
					d[next] = d[x[0]] + 1;
				}
			}
		}

		for (int i = 0; i &amp;lt; sources.length; i++) {
			if(d[sources[i]] == Integer.MAX_VALUE) {
				answer[i] = -1;
				continue;
			}
			answer[i] = d[sources[i]];
		}

		return answer;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;우선순위 큐를 이용하여 쉽게 풀 수 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;생각을 전환해서 여러가지 알고리즘을 이용하여 잘 풀 수 있도록&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;많이 문제를 접해보고, 풀 때 협소하게 생각하지 않도록 노력해야겠다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS/Algorithm</category>
      <author>통통푸딩</author>
      <guid isPermaLink="true">https://codingwell.tistory.com/191</guid>
      <comments>https://codingwell.tistory.com/191#entry191comment</comments>
      <pubDate>Wed, 13 Mar 2024 20:35:38 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 상속, 다형성, Override 원리 (+메모리 구조)</title>
      <link>https://codingwell.tistory.com/190</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;상속과 다형성, Override는 자바의 객체지향에 있어서 중요한 개념들이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;어느정도 개념은 알고 있지만, OS관점? 메모리 구조 관점에서 보았을 때, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;어떤식으로 작동이 되는 지 원리를 알고 싶었고, 공부하게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; background-color: #f6e199;&quot;&gt;&lt;b&gt;&amp;nbsp;상속&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;상속관계인 클래스에서는 자식 클래스가 부모 클래스의 변수와 메서드를 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이게 어떻게 가능한걸까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;JVM 메모리 구조에는 Runtime Data Area가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;프로그램 수행을 위해 OS로부터 별도로 할당받은 메모리 공간이며,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;PC 레지스터, JVM 스택, Native 메서드 스택, 메서드 영역, 힙으로 공간이 나뉘어져있다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;자세한 내용은 아래 글을 참고하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1702638537881&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;[ Java ] JVM란? 자바의 실행 원리 알아보기&quot; data-og-description=&quot;1. JVM이란? JVM은 자바 가상 머신으로 Java Virtual Machine의 줄임말이다. Java는 운영체제(OS)에 구애받지 않고 실행할 수 있는데 , JVM이 그 역할을 한다. 자바 프로그램은 컴퓨터가 이해할 수 있는 언어(&quot; data-og-host=&quot;codingwell.tistory.com&quot; data-og-source-url=&quot;https://codingwell.tistory.com/66&quot; data-og-url=&quot;https://codingwell.tistory.com/66&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/NqrPx/hyULXgpgW9/RPA1ukS74B4PvJz4R8QnGk/img.png?width=800&amp;amp;height=520&amp;amp;face=0_0_800_520,https://scrap.kakaocdn.net/dn/pGCat/hyULXgpg1d/qwM9Ed9lMeHIMKLBmdkWp0/img.png?width=800&amp;amp;height=520&amp;amp;face=0_0_800_520,https://scrap.kakaocdn.net/dn/bDVG53/hyULZrMKRh/drYCR4kXN0fJIhzJy1M6o1/img.png?width=821&amp;amp;height=534&amp;amp;face=0_0_821_534&quot;&gt;&lt;a href=&quot;https://codingwell.tistory.com/66&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://codingwell.tistory.com/66&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/NqrPx/hyULXgpgW9/RPA1ukS74B4PvJz4R8QnGk/img.png?width=800&amp;amp;height=520&amp;amp;face=0_0_800_520,https://scrap.kakaocdn.net/dn/pGCat/hyULXgpg1d/qwM9Ed9lMeHIMKLBmdkWp0/img.png?width=800&amp;amp;height=520&amp;amp;face=0_0_800_520,https://scrap.kakaocdn.net/dn/bDVG53/hyULZrMKRh/drYCR4kXN0fJIhzJy1M6o1/img.png?width=821&amp;amp;height=534&amp;amp;face=0_0_821_534');&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;[ Java ] JVM란? 자바의 실행 원리 알아보기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1. JVM이란? JVM은 자바 가상 머신으로 Java Virtual Machine의 줄임말이다. Java는 운영체제(OS)에 구애받지 않고 실행할 수 있는데 , JVM이 그 역할을 한다. 자바 프로그램은 컴퓨터가 이해할 수 있는 언어(&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;codingwell.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;5가지 공간 중 메서드 영역은 클래스 정보를 처음 메모리 공간에 올릴 때 초기화 되는 대상을 저장하기 위한 공간이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;모든 스레드가 공유하는 영역이고, 클래스, 인터페이스, 메서드 정보, 필드, static 변수 등의 바이트 코드를 보관한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;구체적인 예시와 메모리 구조를 통해 원리를 설명하겠다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702638699522&quot; class=&quot;arduino&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;class Tv {
    boolean power;
    int channel;

    void power() {}
    void channelUp() {}
    void channelDown() {}
}

class CaptionTv extends Tv {
    String text;
    void caption() {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1702638759574&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CaptionTv c = new CaptionTv();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Tv 클래스와 CaptionTv 클래스는 상속관계이고 자식 클래스로 인스턴스 c를 생성하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;메모리 구조에선 어떤일이 일어날까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-16 오후 4.44.49.png&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EIecA/btsB7VtVAqi/tT9JQQnvLP8cYRnjM6mox0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EIecA/btsB7VtVAqi/tT9JQQnvLP8cYRnjM6mox0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EIecA/btsB7VtVAqi/tT9JQQnvLP8cYRnjM6mox0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEIecA%2FbtsB7VtVAqi%2FtT9JQQnvLP8cYRnjM6mox0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;753&quot; height=&quot;355&quot; data-filename=&quot;스크린샷 2023-12-16 오후 4.44.49.png&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1. Runtime Data Area의 메서드 영역에 이미 Tv 클래스 정보와 CaptionTv 클래스 정보가 들어있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2. 인스턴스를 생성하면 스택에 c 참조변수가 생성되고, CaptionTv 생성자가 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3. CaptionTv는 Tv를 상속받았으므로, c의 생성자 동작 시에 super()도 동작되어, 부모 클래스인 Tv의 생성자도 호출된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;4. 이에 따라 힙에 CapitonTv 객체가 생성된다.(부모 클래스의 멤버를 상속받아 포함하고 있음)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;5. 스택에 있는 참조변수 c는 대입 연산자(=)를 통해 힙에 생성된 CaptionTv 객체의 주소를 담고 있다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;  주의할 점&lt;/b&gt;&lt;br /&gt;많은 블로그에서 잘못 다루고 있는 내용을 발견했다.&lt;br /&gt;위의 4번 과정에서 힙에 자식과 부모 클래스 인스턴스 두개가 모두 생성된다고 언급한 블로그들이 많았다.&amp;nbsp;&lt;br /&gt;이것은 잘못된 내용이다.(제대로된 정보를 얻으려고 애씀ㅠ)&lt;br /&gt;&lt;br /&gt;자식 클래스에서 생성자를 호출할 때, 부모 클래스의 생성자도 호출된다.&lt;br /&gt;그렇다고 힙에 두개의 인스턴스가 생성되는 것이 아니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자식 클래스의 인스턴스만 생성된다.&lt;/b&gt;&lt;br /&gt;부모 클래스의 생성자는 따로 생성되지 않으며,&lt;br /&gt;&lt;b&gt;부모 클래스의 속성과 메서드를 자식 클래스에서 상속받아 사용할 수 있도록&lt;span&gt;&amp;nbsp;&lt;/span&gt;초기화하는 과정이다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이 때, 변수는 인스턴스가 생성될 때마다 새로 생성되지만, 같은 클래스의 메서드는 인스턴스가 달라도 같은 로직을 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그래서 메서드는 메서드 영역에 위치하여, 메서드 호출 시에 메서드 영역의 주소를 참조하여 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이로써 참조변수 c는 부모 클래스의 변수와 메서드에 접근할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;&amp;nbsp;다형성&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1) 클래스 형 변환&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1702637039563&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Tv t = new Tv();  //Tv인스턴스 생성에는 Tv 타입의 참조변수를 사용
CaptionTv c = new CaptionTv();  //CaptionTv인스턴스 생성에는 CaptionTv 타입의 참조변수를 사용&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Tv와 CaptionTv는 상속관계이며,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;두 클래스 각각 인스턴스를 생성했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;보통의 상황에선 위와 같이 인스턴스를 생성한다. 인스턴스 타입과 참조변수 타입을 일치시켜 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;다형성은 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 하는 것을 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;즉, 부모클래스 타입의 참조변수로 자식클래스의 인스턴스를 참조할 수 있도록 하였다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이런것을 클래스 형 변환 중에서 &lt;b&gt;업캐스팅&lt;/b&gt;이라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702637646572&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Tv t = new CaptionTv();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이렇게 생성할 경우 참조변수 t는 힙에 생성된 CaptionTv 인스턴스의 주소값을 가지게된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이 인스턴스는 상속관계인 부모의 모든 멤버를 상속받아 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-16 오후 5.39.15.png&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;365&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clII1J/btsB7jofxDp/f1o3imoedVFpabfzOtio61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clII1J/btsB7jofxDp/f1o3imoedVFpabfzOtio61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clII1J/btsB7jofxDp/f1o3imoedVFpabfzOtio61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclII1J%2FbtsB7jofxDp%2Ff1o3imoedVFpabfzOtio61%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;758&quot; height=&quot;349&quot; data-filename=&quot;스크린샷 2023-12-16 오후 5.39.15.png&quot; data-origin-width=&quot;793&quot; data-origin-height=&quot;365&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;여기서 t는 Tv클래스에 선언된 멤버들만 접근할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;업캐스팅을 통해 하위 클래스 객체를 상위 클래스 타입으로 취급되도록 했기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;상위 클래스에서 정의한 멤버만 접근가능한 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CaptionTv 인스턴스에는 상속받은 멤버들뿐만 아니라 CaptionTv 멤버 변수들도 모두 존재하지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일러가 접근할 수 있는 멤버를 Tv 클래스 멤버로 제한하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위의 예시에서는 CaptionTv의 text와 caption()은 사용할 수 없다.(자식 클래스에서 추가로 정의된 멤버)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;이처럼 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;참조변수 타입에 기반&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;해 멤버 변수와 메서드에 접근할 수 있기 때문이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;❓ 왜 참조변수 타입에 따라 접근 멤버를 결정할까&lt;/b&gt;&lt;br /&gt;타입 안전성(Type Safety)을 보장하기 위해!&lt;br /&gt;실행 시간에 발생할 수 있는 타입 관련 오류를 컴파일 시간에 미리 잡도록함&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;2) 오버라이드와 가상 메서드&amp;nbsp;&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;만약에 자식 클래스에서 오버라이드한 메서드가 있다면 어떻게 될까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;여기서 오버라이드 개념 자체는 따로 설명하지 않겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702645801393&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Tv {
    boolean power;
    int channel;

    void power() {}
    void channelUp() {}
    void channelDown() {}
    void volumeUp() {
        System.out.println(&quot;tv volume up&quot;);
    }
}

class CaptionTv extends Tv {
    String text;
    void caption() {}

    @Override
    void volumeUp() {
        System.out.println(&quot;caption tv volume up&quot;);
    }
}

class Main {
    public static void main(String[] args) {
        Tv t = new CaptionTv();
        t.volumeUp();  //caption tv volume up
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이 때, 자식 클래스인 CaptionTv의 volumeUp()이 출력됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위에서는 참조변수의 타입이 Tv이기 때문에 CaptionTv의 변수와 메서드는 접근할 수 없다고 했는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;오버라이딩한 메서드가 어떻게 작동할 수 있을까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;가상 메서드 테이블&lt;/b&gt;을 이용하기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;가상 메서드 테이블은 각 클래스마다 존재하고, 클래스가 메모리를 할당받을 때 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;자신의 메서드와 상속받은 모든 메서드의 주소를 모아 정리한 테이블을 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;JVM이 클래스를 로딩할 때, 메서드 영역에 메서드를 할당하고 가상 메서드 테이블을 생성한다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;가상 메서드 테이블은 각 메서드 이름과 실제 메모리 주소가 짝을 이룬다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;어떤 메서드가 호출되면, 이 테이블에서 주소 값을 찾아서 메서드 바이트코드를 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-16 오후 5.30.16.png&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;441&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zGGyN/btsB2R0T5Dz/SpvlenIvCNNcD02k9DFecK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zGGyN/btsB2R0T5Dz/SpvlenIvCNNcD02k9DFecK/img.png&quot; data-alt=&quot;JVM의 메서드 영역&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zGGyN/btsB2R0T5Dz/SpvlenIvCNNcD02k9DFecK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzGGyN%2FbtsB2R0T5Dz%2FSpvlenIvCNNcD02k9DFecK%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;686&quot; height=&quot;424&quot; data-filename=&quot;스크린샷 2023-12-16 오후 5.30.16.png&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;441&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;JVM의 메서드 영역&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;편의를 위해 Tv클래스의 channelUp()과 channelDown()은 생략했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위 그림에서 보듯 재정의된 volumeUp() 메서드는 서로 다른 메서드 주소를 가지게 되고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;실제 인스턴스에 해당하는 메서드를 호출하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;힙에 생성된 객체는 다음과 같이 &lt;b&gt;가상 메서드 테이블의 주소&lt;/b&gt;를 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;각 클래스의 객체가 생성될때마다 가상 메서드 테이블을 생성하는 것이 아니라,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;같은 클래스의 모든 객체들이 메서드 영역의 같은 테이블을 공유한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-16 오후 5.31.54.png&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WDLVV/btsB3ae5BYE/WF42qmcBLFmSwgz4yl8b1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WDLVV/btsB3ae5BYE/WF42qmcBLFmSwgz4yl8b1k/img.png&quot; data-alt=&quot;힙에 생성되는 인스턴스의 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WDLVV/btsB3ae5BYE/WF42qmcBLFmSwgz4yl8b1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWDLVV%2FbtsB3ae5BYE%2FWF42qmcBLFmSwgz4yl8b1k%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;471&quot; height=&quot;255&quot; data-filename=&quot;스크린샷 2023-12-16 오후 5.31.54.png&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;255&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;힙에 생성되는 인스턴스의 구조&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이를 통하여 가상 메서드 테이블에 접근하고, 가상 메서드 테이블에서 일치하는 메서드를 탐색한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;찾은 메서드의 메서드 주소 즉, 실제 메모리 주소에 접근하여 바이트코드를 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이렇게 프로그램이 실행된 후에, 가상 메서드 테이블을 통해 코드와 메모리가 바인딩 되는 이러한 과정을 &lt;b&gt;동적 바인딩&lt;/b&gt;이라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;따라서, 위의 예시에서 생성한 인스턴스인 CaptionTv의 재정의된 메서드가 실행되는것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Java/개념정리</category>
      <category>가상 메서드 테이블</category>
      <category>다형성</category>
      <category>동적 바인딩</category>
      <category>메서드 영역</category>
      <category>상속</category>
      <category>업캐스팅</category>
      <category>오버라이드</category>
      <category>오버라이딩</category>
      <category>클래스 형 변환</category>
      <author>통통푸딩</author>
      <guid isPermaLink="true">https://codingwell.tistory.com/190</guid>
      <comments>https://codingwell.tistory.com/190#entry190comment</comments>
      <pubDate>Sat, 16 Dec 2023 00:07:34 +0900</pubDate>
    </item>
    <item>
      <title>[운영체제] 메모리 구조 (Heap vs Stack)</title>
      <link>https://codingwell.tistory.com/189</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;메모리 구조에 대해서 어렴풋이만 알고 있는 것 같아 제대로 정리해보려고 합니다.&lt;/span&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;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;주 메모리&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;메모리는 크게 커널(kernal) 영역과 유저(User) 영역으로 나뉘어지고, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;커널 영역에는 운영체제가 적재되고 유저 영역에는 일반 프로세스가 적재됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;프로그램이 실행되기 위해서 프로그램이 주 메모리(RAM)에 load되어 프로세스가 되어야합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;또한, 프로그램 중에 사용할 변수와 데이터들을 메모리에 저장하여 사용합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;유저 영역에 적재되는 프로세스의 메모리 구조는 아래와 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;유저 영역 메모리 구조&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-12-14 오후 12.52.53.png&quot; data-origin-width=&quot;346&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uZmx4/btsBVCBYTwQ/DybkQbX0gWTIHTIO2VraaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uZmx4/btsBVCBYTwQ/DybkQbX0gWTIHTIO2VraaK/img.png&quot; data-alt=&quot;메모리 구조&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uZmx4/btsBVCBYTwQ/DybkQbX0gWTIHTIO2VraaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuZmx4%2FbtsBVCBYTwQ%2FDybkQbX0gWTIHTIO2VraaK%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;346&quot; height=&quot;524&quot; data-filename=&quot;스크린샷 2023-12-14 오후 12.52.53.png&quot; data-origin-width=&quot;346&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;메모리 구조&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;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;메모리 구조는 크게 &lt;b&gt;코드, 데이터, 힙, 스택 영역&lt;/b&gt;으로 나뉩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;운영체제가 실행 프로그램을 위해서 공간을 4가지로 할당해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1) 코드(Code) 영역&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;실행할 프로그램의 코드가 저장되는 영역으로 텍스트 영역이라고도 부릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;한마디로 명령문들이 저장되는 것인데, 제어문이나 함수, 상수들이 여기에 저장됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;2) 데이터(Data) 영역&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;데이터 영역은 프로그램의 전역 변수, 정적 변수(static), 상수가 저장되는 영역입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt; 즉, 보통 메인(main)함수 전에 선언되어 끝날때까지 남아있는 변수들입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;프로그램의 시작과 함께 할당되고, 종료될때까지 메모리상에 존재하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;3) 힙(Heap) 영역&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;힙 영역은 사용자가 직접 관리해야하는 메모리 영역입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;동적 할당이 되는 변수들은 힙 영역에 저장됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;사용자에 의해 공간이 동적으로 할당되고 해제됩니다.(런타임에 크기가 결정)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;커널 영역을 보호하기 위해 메모리의 낮은 주소에서 높은 주소 방향으로 할당됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;4) 스택(Stack) 영역&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;스택 영역은 함수의 호출과 관계되는 지역변수와 매개변수가 저장됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;힙보다 접근 속도가 빠르고, 명시적으로 변수를 할당/해제 할 필요가 없습니다.(컴파일 타임에 크기가 결정)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;함수의 호출과 함께 할당되고, 호출이 완료되면 소멸합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;커널 영역을 보호하기위해 메모리의 높은 주소에서 낮은 주소 방향으로 할당됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt; &amp;nbsp;컴파일 타임 vs&amp;nbsp;런타임&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;컴파일 타임은 소스코드가 실행 가능한 기계어 코드로 변환되어 머신에서 실행 가능한 프로그램이 되는 과정&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;런타임은 컴파일 과정을 마친 프로그램이 사용자에 의해 실행되고 동작되는 시점&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;힙(Heap) vs 스택(Stack)&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위에 그림에서 본 것 처럼 스택과 힙 영역은 사실 상 같은 공간을 사용하기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;스택 영역이 클수록 힙 영역이 작아지고, 스택 영역이 작을수록 힙 영역이 커집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;유저 영역보다 높은 주소에 커널 영역이 있기 때문에 커널 영역을 보호하기 위해,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;유저의 &lt;b&gt;스택 영역은 높은 주소에서 낮은 주소 방향&lt;/b&gt;으로 할당되고,&lt;b&gt; 힙 영역은 낮은 주소에서 높은 주소 방향&lt;/b&gt;으로 할당됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;커널 영역 반대로 데이터가 저장되기 때문에 커널 영역을 침범할 수 없습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;스택과 힙의 영역이 서로 상대의 영역을 침범하게 되면, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;스택 오버플로우(Stack Overflow)와 힙 오버플로우(Heap Overflow)가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;커널 영역 메모리 구조&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1) 코드 (커널 코드)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;2) 데이터&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;모든 하드웨어들(cpu, 메모리)을 관리하기 위한 자료구조,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;모든 프로세스들을 관리하기 위한 자료구조(PCB)&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;3) 스택 (커널 스택)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;각 프로세스마다 별도로 두고 있음(프로세스 커널 스택)&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS/운영체제</category>
      <author>통통푸딩</author>
      <guid isPermaLink="true">https://codingwell.tistory.com/189</guid>
      <comments>https://codingwell.tistory.com/189#entry189comment</comments>
      <pubDate>Thu, 14 Dec 2023 15:17:18 +0900</pubDate>
    </item>
    <item>
      <title>JWT 로그인 시 RefreshToken 저장에 Redis를 사용하는 이유</title>
      <link>https://codingwell.tistory.com/188</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이전에 진행했던 프로젝트에서 JWT 로그인을 구현하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;JWT 로그인에는 Access-Token과 Refresh-Token이 쓰입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;한마디로 표현하면, 액세스 토큰은 인증을 위한 토큰, 리프레시 토큰은 액세스 토큰을 재발급하기위한 토큰입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;리프레시 토큰은 서버에서 만들어서 MySQL에 저장하고, http 쿠키로 생성하여 프론트엔드로 넘겨주었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그런데 프로젝트 리팩토링을 진행하면서, MySQL에 저장했던 리프레시 토큰을 Redis로 바꾸려고 합니다.!!&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;왜 Redis로 바꾸는 것이 좋을 지에 대해 정리해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;Redis 란?&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vPolU/btsBMSe3D6c/FpiBx4LKvMywYYC1zIUxY0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vPolU/btsBMSe3D6c/FpiBx4LKvMywYYC1zIUxY0/img.webp&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vPolU/btsBMSe3D6c/FpiBx4LKvMywYYC1zIUxY0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvPolU%2FbtsBMSe3D6c%2FFpiBx4LKvMywYYC1zIUxY0%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;369&quot; height=&quot;199&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Redis(Remote Dictionary Server)는 [키(Key) - 값(Value)] 쌍의 해시 맵과 같은 구조를 가진 비관계형(NoSQL) 데이터베이스입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;또한, SSD/HHD 같은 보조기억장치가 아닌, 컴퓨의 주 메모리인 RAM에 데이터를 저장하는&amp;nbsp;&lt;b&gt;In-Memory 방식&lt;/b&gt;의 데이터베이스입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;따라서 별도의 쿼리문이 필요 없고, In-Memory에 저장되기 때문에 빠르다는 장점이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;  인-메모리 방식이 빠른 이유?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;프로그램을 실행할 때, CPU는 주 메모리인 RAM에 있는 데이터를 처리합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;RAM은 영구적으로 데이터를 저장하는 곳이 아니라, 일시적으로 데이터를 저장하는 &lt;b&gt;휘발성 메모리&lt;/b&gt;입니다.(전원이 꺼지면 날아감)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그래서 비휘발성의 특징을 가진 디스크(SSD/HDD)에서 필요한 데이터를 RAM에 올려 CPU가 처리하게끔 합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;즉, 디스크 -&amp;gt; 메모리 -&amp;gt; CPU의 과정을 거쳐야하지만, 인메모리 방식의 경우 메모리에 데이터를 저장하기 때문에 디스크에 접근을 하지 않아도 되어 빠른 속도를 가집니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이러한 이유로, Redis는 캐싱에 많이 쓰이기도 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;빠르다는 특징 외에도, Refresh-Token을 Redis에 저장하는 경우 장점이 몇가지 더 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;위에 말한 장점과 같이 정리해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;Refresh Token을 Redis에서 사용하는 이유&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1) 유효기간 지정 가능&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Redis는 데이터의 유효기간(TTL, Time-To-Live)을 정할 수 있습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;관계형 데이터베이스에서는 리프레시 토큰을 만료시키기 위해서 주기적으로 만료된 토큰을 삭제시키는 요청이나 스케쥴링을 해야하고, 이는 비효율적인 비용을 발생시킵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Redis에서는 리프레시 토큰의 만료일과 똑같이 맞춰 지정할 수 있어, 토큰이 자동으로 삭제되도록 하여 더 효율적입니다.&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2) 성능 이점&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Redis는 앞서 말한것처럼 레디스는 인-메모리 방식이라 성능이 RDB에 비해 빠릅니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;리프레시 토큰은 액세스 토큰을 재발급하기 위해서 자주 호출해야하기 때문에, 성능이 더 빠른 레디스(인-메모리)에 저장하는 것이 더 유리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199; font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;Redis vs RDB&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그런데, Redis는 휘발성 메모리여서 장애가 나거나 전원이 끊어질 경우 데이터가 날아갈 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그렇다면 영구적으로 저장할 수 있는 RDB가 낫지 않을까요?&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그렇지만, 리프레시토큰은 전부 지워지더라도 모든 유저가 로그아웃되고 재로그인을 해야한다는 것이 전부여서 그렇게 크리티컬한 일은 아니라고 판단하였습니다. 혹여나 데이터가 날아가 재로그인을 해야하는 상황을 고려하더라도, 속도가 매우 뛰어나기 때문에 Redis를 선택하는 것이 더 이득이라고 생각하여 리팩토링을 진행중입니다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;어떤 기술을 변경할때는 항상 트레이드오프가 있지만, 상황과 비용을 잘 따져서 선택하는 것이 중요하다고 생각합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>백엔드 및 서버</category>
      <category>access token</category>
      <category>JWT</category>
      <category>Redis</category>
      <category>refresh token</category>
      <category>레디스</category>
      <category>리프레시토큰</category>
      <category>액세스토큰</category>
      <author>통통푸딩</author>
      <guid isPermaLink="true">https://codingwell.tistory.com/188</guid>
      <comments>https://codingwell.tistory.com/188#entry188comment</comments>
      <pubDate>Wed, 13 Dec 2023 19:28:04 +0900</pubDate>
    </item>
    <item>
      <title>[데이터베이스] 트랜잭션과 동시성 제어</title>
      <link>https://codingwell.tistory.com/187</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;1. 특성 (ACID)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1) 원자성 (Atomicity)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 한 트랜잭션 내 모든 연산들이 완전히 수행되거나 전혀 수행되지 않아야함 (all or nothing)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- DBMS의 회복 모듈 : 시스템 다운이 될 경우, 트랜잭션의 영향을 취소함으로써 원자성 보장&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2) 일관성 (Consisitency)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 어떤 트랜잭션이 수행되기 전에 데이터베이스가 일관된 상태를 가졌다면 트랜잭션이 수행된 후에 데이터베이스는 또 다른 새로운 일관된 상태를 가짐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- DBMS의 무결성 제약 조건, 동시성 제어 모듈&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3) 고립성 (Isolation)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 한 트랜잭션이 데이터를 갱신하는 동안 이 트랜잭션이 완료되기 전에는 갱신중인 데이터를 다른 트랜잭션들이 접근하지 못하도록 해야함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 다수의 트랜잭션들이 동시에 수행되더라도 그 결과는 순차적으로 수행했을때랑 같아야함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- DBMS의 동시성 제어 모듈 : 고립성 보장&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;4) 지속성 (Durability)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 한 트랜잭션이 완료되면 이 트랜잭션이 갱신한 것은 그 후에 시스템이 고장나도 손실되지 않음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- DBMS의 회복 모듈 : 시스템이 다운되어도 지속성 보장&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;2. 동시성 제어&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1) 다수의 사용자들이 동시에 DBMS에 접근하고 트랜잭션을 수행할때, 서로 간섭이 생기지 않도록 해야함 (일관성과 무결성 보장해야함)&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2) 동시성과 일관성은 트레이드 오프 관계 !&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; text-align: start;&quot;&gt;동시성을 높이기 위해 lock을 최소화하면 일관성을 유지하기 어려워지고, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000; text-align: start;&quot;&gt;일관성을 높이기 위해 lock을 많이 사용하면 동시성이 낮아짐&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 동시성 : 트랜잭션들이 순차적으로 실행되는 것이 아니라, 트랜잭션을 구성하는 각각의 쿼리문들이 트랜잭션의 순서에 상관없이 동시에 실행되는 것&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 일관성 : 자신이 발생시킨 변경사항과 다른 트랜잭션의 변경 사항(읽을 수 있는 버전만 허용)을 포함해 일관성 있는 상태로 데이터를 제공하는 것&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3) 종류&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 직렬 스케줄 (serial schedule) : 여러 트랜잭션들의 집합을 한번에 한 트랜잭션씩 차례대로 수행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 비직렬 스케줄 (non-serial schedule) : 여러 트랜잭션들을 동시에 수행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 직렬 가능 (serializable) : 비직렬 스케줄의 결과가 어떤 직렬 스케줄의 수행결과와 동등함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;4) 동시성 제어를 하지않았을 때 생길 문제&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 갱신 손실 (Lost Update) : 수행중인 트랜잭션이 갱신한 내용을 다른 트랜잭션이 덮어써서 무효화됨&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 오손 데이터 읽기 (Dirty Read) : 완료되지 않은 트랜잭션이 갱신한 데이터를 읽는것&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 반복 가능하지 않은 읽기 (Unrepetable Read) : 한 트랜잭션이 동일한 데이터를 두번읽을때 서로 다른값을 읽는것&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;5) locking&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;동시성 제어를 위한 방법.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- x-lock (eXclusive lock, 독점 락)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;트랜잭션에서 갱신을 목적으로 데이터항목에 접근할때 요청.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;현재 걸려있는 락이 x-lock일 경우, x-lock과 s-lock 요청이 오면 둘다 대기해야함&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- s-lock (Shared lock, 공유 락)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;트랜잭션에서 읽을 목적으로 데이터 항목에 접근할때 요청.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;현재 걸려있는 락이 s-lock일 경우, s-lock 요청은 허용이지만, x-lock 요청은 대기해야함&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 2단계 락 프로토콜 (2-phase locking protocol) : 락을 요청하는 것과 해제하는 것이 2단계로 이루어짐&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;락 확장 단계 : 트랜잭션이 데이터 항목에 대하여 새로운 락을 요청할 수 있지만 가지고 있던 락을 하나라도 해제할 수 없음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;락 수축 단계 : 가지고 있던 락을 해제할 수 잇지만 새로운 락을 요청할 수 없음. 조금씩 해제할 수도 있고 한꺼번에 모든 락을 해제할 수도 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;lock point : 한 트랜잭션에서 필요로 하는 모든 락을 걸어놓은 시저&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 데드락(Deadlock)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2단계 락 프로토콜에선 데드록이 발생할 수 있음.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;두개 이상의 트랜잭션들이 서로 상대방이 보유하고 있는 락을 요청하면서 기다리고 있는 상태.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;ex) 예시&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1. T1이 X에 대해 x-lock 요청&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2. T2가 Y에 대해 x-lock 요청&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3. T1이 Y에 대해 s-lock이나 x-lock 요청하면 락 해제될때까지 대기&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;4. T2가 X에 대해 s-lock이나 x-lock 요청하면 락 해제될때까지 대기&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;-&amp;gt; 서로 무한정 대기하므로 데드락&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 팬텀 문제 (Phantom Problem) : 한 트랜잭션 내에서 동일한 쿼리를 두번 수행했을 때, 첫번째 쿼리에서 나타나지않았던 투플(Phantom)이 두번째 쿼리에서 나타나는 현상 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;ex) 다른 트랜잭션에서 중간에 Insert했을 경우.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;3. 회복(recovery)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1) 필요성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 트랜잭션 수행 도중이나 완료된 직후에 시스템이 다운됐을때, 원자성과 지속성을 보장하기 위해&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&amp;nbsp;- 고장 발생 전에 트랜잭션이 완료됐다면, 회복 모듈은 갱신 사항을 재수행(redo)하여 지속성을 보장함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 고장 발생 전에 트랜잭션이 완료되지 못했다면, 데이터베이스에 반영했을 가능성이 있는 갱신 사항을 취소(undo)하여 원자성을 보장함&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2) 로그를 사용한 즉시 갱신&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 즉시 갱신에서는 갱신 사항이 주기억 장치 버퍼에 유지되다가 완료되기 전이라도 디스크의 데이터베이스에 기록될 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 원자성과 지속성 보장을 위해 DBMS는 로그 파일을 유지함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 각 로그 레코드는 로그 순서번호로 식별되고 로그 레코드마다 트랜잭션 ID를 포함시킴. 동일한 트랜잭션에 속하는 로그 레코드들은 연결 리스트로 유지됨&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3) 완료점(commit point)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 한 트랜잭션의 데이터베이스 갱신 연산이 다 끝나고 로그에 기록되었을 때를 말함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 회복 모듈은 로그에 start와 commit 로그 레코드가 모두 존재하는 트랜잭션들은 재수행(redo), start는 존재하지만 commit 로그 레코드는 없는 트랜잭션들은 취소(undo)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;4) 로그 먼저 쓰기 (Write-Ahead Logging)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 주기억 장치 데이터베이스 버퍼에 갱신 사항을 기록하고, 로그 버퍼에는 로그 레코드를 기록&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 만약 데이터베이스 버퍼가 로그 버퍼보다 먼저 디스크에 기록되는 경우 : 로그 버퍼가 기록되기 전에 시스템이 다운되면 주기억 장치는 휘발성이어서 로그 값이 남아있지 않게됨 &amp;rarr; 트랜잭션의 취소가 불가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 따라서 데이터베이스 버퍼보다 로그 버퍼를 먼저 디스크에 기록해야함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;5) 체크 포인트(check point)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 시스템이 다운된 시점부터 오래전에 완료된 트랜잭션들은 이미 디스크에 반영되었을 가능성이 크지만, 로그를 사용하더라도 어떤 트랜잭션이 주기억 장치로부터 디스크에 기록되었는지 구분할 수가 없음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 그래서 DBMS는 회복 시 재수행할 트랜잭션의 수를 줄이기 위해 주기적으로 체크포인트를 수행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 주기억 장치의 버퍼 내용이 디스크에 강제로 기록됨 : 수행중인 트랜잭션을 잠시 멈추고 주기억 장치의 로그 버퍼를 디스크에 강제 출력 후 주기억 장치의 데이터베이스 버퍼를 디스크에 강제 출력함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 체크포인트가 끝나면 로그에 checkpoint 로그 레코드가 기록됨&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 보통 10~20분마다 한번씩 수행&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;ex) 예시&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3tbTA/btsAaOShgI1/GKCPwiCTknXJ3AbiFTAZP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3tbTA/btsAaOShgI1/GKCPwiCTknXJ3AbiFTAZP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3tbTA/btsAaOShgI1/GKCPwiCTknXJ3AbiFTAZP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3tbTA%2FbtsAaOShgI1%2FGKCPwiCTknXJ3AbiFTAZP0%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;471&quot; height=&quot;224&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;트랜잭션 T0, T1, T3은 무시. T4, T5는 재수행. T2, T6은 취소&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;&lt;b&gt;4. 고립 수준&lt;/b&gt;&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1) Read Uncommited&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 가장 낮은 고립 수준&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- s-lock을 걸지 않고 데이터를 읽기 때문에 Dirty Read 발생 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- Phantom Read, Unrepetable Read, Dirty Read 발생 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 갱신하려는 데이터에 대해서는 x-lock을 걸고, 트랜잭션이 끝날때까지 보유함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2) Read Commited&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 기본값으로 많이 사용되는 고립수준&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 다른 트랜잭션이 커밋한 정보만 읽을 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 읽으려는 데이터에 대해서 s-lock을 걸고, 읽기가 끝나자마자 락을 해제. 동일한 데이터를 다시 읽기위해 s-lock을 다시 걸고 데이터를 읽으면 이전에 읽은 값과 다른 값을 읽을수도 있음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- Phantom Read, Unrepetable Read 발생가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 갱신하려는 데이터에 대해서는 x-lock을 걸고, 트랜잭션이 끝날때까지 보유함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;3) Repetable Read&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 읽으려는 데이터에 대해 s-lock을 걸고, 트랜잭션이 끝날때까지 보유함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 한 트랜잭션 내에서 동일한 질의를 두번 이상 수행할 때 매번 같은 값을 포함한 결과를 검색하게됨&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 새로운 행을 추가하는 것을 막을 수는 없어서 Phantom Read 발생 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 갱신하려는 데이터에 대해서는 x-lock을 걸고, 트랜잭션이 끝날때까지 보유함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;4) Serializable&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 가장 높은 고립 수준. 가장 성능이 떨어짐&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 한 트랜잭션에서 읽고 쓰는 레코드들을 다른 트랜잭션에서 절대 접근할 수없음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 조회되는 투플들뿐만 아니라 인덱스에 대해서도 s-lock을 걸고 트랜잭션이 끝날때까지 보유함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 갱신하려는 데이터에 대해서는 x-lock을 걸고 트랜잭션이 끝날때까지 보유함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;- 기다렸다가 순차적 진행&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS/데이터베이스</category>
      <category>locking</category>
      <category>데이터베이스</category>
      <category>동시성 제어</category>
      <category>락</category>
      <category>트랜잭션</category>
      <author>통통푸딩</author>
      <guid isPermaLink="true">https://codingwell.tistory.com/187</guid>
      <comments>https://codingwell.tistory.com/187#entry187comment</comments>
      <pubDate>Mon, 13 Nov 2023 18:19:20 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] - 정렬 알고리즘(삽입 정렬, 선택 정렬, 버블 정렬, 합병 정렬, 퀵 정렬, 힙 정렬)</title>
      <link>https://codingwell.tistory.com/186</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;1. 삽입 정렬 (Insertion Sort)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미 정렬이 된 부분과 되지 않는 부분을 나누면서 정렬한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열의 앞의 요소부터 차례대로 이미 정렬이 된 부분과 비교하여, 적합한 위치를 찾아 삽입하는 알고리즘이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두번째 요소부터 왼쪽의 요소들(이미 정렬이 된 부분)과 비교하여 삽입 위치를 찾아야한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이미 정렬이 된 부분과 비교연산을 할때는, 왼쪽으로 옮겨가며 비교를 하여 삽입 위치를 찾는다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. [5, 3, 8, 1, 2, 7] &amp;rarr; 두번째 원소인 3과 왼쪽의 이미 정렬된 배열인 [5] 와 비교&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- 3과 5를 비교했을 때 5보다 작기 때문에 5를 한칸 뒤로 이동 : [3, 5]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. [3, 5, 8, 1, 2, 7] &amp;rarr; 세번째 원소인 8과 왼쪽의 이미 정렬된 배열인 [3, 5] 와 비교&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- 8과 5를 비교했을 때 5보다 크기 때문에 그대로 : [3, 5, 8]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. [3, 5, 8, 1, 2, 7] &amp;rarr; 네번째 원소인 1과 왼쪽의 이미 정렬된 배열인 [3, 5, 8]과 비교&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;1) 1과 8을 비교했을 때 8보다 작기 때문에 8을 한칸 뒤로 이동 : [3, 5, 1, 8]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;2) 1과 5를 비교했을 때 5보다 작기 때문에 5를 한칸 뒤로 이동 : [3, 1, 5, 8]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;3) 1과 3을 비교했을 때 3보다 작기 때문에 3을 한칸 뒤로 이동 : [1, 3, 5, 8]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;hellip;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마지막 원소까지 반복 &amp;rarr; [1, 2, 3, 5, 7, 8]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;private static void insertionSort(int[] arr) {
    for (int i = 1; i &amp;lt; arr.length; i++) {
        for (int j = i-1; j &amp;gt;=0; j--) {
            if(arr[j] &amp;gt; arr[i]) {
                int tmp = arr[j];
                arr[j] = arr[i];
                arr[i] = tmp;
            } else {
                break;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;시간 복잡도&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;평균, 최악의 경우 : O(n^2)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최선의 경우 : 한번의 비교 연산을 한 후 이동이 없다면(즉, 모두 정렬 되어있다면) O(n)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;평균 시간복잡도가 O(n^2)인 정렬들(삽입, 선택, 버블) 중에선 가장 빠르다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대부분 정렬이 이미 되어 있다면 효율적이게 됨.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2. 선택 정렬 (Selection Sort)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;심플하지만 비효율적인 알고리즘&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열을 선형탐색하며 가장 작은 원소를 배열 맨 앞으로 보내 맨 앞에 있던 원소와 자리를 바꿈 &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;rarr; 남은 값들 중 제일 작은 원소를 찾은 뒤 두번째 위치에 보냄 &amp;rarr; &amp;hellip;(마지막까지 반복)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. [5, 3, 8, 1, 2, 7] &amp;rarr; [1, 3, 8, 5, 2, 7] : 첫번째 원소 5와 최솟값 1을 교체&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. [1, 3, 8, 5, 2, 7] &amp;rarr; [1, 2, 8, 5, 3, 7] : 두번째 원소 3과 최솟값 2를 교체&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. [1, 2, 8, 5, 3, 7] &amp;rarr; [1, 2, 3, 5, 8, 7] : 세번째 원소 8과 최솟값 3을 교체&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;hellip;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마지막 원소까지 반복 &amp;rarr; [1, 2, 3, 5, 7, 8]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;private static void selectionSort(int[] arr) {
	for (int i = 0; i &amp;lt; arr.length-1; i++) {
		int minIdx = i;
		for (int j = i+1; j &amp;lt; arr.length; j++) {
			if(arr[minIdx] &amp;gt; arr[j]) {
				minIdx = j;
			}
		}
		int tmp = arr[i];
		arr[i] = arr[minIdx];
		arr[minIdx] = tmp;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;시간복잡도&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최선, 평균, 최악의 시간복잡도 : O(n^2)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;첫번째는 배열의 크기 (n-1)만큼 비교연산 하고, 다음은 (n-2)만큼, (n-3), &amp;hellip;, 1 까지 비교연산을 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;즉 (n-1) + (n-2) + &amp;hellip; + 2 + 1 = n(n-1)/2 이므로 O(n^2) 이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;선택정렬은 구현하기에 단순하지만, 비효율적이라고 볼수 있다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;3. 버블 정렬 (Bubble Sort)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열의 앞 요소부터 차례대로 진행하며, 서로 인접한 두 요소를 비교하여 바꾸면서 정렬하는 알고리즘&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;오름차순으로 정렬한다고 할 때, 현재 요소가 다음 요소보다 크면 두 요소를 바꾼다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;첫번째 탐색&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1-1. [5, 3, 8, 1, 2, 7] &amp;rarr; [3, 5, 8, 1, 2, 7] : 첫번째 요소 5 &amp;gt; 두번째 요소 3 이므로 두 요소를 바꾼다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1-2. [3, 5, 8, 1, 2, 7] &amp;rarr; [3, 5, 8, 1, 2, 7] : 두번째 요소 5 &amp;lt; 세번째 요소 8 이므로 그대로&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1-3. [3, 5, 8, 1, 2, 7] &amp;rarr; [3, 5, 1, 8, 2, 7] : 세번째 요소 8 &amp;gt; 네번째 요소 1 이므로 두 요소를 바꾼다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;hellip;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마지막 요소까지 반복하면 [3, 5, 1, 2, 7, 8] : 여기까지가 한번의 탐색이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가장 맨 끝으로 가장 큰 값이 이동했으므로 맨 끝을 빼고 다음 탐색을 시작한다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두번째 탐색&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2-1. [3, 5, 1, 2, 7, 8] &amp;rarr; [3, 5, 1, 2, 7, 8] : 첫번째 요소 3 &amp;lt; 두번째 요소 5 이므로 그대로&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2-2. [3, 5, 1, 2, 7, 8] &amp;rarr; [3, 1, 5, 2, 7, 8] : 두번째 요소 5 &amp;gt; 세번째 요소 1 이므로 두 요소를 바꾼다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;hellip;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;마지막 요소인 8을 빼고 7까지 반복하여 두번째 탐색을 끝낸다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;뒤에서 두번째까지 정렬을 완료했으므로 뒤에서 두개의 요소를 빼고 다음 탐색을 시작한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이런식으로 모든 요소를 정렬한다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;private static void bubbleSort(int[] arr) {
	for (int i = arr.length-1; i &amp;gt;=0; i--) {
		for (int j = 0; j &amp;lt; i; j++) {
			if(arr[j] &amp;gt; arr[j+1]) {
				int tmp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = tmp;
			}
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;시간 복잡도&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최선, 평균, 최악 시간복잡도 : O(n^2)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;비교 연산이 (n-1) + (n-2) + &amp;hellip; + 2 + 1 = n(n-1)/2 이므로 시간복잡도가 O(n^2)가 된다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;4. 합병 정렬 (Merge Sort)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;병합 정렬이라고도 한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열을 절반씩 나누어 각각 정렬한 후에 합친 후 다시 정렬하는 알고리즘이다. (분할 정복법 사용)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열을 절반씩 분할하는 Divide, 부분 배열을 정렬하면서(Conquer) 하나의 배열에 합병(Combine)합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서 정렬하면서 합병하는 방법은 다음과 같습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두 부분 배열이 있을 때, 예를 들어 위의 경우에서 [6,7]과 [5,8]을 합병할때는&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두 배열의 값들을 처음부터 하나씩 비교하여 더 작은 값을 새로운 배열로 옮깁니다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. [6,7] 과 [5,8]의 첫번째 값인 6과 5중 5가 더 작기 때문에 새로운 배열로 옮깁니다. &amp;rarr; [ 5 ]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. [6,7] 과 [8] 의 6과 8중 6이 더 작기 때문에 새로운 배열로 옮깁니다. &amp;rarr; [5, 6]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. [7] 과 [8]의 7과 8중 7이 더 작기 때문에 새로운 배열로 옯깁니다. &amp;rarr; [5, 6, 7]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4. [8]. 남은 값들을 모두 옮깁니다. &amp;rarr; [5, 6, 7, 8]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;실제 코드로 구현할 때는, 두 배열의 0번째 인덱스부터 비교한 후, 새로운 배열에 옮긴 부분 배열의 인덱스는 1씩 증가시켜주면 됩니다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;private static void mergeSort(int[] arr, int[] result, int start, int end) {
	if(start &amp;lt; end) {
		int mid = (start + end) / 2;
		mergeSort(arr,result, start, mid);
		mergeSort(arr,result,  mid+1, end);

		int left = start, right = mid + 1;
		int idx = left;

		while(left&amp;lt;=mid || right&amp;lt;=end) {
			if(right &amp;gt; end || (left &amp;lt;= mid &amp;amp;&amp;amp; arr[left] &amp;lt; arr[right])) {
				result[idx++] = arr[left++];
			} else {
				result[idx++] = arr[right++];
			}
		}

		for (int i = start; i &amp;lt;= end; i++) {
			arr[i] = result[i];
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;시간 복잡도&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최선, 평균, 최악의 경우 모두 O(N * logN) 이다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;데이터 분포에 영향을 덜 받는 효율적인 방법이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;정확히 절반씩 나누기 때문에 최악의 경우에도 O(NlogN)을 보장한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;재귀 호출의 깊이가 n &amp;rarr; n/2 &amp;rarr; n/4 &amp;rarr; &amp;hellip; &amp;rarr; 1 이므로 O(logN)이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기에 각 합병 단계에서 최대 n번씩 비교 연산을 하기 때문에 n을 곱해줘서 O(N*logN)이다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;5. 퀵 정렬 (Quick Sort)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;퀵 정렬은 매우 빠른 정렬 알고리즘이며, 분할 정복법을 사용한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러나 합병정렬과 달리 비균등하게 분할. 피벗(pivot)을 사용하여 두개의 리스트로 나누는 방법&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;피벗을 고른 후에 피벗보다 작은 원소들은 모두 피벗의 왼쪽으로 옮겨주고, 피벗보다 큰 요소들은 모두 피벗의 오른쪽으로 옮겨진다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;피벗의 왼쪽 리스트와 오른쪽 리스트 즉, 분할된 부분 리스트를 각각 재귀 호출하여 반복한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그때도 피벗을 정한 후에 두 개의 리스트로 나누는 것을 반복한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;더 이상 분할이 안될때까지 반복&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. [3, 7, 8, 1, 5, 9, 6, 2, 4]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) 피벗은 첫번째 원소인 3.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2) 피벗을 기준으로 오른쪽으로 가면서 피벗값보다 큰 값을 탐색. 두번째 원소인 7이 큰 값임&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3) 피벗을 기준으로 왼쪽으로 가면서 피벗값보다 작은 값 탐색. 여덟번째 원소인 2가 작은 값&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4) 이 두 원소의 자리를 바꿈(swap) &amp;rarr; [3, 2, 8, 1, 5, 9, 6, 7, 4]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. [3, 2, 8, 1, 5, 9, 6, 7, 4]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) 피벗은 첫번째 원소인 3.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2) 피벗을 기준으로 오른쪽으로 가면서 피벗값보다 큰 값을 탐색. 세번째 원소인 8이 큰 값임&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3) 피벗을 기준으로 왼쪽으로 가면서 피벗값보다 작은 값 탐색. 네번째 원소인 1이 작은 값&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4) 이 두 원소의 자리를 바꿈(swap) &amp;rarr; [3, 2, 1, 8, 5, 9, 6, 7, 4]&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. [3, 2, 1, 8, 5, 9, 6, 7, 4]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1) 피벗은 첫번째 원소인 3.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2) 피벗을 기준으로 오른쪽으로 가면서 피벗값보다 큰 값을 탐색. 네번째 원소인 8이 큰 값임&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3) 피벗을 기준으로 왼쪽으로 가면서 피벗값보다 작은 값 탐색. 세번째 원소인 1이 작은 값&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4) 큰 값이 작은 값이 엇갈리면(큰 값의 인덱스&amp;lt;작은 값의 인덱스), 작은 값과 피벗을 바꿈(swap) &amp;rarr; [1, 2, 3, 8, 5, 9, 6, 7, 4]&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5) 피벗(3)을 기준으로 왼쪽과 오른쪽으로 2개의 리스트가 나누어짐. 왼쪽은 3보다 작은 수들, 오른쪽은 3보다 큰 수들이 된다. 이 두 개의 리스트를 재귀 호출하여 독립적으로 반복 수행&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4. [1,2] 수행, [8, 5, 9, 6, 7, 4] 수행.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;hellip;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열의 크기가 1이하가 될때까지 반복&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;private static void quickSort(int[] arr, int pivot, int end) {
	if(pivot &amp;gt;= end) return;

	int left = pivot + 1, right = end;
	while(true) {
		while(left &amp;lt;= end &amp;amp;&amp;amp; arr[pivot] &amp;gt;= arr[left]) {
			left++;
		}

		while(right &amp;gt; pivot &amp;amp;&amp;amp; arr[pivot] &amp;lt;= arr[right]) {
			right--;
		}

		if (left &amp;gt; right) {
			int tmp = arr[right];
			arr[right] = arr[pivot];
			arr[pivot] = tmp;
			quickSort(arr, pivot, right-1);
			quickSort(arr, right+1, end);
			break;
		} else {
			int tmp = arr[left];
			arr[left] = arr[right];
			arr[right] = tmp;
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;시간 복잡도&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최선, 평균의 경우 : O(N logN)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최악의 경우 : O(n^2)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;재귀 호출의 깊이가 n/2 &amp;rarr; n/4 &amp;rarr; &amp;hellip; &amp;rarr; 1 이므로 O(logN)이고,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;각 단계에서 전체 원소를 돌면서 비교해야하기 때문에, 평균 N번 비교로 O(N * logN)이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러나 무작위로 선정된 한 원소를 사용하여 배열을 분할하고, 이 원소가 중간값에 가까운 값이 되리라는 보장이 없어서 치우치게 되면, 느리게 동작할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최악의 경우 배열이 계속해서 불균형하게 나누어질 경우 (이미 정렬된 리스트), 재귀 호출의 깊이가 N이 되기 때문에 O(N^2)이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;6. 힙 정렬 (Heap Sort)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;힙은 완전 이진 트리를 기반으로 우선순위 큐를 위하여 만들어진 자료구조.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최댓값과 최솟값을 빠르게 추출할 수 있음&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최대 힙은 내림차순 (트리의 루트노드가 가장 큰값), 최소 힙은 오름차순 정렬(루트노드가 가장 작은값)이다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;힙 정렬은 힙 생성 알고리즘 (Heapify)를 적용하여 힙 구조를 만드는 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Heapify는 부모노드와 자식노드의 크기를 비교하여 적절하게 서로 바꿔주는 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;노드 개수만큼 힙 생성 알고리즘을 수행하여 힙 구조를 만든다.&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;시간 복잡도&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;최선, 평균, 최악의 경우 : O(N logN)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;힙 트리의 전체 높이는 logN이므로 (완전이진트리) O(logN)이고,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;전체 노드의 개수가 n개이므로 총 O(N * logN)이 걸림&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&amp;nbsp;결론&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;비효율적이나 구현은 쉬운 정렬 알고리즘 : 삽입 정렬, 선택 정렬, 버블 정렬&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;효율적이고 구현이 복잡한 정렬 알고리즘 : 합병 정렬, 퀵 정렬, 힙 정렬&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 130px;&quot; border=&quot;1&quot; data-ke-style=&quot;style13&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;최선&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;평균&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;최악&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;삽입 정렬&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;N&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;N^2&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;N^2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;선택 정렬&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;N^2&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;N^2&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;N^2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;버블 정렬&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;N^2&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;N^2&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;N^2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;합병 정렬&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;NlogN&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;NlogN&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;NlogN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;퀵 정렬&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;NlogN&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;NlogN&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 18px;&quot;&gt;N^2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;힙 정렬&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;NlogN&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;NlogN&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 20px;&quot;&gt;NlogN&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/Algorithm</category>
      <category>버블 정렬</category>
      <category>삽입 정렬</category>
      <category>선택 정렬</category>
      <category>정렬 알고리즘</category>
      <category>퀵 정렬</category>
      <category>합병 정렬</category>
      <category>힙 정렬</category>
      <author>통통푸딩</author>
      <guid isPermaLink="true">https://codingwell.tistory.com/186</guid>
      <comments>https://codingwell.tistory.com/186#entry186comment</comments>
      <pubDate>Tue, 24 Oct 2023 00:31:46 +0900</pubDate>
    </item>
    <item>
      <title>[SWEA] 5653.줄기세포배양(모의 SW 역량테스트) - JAVA</title>
      <link>https://codingwell.tistory.com/185</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;SWEA에서 모의 역량테스트 문제 풀어보다가 신기한?흥미로운? 문제를 발견해서 적어보려고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;또, 내가 푼 방법은 다른사람들이 주로 푼 방법과는 달라서 두가지 방법을 모두 정리해보려한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #f89009;&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #006dd7;&quot;&gt;&lt;a style=&quot;color: #006dd7;&quot; href=&quot;https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRJ8EKe48DFAUo&amp;amp;categoryId=AWXRJ8EKe48DFAUo&amp;amp;categoryType=CODE&amp;amp;problemTitle=%EB%AA%A8%EC%9D%98&amp;amp;orderBy=FIRST_REG_DATETIME&amp;amp;selectCodeLang=ALL&amp;amp;select-1=&amp;amp;pageSize=10&amp;amp;pageIndex=1&quot;&gt;https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRJ8EKe48DFAUo&amp;amp;categoryId=AWXRJ8EKe48DFAUo&amp;amp;categoryType=CODE&amp;amp;problemTitle=%EB%AA%A8%EC%9D%98&amp;amp;orderBy=FIRST_REG_DATETIME&amp;amp;selectCodeLang=ALL&amp;amp;select-1=&amp;amp;pageSize=10&amp;amp;pageIndex=1&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1697188439149&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;SW Expert Academy&quot; data-og-description=&quot;SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!&quot; data-og-host=&quot;swexpertacademy.com&quot; data-og-source-url=&quot;https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRJ8EKe48DFAUo&amp;amp;categoryId=AWXRJ8EKe48DFAUo&amp;amp;categoryType=CODE&amp;amp;problemTitle=%EB%AA%A8%EC%9D%98&amp;amp;orderBy=FIRST_REG_DATETIME&amp;amp;selectCodeLang=ALL&amp;amp;select-1=&amp;amp;pageSize=10&amp;amp;pageIndex=1&quot; data-og-url=&quot;https://swexpertacademy.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c2dPjU/hyUdS6Mg0t/vW7YOBK3KWTk9Gx8pO0h1k/img.png?width=600&amp;amp;height=315&amp;amp;face=0_0_600_315,https://scrap.kakaocdn.net/dn/ei22hr/hyT9DclFZe/MFsEJzDNTUh1klfgTbXqEK/img.png?width=3378&amp;amp;height=3378&amp;amp;face=0_0_3378_3378,https://scrap.kakaocdn.net/dn/bvJlxV/hyT9Ikqnf8/i58aUDZTzCL3dZiYw2mXq1/img.png?width=3063&amp;amp;height=2071&amp;amp;face=0_0_3063_2071&quot;&gt;&lt;a href=&quot;https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRJ8EKe48DFAUo&amp;amp;categoryId=AWXRJ8EKe48DFAUo&amp;amp;categoryType=CODE&amp;amp;problemTitle=%EB%AA%A8%EC%9D%98&amp;amp;orderBy=FIRST_REG_DATETIME&amp;amp;selectCodeLang=ALL&amp;amp;select-1=&amp;amp;pageSize=10&amp;amp;pageIndex=1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRJ8EKe48DFAUo&amp;amp;categoryId=AWXRJ8EKe48DFAUo&amp;amp;categoryType=CODE&amp;amp;problemTitle=%EB%AA%A8%EC%9D%98&amp;amp;orderBy=FIRST_REG_DATETIME&amp;amp;selectCodeLang=ALL&amp;amp;select-1=&amp;amp;pageSize=10&amp;amp;pageIndex=1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c2dPjU/hyUdS6Mg0t/vW7YOBK3KWTk9Gx8pO0h1k/img.png?width=600&amp;amp;height=315&amp;amp;face=0_0_600_315,https://scrap.kakaocdn.net/dn/ei22hr/hyT9DclFZe/MFsEJzDNTUh1klfgTbXqEK/img.png?width=3378&amp;amp;height=3378&amp;amp;face=0_0_3378_3378,https://scrap.kakaocdn.net/dn/bvJlxV/hyT9Ikqnf8/i58aUDZTzCL3dZiYw2mXq1/img.png?width=3063&amp;amp;height=2071&amp;amp;face=0_0_3063_2071');&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;SW Expert Academy&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;swexpertacademy.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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #f89009;&quot;&gt;&lt;b&gt;내 풀이&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;일단, 문제를 처음 읽고 든 생각은.. 배양 용기의 크기가 무한하다고 가정해야하고, 배열이 계속해서 커지는데 어떻게 풀지?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;심지어 배열이 상하좌우로 알수없게 커진다는점이 고민을 하게 만들었고,,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;결국 난 배열이 아니라, 해시맵을 이용해서 풀었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;해시맵의 key 값을 x,y값으로 하고 value에는 세포의 정보를 담았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;초기에 좌상단이 0,0이므로 왼쪽으로 커진다면 마이너스 값이 키값으로 들어가게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;어차피 키값(인덱스값) 관리만 잘해준다면, 배열처럼 O(1)로 조회할 수 있기 때문에 bfs를 할때도 비효율적일 것은 없다고 생각했다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;나중에 사람들이 푼걸 좀 보니 배열을 주로 이용했는데, 배열의 최대 크기를 예상해서 배열을 크게 만들고, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;시작을 배열의 중간에서 시작하는 방법을 주로 많이 쓰더라..!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그래서 이것도 아래 정리해보면서 공부해보려한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;참고로, 해시맵을 돌면서 번식을 하는데, 죽은 세포와 살아있는 세포는 따로 해시맵을 두어서 쓸데없는 시간을 줄이도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;또, 세포 정보에는 생성된 시간과 생명력을 저장하도록 해, 이를 현재 시간과 비교해서 활성 상태,비활성 상태,번식을 하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;두 개 이상이 같은 곳으로 동시에 번식하려고 하는 경우, 생명력 수치가 더 높은 세포를 해시맵에 put했다.(맵은 put할 경우 갱신되기 때문)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;크기가 무한해지는 걸 어떻게할까의 고민을 해결하고보니, 생각보다 쉽게 풀렸다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1697189187878&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;
import java.util.Map.Entry;

/**
 * k시간 후 살아있는 줄기세포(비활성 + 활성) 총 개수 구하기
 * &amp;lt;p&amp;gt;
 * 초기 : 비활성 상태(x시간동안) 활성 - x시간동안 살아있은 후 죽음 - 첫1시간동안 네방향으로 동시에 번식(번식된 곳은 비활성) - 이미 줄기세포가 있는곳으론 번식 못함 - 두개이상이 같은곳으로 동시
 * 번식하려고하는 경우 생명력 수치가 높은 줄기세포가 함
 */

class Main {
    static class Point {
        int x, y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Point point = (Point) o;
            return x == point.x &amp;amp;&amp;amp; y == point.y;
        }

        @Override
        public int hashCode() {
            return Objects.hash(x, y);
        }
    }

    static class Cell {
        int x, y;
        int health;
        int createTime;
        int state; //0: 비활성, 1: 활성, 2: 죽음

        public Cell(int x, int y, int health, int createTime, int state) {
            this.x = x;
            this.y = y;
            this.health = health;
            this.createTime = createTime;
            this.state = state;
        }
    }

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();

        int T = Integer.parseInt(br.readLine().trim());

        for (int tc = 1; tc &amp;lt;= T; tc++) {
            StringTokenizer st = new StringTokenizer(br.readLine(), &quot; &quot;);
            int n = Integer.parseInt(st.nextToken());
            int m = Integer.parseInt(st.nextToken());
            int k = Integer.parseInt(st.nextToken());

            Map&amp;lt;Point, Cell&amp;gt; cells_lived = new HashMap&amp;lt;&amp;gt;();
            Set&amp;lt;Point&amp;gt; cells_dead = new HashSet&amp;lt;&amp;gt;();

            for (int i = 0; i &amp;lt; n; i++) {
                st = new StringTokenizer(br.readLine());
                for (int j = 0; j &amp;lt; m; j++) {
                    int health = Integer.parseInt(st.nextToken());
                    if (health == 0) {
                        continue;
                    }
                    cells_lived.put(new Point(i, j), new Cell(i, j, health, 0, 0));
                }
            }

            int[] dx = {0, 1, 0, -1}, dy = {1, 0, -1, 0};
            for (int time = 1; time &amp;lt;= k; time++) {
                Map&amp;lt;Point, Cell&amp;gt; newCells = new HashMap&amp;lt;&amp;gt;();  //새로 번식하는 세포들
                List&amp;lt;Point&amp;gt; dead = new ArrayList&amp;lt;&amp;gt;();  //새로 죽는 세포들

                for (Entry&amp;lt;Point, Cell&amp;gt; cellEntry : cells_lived.entrySet()) {
                    int x = cellEntry.getKey().x;
                    int y = cellEntry.getKey().y;
                    Cell cell = cellEntry.getValue();

                    if (cell.state == 2) {
                        continue;
                    }

                    if (cell.state == 0 &amp;amp;&amp;amp; (cell.createTime + cell.health) == time) {
                        cell.state = 1;  //활성화 상태로 변경
                    } else if (cell.state == 1) {
                        if (cell.createTime + cell.health + 1 == time) {
                            //번식
                            for (int i = 0; i &amp;lt; 4; i++) {
                                int nx = x + dx[i];
                                int ny = y + dy[i];
                                Point next = new Point(nx, ny);

                                if (cells_lived.containsKey(next) || cells_dead.contains(next)) {
                                    continue;
                                }

                                //두개 이상이 같은곳으로 동시 번식하려는 경우, 생명력 수치가 더 높은걸로 갱신
                                if ((newCells.containsKey(next) &amp;amp;&amp;amp; newCells.get(next).health &amp;lt; cell.health)
                                        || !newCells.containsKey(next)) {
                                    newCells.put(next, new Cell(nx, ny, cell.health, time, 0));
                                }
                            }
                        }
                        if (cell.createTime + cell.health * 2 == time) {  //죽은 상태로 변경
                            cell.state = 2;
                            dead.add(new Point(x, y));
                        }
                    }

                }

                cells_lived.putAll(newCells);

                for (Point point : dead) {  //살아있는 세포들에서 죽은 세포 제거
                    cells_lived.remove(point);
                }
                cells_dead.addAll(dead);
            }

            sb.append('#').append(tc).append(' ').append(cells_lived.size()).append('\n');
        }
        br.close();
        System.out.print(sb);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #f89009;&quot;&gt;&lt;b&gt;다른 풀이&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;앞서 말한대로 난 해시맵을 이용해서 풀었지만, 대부분은 배열을 크게 선언해서 사용한걸 봤다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;어차피 배열은 n*m이고 위아래로 최대 K만큼 더 커질 수 있기 때문에 map[n+2*k][m+2*k]으로 선언하면 된다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;사실 근데 이거보다 작게 선언해도 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;세포 생명력 수치가 1일때 가장 빠르게 번식하는데, 이 세포는 2시간에 한번씩 증식하기 때문에 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;k시간동안 최대 k/2번 증식한다고 볼 수 있다. 그래서 map[n+k][m+k]로 잡아도 된다.&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;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이렇게 배열의 최대 크기?를 예상한 후 생성해서 푸는 방법도 좋은 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;대부분의 사람들이 이렇게 푼거보니 내가 푼 방법은 신기한 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #f89009;&quot;&gt;&lt;b&gt;느낀점&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그래도 사람들이 주로 안 푼 방법으로 푼 것도 뭔가 뿌듯? 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그래도 여러가지 풀이들을 보면서 실력을 키워야겠다 생각이든다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS/Algorithm</category>
      <category>5653</category>
      <category>SWEA</category>
      <category>모의 SW 역량테스트</category>
      <category>자바</category>
      <category>줄기세포배양</category>
      <author>통통푸딩</author>
      <guid isPermaLink="true">https://codingwell.tistory.com/185</guid>
      <comments>https://codingwell.tistory.com/185#entry185comment</comments>
      <pubDate>Fri, 13 Oct 2023 19:11:57 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] 자바로 Stack 직접 구현해보기</title>
      <link>https://codingwell.tistory.com/184</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;오랜만에 자료구조를 직접 구현해보는 연습을 해보고있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;스택은 자주 사용하는 자료구조이며, 어느정도 개념도 잘 알고 있다보니 직접 구현하는 게 어렵진 않았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;그래서 나 스스로에게 미션(?)을 부여하면서 구현해보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;첫번째는, 제네릭을 사용해서 구현할 것.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;두번째는, 스택의 구성은 배열과 링크드리스트 두가지 버젼을 구현해볼것.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;이를 구현하기 위해서 인터페이스를 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;보통 스택에서 사용하는 메소드들을 인터페이스를 통해 선언해놓고 배열 스택과 링크드리스트 스택에서 구현하도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&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;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;Stack&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1691587065802&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface Stack&amp;lt;E&amp;gt; {
    boolean add(E data);
    E pop();
    E peek();
    E get(int idx);
    boolean isEmpty();
    void clear();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;1) 배열을 이용한 스택 - ArrayStack&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1691587253204&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Arrays;

public class ArrayStack&amp;lt;E&amp;gt; implements Stack&amp;lt;E&amp;gt; {
    private final int initCapacity = 100;
    private Object[] arr = new Object[initCapacity];
    private int size = 0;

    private void increaseCapacity() {
        int newSize = arr.length + initCapacity;
        arr = Arrays.copyOf(arr, newSize);
    }

    @Override
    public boolean add(E data) {
        if(size &amp;gt;= arr.length-1) {
            increaseCapacity();
        }

        arr[size++] = data;
        return true;
    }

    @Override
    public E pop() {
        E data = (E) arr[--size];
        arr[size] = 0;
        return data;
    }

    @Override
    public E peek() {
        return (E) arr[size-1];
    }

    @Override
    public E get(int idx) {
        if(idx &amp;gt;= size) {
            throw new ArrayIndexOutOfBoundsException();
        }
        return (E) arr[idx];
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public void clear() {
        size = 0;
        arr = new Object[initCapacity];
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;배열용 스택은  배열의 크기를 처음에 100만큼 할당해준다음, 꽉차면 배열의 크기를 100씩 늘려주는 식으로 구현했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;2) 링크드 리스트를 이용한 스택 - LinkedListStack&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1691588337485&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LinkedListStack&amp;lt;E&amp;gt; implements Stack&amp;lt;E&amp;gt; {
    private Node&amp;lt;E&amp;gt; head;
    private Node&amp;lt;E&amp;gt; top;
    private int size = 0;

    private class Node&amp;lt;E&amp;gt; {
        private Node&amp;lt;E&amp;gt; next;
        private E data;

        public Node(E data) {
            this.data = data;
        }
    }

    public Node&amp;lt;E&amp;gt; search(int idx) {
        if(size &amp;lt;= idx) {
            throw new ArrayIndexOutOfBoundsException(idx);
        }
        Node node = head;

        for (int i = 0; i &amp;lt; idx; i++) {
            node = node.next;
        }

        return node;
    }

    @Override
    public boolean add(E data) {
        Node&amp;lt;E&amp;gt; newNode = new Node&amp;lt;&amp;gt;(data);

        if(isEmpty()) {
            head = newNode;
            top = newNode;
        } else {
            Node&amp;lt;E&amp;gt; tmp = top;
            tmp.next = newNode;
            top = newNode;
        }
        size++;
        return true;
    }

    @Override
    public E pop() {
        Node&amp;lt;E&amp;gt; deleted = top;
        E data = deleted.data;

        if(size == 1) {
            head = null;
            top = null;
        } else {
            Node&amp;lt;E&amp;gt; node = search(size - 2);
            node.next = null;
            top = node;
        }
        deleted = null;
        size--;
        return data;
    }

    @Override
    public E peek() {
        return top.data;
    }

    @Override
    public E get(int idx) {
        return search(idx).data;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public void clear() {
        Node&amp;lt;E&amp;gt; node = head;

        while(node != null) {
            Node&amp;lt;E&amp;gt; tmp = node;
            node = node.next;
            tmp = null;
        }
        head = null;
        top = null;
        size = 0;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;링크드리스트 스택은 head와 top 노드 정보를 가지며 각 노드는 다음 노드 정보를 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;링크드리스트를 구현해봤다면 어렵지 않게 구현할 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; color: #000000;&quot;&gt;혹시 잘못된 부분이 있으면 댓글 남겨주세요!&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS/자료구조</category>
      <category>linkedlist</category>
      <category>링크드리스트 스택</category>
      <category>배열 스택</category>
      <category>자바</category>
      <author>통통푸딩</author>
      <guid isPermaLink="true">https://codingwell.tistory.com/184</guid>
      <comments>https://codingwell.tistory.com/184#entry184comment</comments>
      <pubDate>Thu, 10 Aug 2023 15:34:17 +0900</pubDate>
    </item>
    <item>
      <title>[자료구조] 자바로 LinkedList 직접 구현해보기</title>
      <link>https://codingwell.tistory.com/183</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만에 손코딩 연습도 해볼겸 개념정리도 한번 할겸 자바로 링크드리스트를 구현해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크드리스트는 노드가 연속적으로 다음 포인터를 가지고 있는 자료구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크드 리스트의 개념이나 특징을 공부한 후에 구현해보는 것을 추천한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 데이터 타입을 그냥 가장 상위 클래스인 Object 클래스로 구현해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 하면 여러개의 다른 데이터 타입을 넣을 수는 있겠지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 데이터 타입으로 고정할 수가 없었다. (예를 들면 자바 라이브러리 util에 있는 자료구조들처럼..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 제네릭 타입으로 구현하여 호출하는 쪽에서 타입을 지정하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 타입을 파라미터로 넣으면, 컴파일 오류가 나게하여 더 좋은 코드를 작성해보았다.&lt;/p&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1691574276333&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LinkedList&amp;lt;E&amp;gt; {
    private Node&amp;lt;E&amp;gt; head;
    private Node&amp;lt;E&amp;gt; tail;
    private int size = 0;

    private class Node&amp;lt;E&amp;gt; {
        private Node&amp;lt;E&amp;gt; next;
        private E data;

        public Node(E data) {
            this.data = data;
        }
    }

    public Node&amp;lt;E&amp;gt; search(int idx) {  //idx번째 있는 노드 반환
        if(idx &amp;gt;= size) {
            throw new IndexOutOfBoundsException();
        }
        Node&amp;lt;E&amp;gt; node = head;
        for (int i = 0; i &amp;lt; idx; i++) {
            node = node.next;
        }
        return node;
    }

    public void addFirst(E data) {  //맨 앞에 노드 추가
        Node&amp;lt;E&amp;gt; newNode = new Node(data);

        newNode.next = head;
        head = newNode;
        size++;

        if(newNode.next == null) {
            tail = head;
        }
    }

    public void add(int idx, E data) {  //idx번째에 노드 추가
        if(idx == 0) {
            addFirst(data);
            return;
        }

        Node&amp;lt;E&amp;gt; newNode = new Node&amp;lt;&amp;gt;(data);
        Node&amp;lt;E&amp;gt; tmp = search(idx-1);
        newNode.next = tmp.next;
        tmp.next = newNode;
        size++;

        if(newNode.next == null) {
            tail = newNode;
        }
    }

    public E removeFirst() {  //맨 앞 노드 삭제
        if(head == null) {
            throw new IndexOutOfBoundsException();
        }
        E data = head.data;
        Node&amp;lt;E&amp;gt; tmp = head;
        head = tmp.next;

        tmp = null;
        size--;
        return data;
    }

    public E remove(int idx) {  //idx번째에 있는 노드 삭제
        if(idx &amp;gt;= size) {
            throw new IndexOutOfBoundsException();
        }
        if(idx == 0) {
            return removeFirst();
        }

        Node&amp;lt;E&amp;gt; node = search(idx-1);
        Node&amp;lt;E&amp;gt; deleted = node.next;

        node.next = deleted.next;
        E data = deleted.data;
        deleted = null;
        size--;

        if(node.next == null) {
            tail = node;
        }
        return data;
    }

    public void print() {  //모든 노드의 데이터 순서대로 출력
        if(head == null) {
            System.out.println(&quot;x&quot;);
            return;
        }

        Node&amp;lt;E&amp;gt; node = head;
        while(node != null) {
            System.out.print(node.data + &quot; &quot;);
            node = node.next;
        }
        System.out.println();
    }

    public void printInfo() {  //현재 head, tail의 데이터와 size 출력
        if(size == 0) return;
        System.out.println(&quot;head : &quot; + head.data + &quot;,tail : &quot; + tail.data + &quot;,size : &quot; + size);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;링크드리스트는 head와 tail, size를 가지고 있으며, 각 노드는 다음 노드 정보와 데이터를 가지고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러가지 예외 처리는 적당히만 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 잘못된 부분 있으면 피드백 부탁드립니다!&lt;/p&gt;</description>
      <category>CS/자료구조</category>
      <author>통통푸딩</author>
      <guid isPermaLink="true">https://codingwell.tistory.com/183</guid>
      <comments>https://codingwell.tistory.com/183#entry183comment</comments>
      <pubDate>Wed, 9 Aug 2023 18:54:21 +0900</pubDate>
    </item>
  </channel>
</rss>