<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자의 생활</title>
    <link>https://han-studio.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 5 Aug 2026 07:17:57 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Developer성현</managingEditor>
    <item>
      <title>coroutine(코루틴)</title>
      <link>https://han-studio.tistory.com/74</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;코루틴 은 코틀린에서 비동기 처리를 쉽고 가볍게 할 수 있도록 제공하는 라이브러리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 란&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순차적으로 실행되는 것을 동기 라고 합니다. 하지만 서비스를 개발하다 보면 네트워크를 통해 데이터를 주고받는 작업이 거의 필수적이지만 이런 작업은 시간이 얼마나 걸릴지 모른다는 것입니다. 그래서 이런 작업은 호출을 한 뒤에 언제 응답이 올지 모르기 때문에 미뤄놓고 다음 작업을 먼저 수행하고 응답이 왔을 때 이어서 수행하는 것을 비동기 작업이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이런 작업이 어떻게 가능할까요?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OS는 여러 개의 스레드를 가지고 있습니다. 스레드는 마치 여러 프로그램을 동시에 실행시킬 수 있는 것처럼 도와주는 역할을 합니다. 하지만 스레드 또한 개수가 제한적이고 사용할 때 비용이 크기 때문에 남용해서는 안됩니다. 비용이 크다는 건 하나의 스레드가 하나의 프로그램을 도맡아서 처리하는 것이 아니고 여러 프로그램을 하나의 스레드가 번갈아 가면서 작업을 수행하는데 이 과정에서 다른 프로그램들의 수행하전 중간 데이터를 메모리에 저장을 해야 하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코루틴이 처리하는 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드를 사용하기 위해서는 비용이 크다고 했습니다. 그래서 코루틴은 여러 스레드를 사용하는 방법이 아닌 중단시키는 방식으로 작업을 처리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중단시킨다는 말은 스레드가 네트워크 처리와 같은 오래 걸리고 언제 끝날 지 모르는 작업들은 계속 점유하는 게 아닌 잠시 내려놓고 해당 스레드를 다른 작업을 실행할 수 있도록 넘겨준 뒤 해당 작업이 완료되면 다시 올라와서 스레드가 처리해 주는 방식입니다.&lt;/p&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;코루틴은 2가지 이상의 작업을 동시에 처리하는 게 아닙니다. 정확히 말하면 잠시 정지시키는 것입니다. 다만 스레드를 점유한 상태에서 정지하는 것이 아니라 해당 스레드가 다른 작업을 계속 수행할 수 있도록 풀어준 뒤 완료되면 다시 스레드가 이어서 작업을 처리해 주는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;코루틴 사용하기&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;elm&quot;&gt;&lt;code&gt;import kotlinx.coroutines.*&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;fun main(){
    runBlocking {
        println(&quot;start&quot;)
        delay(1000)
        println(&quot;stop&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 실행해 보면 start 가 출력된 후 약 1초 뒤에 stop 가 출력이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 이 코드들이 runBlocking라는 람다함수 내부에 있습니다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;runBlocking&lt;span&gt; 은 내부 로직이 모두 수행될 때까지 메인 스레드를 붙잡아 두는 역할을 합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;만약 이 함수가 없다면 delay로 시간을 지연시킬 수 없습니다. 이 delay 함수가 자로 정지함수입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;한번 delay 함수의 구조를 간단히 보겠습니다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;public suspend fun delay(timeMillis: Long)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이 함수에는 suspend라는 키워드가 있습니다. 이 키워드는 해당 함수가 정지함수라는 의미입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;그럼 저의도 정지함수를 만들어 보겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;suspend fun networkGetText(): String{
    delay(2000)
    return &quot;데이터1&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이렇게 네트워크에서 텍스트를 가져오는 모의 함수를 만들었습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;* 여기서 중요한 규칙이 있습니다. 정지함수는 정지함수 내부 또는 runBlocking와 같은 루틴을 대기할 수 있는 특수 함수 내부에서만 사용할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;fun main(){
    runBlocking {
        println(&quot;start&quot;)
        println(networkGetText())
        println(&quot;stop&quot;)
    }
}
suspend fun networkGetText(): String{
    delay(2000)
    return &quot;데이터1&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이 코드도 동일하게 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;runBlocking에서&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 start 가 출력된 후에 약 2초 뒤 데이터 1과 stop 가 출력이 됩니다.&lt;/p&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;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;하지만 보시다시피 이&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&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;letter-spacing: 0px;&quot;&gt;그럼 이번에는 정말 코루틴을 사용해 보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;방법 1 (launch)&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;fun main(){
    runBlocking {
        println(&quot;start&quot;)
        launch {
            println(networkGetText())
        }
        println(&quot;end&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;launch는 코루틴을 생성하는 람다함수입니다. 이 함수 내부에 정지함수를 넣으면 코루틴에 의해 정지함수는 특수한 메모리 공간에 들어가서 작업이 끝날 때까지 정지하고 해당 스레드는 계속 다음 작업을 수행하게 됩니다. 그리고 정지함수의 작업이 끝나면 다시 스레드에 의해 이어서 수행하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 코드를 실행해 보면 start 가 출력된 후 바로 end 가 출력이 되고 약 2초 뒤 데이터 1 이 출력됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법 2 (Async)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Async는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;launch와&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;직접 사용해 보겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;fun main(){
    runBlocking {
        println(&quot;start&quot;)
        val deferred = async {
            networkGetText()
        }
        println(deferred.await())
        println(&quot;end&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;async는 반환할 때 &amp;nbsp;Deferred 객체 타입으로 반환하게 됩니다. 그리고 await() 함수를 통해 반환값을 가져올 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 건 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Deferred&lt;span&gt; 타입의 객체를 정지함수가 실행이 완료될 때 반환하는 것이 아니라 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;async&lt;span&gt;&amp;nbsp; 함수가 호출될 때 바로 반환한다는 것입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;그리고 await()를 통해 결과가 출력됐는지를 감시하고 있다가 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;async&lt;span&gt; 내부의 값이 반환되면 await()를 통해 가져오게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;그런데 이 코드를 실행해 보시면 end 문자열이 await()를 통해 반한 된 후 실행되는 것을 보실 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;즉 await() 도 정지함수라는 것입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이렇게 코루틴을 사용해서 정지함수를 호출해도 스레드를 효율적으로 계속 사용할 수 있는 방법을 알았습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p 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;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;그럼 한 가지 간단한 실험을 해보겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;만약 코루틴 내부에서 일반 함수를 호출했는데 이 함수가 처리되는 시간이 1초라면 어떻게 될까요?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;한번 테스트해 보겠습니다&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;fun main(){
    runBlocking {
        println(&quot;start&quot;)
        launch {
            Thread.sleep(1000)
        }
        println(&quot;end&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이 코드는 코루틴이 생성되고 내부에서 스레드를 강제로 1초 동안 멈추게 합니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;중요한 건 sleep는 중지함수가 아니라는 것입니다. 즉 메인 스레드는 1초 동안 점추게 되어 아무런 작업도 못하게 되는 것입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 코드를 실행해 보면 이상하게도 start 가 출력되고 바로 end 가 출력된 후에 코루틴이 내부 로직이 수행된다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 동작하는 이유는 부모의 코드가 아직 끝나지 않았기 때문입니다. 조금 바꿔 말하면 부모의 코드가 메인스레드를 계속 점유하고 있었기 때문입니다. launch는 부모에게서 생성된 코루틴 이기 때문에 부모(상위)에서 실행되는 스레드의 점유가 끝나야 자식 코루틴이 사용할 수 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 지금까지 launch는 부모의 코드가 스레드를 잠시 내려놓았을 때 실행을 하게 된 것입니다. 그럼 코드를 조금 바꿔보겠습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;fun main(){
    runBlocking {
        println(&quot;start&quot;)
        launch {
            Thread.sleep(1000)
        }
        delay(1)
        println(&quot;end&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 부모코드가 실행하다 delay 정지함수를 만나 1ms 약 0.001초 동안 정지를 하고 있으면 스레드는 이 작은 틈에도 일을 하기 위해 이전에 코루틴이 생성된 부분을 수행하러 가는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dispatchers로 스레드 분리&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;스레드의 종류는 대표적으로 3가지가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Main: 프로그램이 실행될 때 기본으로 제공된 스레드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. IO: 네트워크 또는 파일 입출력 수행에 특화된 스레드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Default: 이 스레드는 많은 양의 연산에 특화된 스레드입니다. 아무것도 지정하지 않은 상태라면 해당 스레드를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*중요 저의는 지금까지 launch 나 async를 사용할 때 스레드를 지정하지 않았습니다. 하지만 실제로 사용된 스레드는 Default 가 아닌 main입니다. 그 이유는 runBlocking 내부에서 실행하고 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;launch&lt;span&gt; 나 async는 상위에서 이미 제공되는 스레드가 있으면 그것을 이어받아 사용하게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(확인방법)&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;println(Thread.currentThread().name)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;fun main(){
    runBlocking {
        println(&quot;start&quot;)
        launch(Dispatchers.IO) {
            Thread.sleep(1000)
            println(networkGetText())
        }
        delay(1)
        // yield() 추천
        println(&quot;end&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 launch 부분에서 코루틴이 생성이 되었을 때 이 코루틴을 실행하는 스레드는 IO 가 되는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 main 스레드는 1ms를 쉬고 바로 작업을 수행할 수 있게 되는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 delay(1)는 뭔가 꼼수처럼 보이기도 하고 컴퓨터 입장에서는 1ms 도 느린 시간이기 때문에 상당히 안 좋을 수 있습니다. 그래서 이런 경우에는 yield()를 사용하는 것이 더 올바른 코드라고 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;yield()는 제어권을 자식이라고 해도 자식이 먼저 호출을 했다면 권한을 넘겨주게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드를 분리하는 방법 중에서도 withContext()를 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;withContext()의 특징은 코루틴을 생성하지 않고 단순히 스레드만 변경하기 위한 용도입니다. 또한 정지함수입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;fun main(){
    runBlocking {
        println(&quot;start&quot;)
        withContext(Dispatchers.IO) {
            Thread.sleep(1000)
            println(networkGetText())
        }
        println(&quot;end&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드를 실행해 보면 단순히 동기적으로 실행이 됩니다. launch , async 와는 엄연히 다른 역할을 하는 정지함수입니다.&lt;/p&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;코루틴을 사용해서 네트워크에 요청을 하는 경우 응답이 오면 자동으로 코루틴이 종료가 됩니다. 하지만 응답이 오기 전에 사용자가 회면을 나간다거나 취소버튼을 누르면 코루틴은 기다릴 필요가 없게 되니 직접 종료를 해야 하는 경우가 있습니다. 혹은 요청을 하고 10초가 지났는데도 응답이 없으면 스스로 종료를 하는 경우도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 실행 중인 코루틴을 강제로 종료하는 방법을 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;launch와 async 함수는 호출이 되면 객체를 반환하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;launch는&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;async는 Deferred 타입의 객체를 반환합니다. ( Deferred는 Job를 상속하고 있습니다. )&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Job는&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;cancel()를 사용하면 실행 중인 코루틴을 종료할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;fun main(){
    runBlocking {
        val job: Job = launch {
            for (i in 0..&amp;lt; 5){
                println(i)
                delay(1000)
            }
        }
        launch {
            delay(3000)
            job.cancel()
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드를 실행하면 3 까지만 나오고 종료되는 것을 보실 수 있습니다.&lt;/p&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;</description>
      <category>kotlin</category>
      <category>concurrent</category>
      <category>kotlin</category>
      <category>코루틴</category>
      <category>코틀린</category>
      <author>Developer성현</author>
      <guid isPermaLink="true">https://han-studio.tistory.com/74</guid>
      <comments>https://han-studio.tistory.com/74#entry74comment</comments>
      <pubDate>Wed, 11 Feb 2026 02:27:42 +0900</pubDate>
    </item>
    <item>
      <title>평균(1546) [Kotlin]</title>
      <link>https://han-studio.tistory.com/73</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;세준이는 기말고사를 망쳤다. 세준이는 점수를 조작해서 집에 가져가기로 했다. 일단 세준이는 자기 점수 중에 최댓값을 골랐다. 이 값을 M이라고 한다. 그러고 나서 모든 점수를 점수/M*100으로 고쳤다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 세준이의 최고점이 70이고, 수학점수가 50이었으면 수학점수는 50/70*100이 되어 71.43점이 된다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;세준이의 성적을 위의 방법대로 새로 계산했을 때, 새로운 평균을 구하는 프로그램을 작성하시오.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;입력&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;첫째 줄에 시험 본 과목의 개수 N이 주어진다. 이 값은 1000보다 작거나 같다. 둘째 줄에 세준이의 현재 성적이 주어진다. 이 값은 100보다 작거나 같은 음이 아닌 정수이고, 적어도 하나의 값은 0보다 크다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;출력&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;첫째 줄에 새로운 평균을 출력한다. 실제 정답과 출력값의 절대오차 또는 상대오차가 10&lt;/span&gt;-2&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이하이면 정답이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;1212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v3b9N/dJMcagcVbZy/wK1AJB4QQ6NKvEOIJ0HVFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v3b9N/dJMcagcVbZy/wK1AJB4QQ6NKvEOIJ0HVFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v3b9N/dJMcagcVbZy/wK1AJB4QQ6NKvEOIJ0HVFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv3b9N%2FdJMcagcVbZy%2FwK1AJB4QQ6NKvEOIJ0HVFK%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;688&quot; height=&quot;855&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;1212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 해야 할 작업은 입력밭은 값을 가공할 수 있도록 정수 형태의 배열 또는 리스트로 만들어 주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 입력값은 성적 개수이기 때문에 C언어 같은 경우 배열의 크기를 잡아야 하기 때문에 필요하겠지만 Kotlin 은 필요 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 값은 성적 사이에 공백이 한 칸 존재합니다. 이 공백으로 성적을 구분하여 나눌 수 있습니다.&lt;u&gt;&lt;/u&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;val score = num.split(&quot; &quot;).map { it.toInt() }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;특정 문자를 통해 분리하는 방법은 split() 함수를 사용하면 쉽게 가능합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;매개변수로 특정 문자열을 넣으면 그 문자열을 기준으로 분리가 됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;참고로 split() 함수는 vararg으로 지원하기 때문에 여러 문자열도 동시에 적용할 수 있습니다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 문자열을 공백을 기준으로 나누어 List 형태로 반환하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에 map() 함수를 사용해서 숫자로 이루어진 문자열을 정수로 변환하여 List&amp;lt;Int&amp;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;이제 이 리스트에서 가장 큰 값을 구해야 합니다. 이때는 max() 함수를 사용하면 쉽게 찾을 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;val maxScore = score.max()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 구한 가장 높은 점수를 사용하여 새로운 평균을 만들면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 평균을 구하는 공식은 문제에서 제공해 주고 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;val newAvg = score.map { (it / maxScore.toDouble()) * 100 }.average()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 점수를 새로운 기준으로 다시 만들어야 하기 때문에 map()&amp;nbsp; 함수를 사용해서 모든 점수에 가장 큰 점수로 나눈 후 100을 곱하도록 하면 새로운 점수가 List&amp;lt;Int&amp;gt; 형태로 나오게 됩니다. 그리고 이 List의 평균을 구하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평균은 average() 함수로 구할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;fun main() {
    readln()
    val num = readln()

    val score = num.split(&quot; &quot;).map { it.toInt() }
    val maxScore = score.max()
    val newAvg = score.map { (it / maxScore.toDouble()) * 100 }.average()
    println(newAvg)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <category>코딩테스트/백준</category>
      <author>Developer성현</author>
      <guid isPermaLink="true">https://han-studio.tistory.com/73</guid>
      <comments>https://han-studio.tistory.com/73#entry73comment</comments>
      <pubDate>Wed, 3 Dec 2025 00:57:34 +0900</pubDate>
    </item>
    <item>
      <title>숫자의 합(11720) [Kotlin]</title>
      <link>https://han-studio.tistory.com/72</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/11720&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11720&lt;/a&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;N개의 숫자가 공백 없이 쓰여있다. 이 숫자를 모두 합해서 출력하는 프로그램을 작성하시오.&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;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;입력&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; background-color: #ffffff; letter-spacing: 0px;&quot;&gt;첫째 줄에 숫자의 개수 N (1 &amp;le; N &amp;le; 100)이 주어진다. 둘째 줄에 숫자 N개가 공백 없이 주어진다.&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;color: #555555; background-color: #ffffff; letter-spacing: 0px;&quot;&gt;출력&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;입력으로 주어진 숫자 N개의 합을 출력한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;838&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sUclf/dJMcaioevxA/yhjPqubkPMjM4MK3Ve4VZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sUclf/dJMcaioevxA/yhjPqubkPMjM4MK3Ve4VZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sUclf/dJMcaioevxA/yhjPqubkPMjM4MK3Ve4VZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsUclf%2FdJMcaioevxA%2FyhjPqubkPMjM4MK3Ve4VZ1%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;1220&quot; height=&quot;838&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;838&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 첫 번째 줄에 숫자의 개수가 입력된다고 했습니다. 만약 배열을 사용한다면 이 값을 사용해서 크기를 지정할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;val reader = BufferedReader(InputStreamReader(System.`in`))

reader.readLine()
val strNum = reader.readLine()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Koltin을 사용하면 배열을 사용하지 않아도 됩니다. 그러니 첫 번째 줄은 그냥 넘기면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다음 숫자를 문자열로 공백 없이 받는다고 했습니다. 이를 하나씩 잘라서 정수로 만들고 더하기만 하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 다양한 방법이 존재합니다. 모든 방법을 다룰 순 없으니 몇 가지만 사용해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 반복문 for 사용하기&lt;/h3&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;var arrNumberAdd = 0
for (num in strNum){
    arrNumberAdd += num.digitToInt()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 문자열을 반복문으로 문자 단위로 가져올 수 있습니다. 그리고 가져오는 동시에 정수로 변경하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 문자를 정수로 변경하는 함수로 digitToInt()를 사용하였습니다. 이것 말고도 toInt()라는 함수도 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름만 보면 두 개 다 정수로 변환하는 함수로 보이지만 큰 차이점이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;digitToInt() 은 문자를 정수로 변경할 수 있는지 확인을 한 후 변환이 가능하면 정수로 변환 수 반환해 줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;그리고 정수로 변환할 수 없는 문자라면 예외를 발생시킵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;추가로 digitToIntOrNull()이라는 함수도 존재합니다. 이는 동일한 역할을 하지만 정수로 변환을 못하는 값이라면 null을 반환합니다.&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;toInt()는 문자를 유니코드 형태로 반환을 해 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서는 문자열이 정수로만 나온다고 하였으니 digitToInt()을 사용하면 됩니다.&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;2. 컬렉션 함수, 집계함수 사용하기&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;var arrNumberAdd = 0
strNum.forEach {
    arrNumberAdd += it.digitToInt()
}&lt;/code&gt;&lt;/pre&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;val arrNumberAdd = strNum.map { it.digitToInt() }.sum()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 map {} 컬렉션 함수를 사용하여 문자열을 각각의 문자로 나눈 후 정수로 변환하여 List 형태로 만든 뒤 이를 sum() 집계함수로 모든 요소를 더하였습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;val arrNumberAdd = strNum.sumOf { it - '0' }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 sumOf {}를 사용하였습니다. 이는 문자열을 문자로 변환한 후 문자 '0'을 뺀 모든 요소를 더하고 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법들 말고도 수많은 방법들이 있겠지만 여기서는 이 정도만 해보겠습니다.&lt;/p&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>코딩테스트/백준</category>
      <author>Developer성현</author>
      <guid isPermaLink="true">https://han-studio.tistory.com/72</guid>
      <comments>https://han-studio.tistory.com/72#entry72comment</comments>
      <pubDate>Fri, 28 Nov 2025 16:45:47 +0900</pubDate>
    </item>
    <item>
      <title>상태 호이스팅</title>
      <link>https://han-studio.tistory.com/71</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;상태 호이스팅 이란 간단하게 말하면 Composable의 상태를 위로 올리는 개념을 말합니다.&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;h2 data-ke-size=&quot;size26&quot;&gt;stateful, stateless&lt;/h2&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이 두 개는 Composable 가 상태를 관리하는 방법들입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나씩 자세히 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. stateful&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 composable 함수 내부에서 상태를 관리하는 방법입니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Composable
fun CountButton(
    modifier: Modifier
){
    val count = remember { mutableIntStateOf(0) }
    Button(
        onClick = {count.intValue++},
        modifier = modifier
    ) {
        Text(
            text = count.intValue.toString()
        )
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드처럼 자기 자신이 직접 UI와 상태를 관리하는 방식을 stateful이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이런 식으로 코드를 작성하게 되면 나중에 해당&amp;nbsp; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;composable&lt;span&gt; 함수를 재활용할 수가 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하지만 무조건 이 방식을 사용하면 안 된다는 것은 아닙니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자세한 건 뒤에서 이어서 설명하겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;2. stateless&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이 방식이 상태 호이스팅에 사용되는 방식입니다.&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Composable
fun CountButton(
    buttonOnClick: () -&amp;gt; Unit,
    buttonText: String,
    modifier: Modifier
){
    Button(
        onClick = buttonOnClick,
        modifier = modifier
    ) {
        Text(
            text = buttonText
        )
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 고차함수 형태로 연결해서 상위 Composable 함수에 넘길 수 있도록 만들고 문자열도 파라미터로 받을 수 있도록 만드는 것을 stateless라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이 Composable 함수를 이렇게 사용할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Preview
@Composable
fun CountApp(){
    val count = remember { mutableIntStateOf(0) }
    Scaffold { innerPadding -&amp;gt;
        Box(
            modifier = Modifier
                .padding(innerPadding)
                .fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            CountButton(
                buttonOnClick = {
                    count.intValue++
                },
                buttonText = count.intValue.toString(),
                modifier = Modifier
            )
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이러한 구조를 저의는 처음부터 사용하고 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;739&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHleQq/dJMcahQk4cq/3MDoNvOMihLJHOEqdQLab0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHleQq/dJMcahQk4cq/3MDoNvOMihLJHOEqdQLab0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHleQq/dJMcahQk4cq/3MDoNvOMihLJHOEqdQLab0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHleQq%2FdJMcahQk4cq%2F3MDoNvOMihLJHOEqdQLab0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;739&quot; height=&quot;342&quot; data-origin-width=&quot;739&quot; data-origin-height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Button 컴포저블 함수를 보면 상태를 상위에서 제어할 수 있도록 Stateless 형태로 되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Stateless 형태로 하면 재활용성도 좋아지고 UI 테스트를 하기 편해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 무조건 모든 Composable 함수를 Stateless로 만들면 안 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 Composable 트리구조를 통해 이유를 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Compoable_Tree.png&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cD4MJD/dJMcafdUUSx/QWuI65JEZKZNWGo0hEkm4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cD4MJD/dJMcafdUUSx/QWuI65JEZKZNWGo0hEkm4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cD4MJD/dJMcafdUUSx/QWuI65JEZKZNWGo0hEkm4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcD4MJD%2FdJMcafdUUSx%2FQWuI65JEZKZNWGo0hEkm4K%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;617&quot; height=&quot;341&quot; data-filename=&quot;Compoable_Tree.png&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;341&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;모든 Compoable 함수는 결국 하나의 Composable에 모이게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 Root Composable 가 앱을 개발할 때 가장 최상단 컴포저블 함수입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 모든 Compoable 함수가 Stateless 방식을 사용해서 Root 함수까지 상태를 호이스팅 한다면 Root Composable 함수가 너무 큰 책임을 가지게 됩니다. 또한 이렇게 구성을 할 경우 리컴포지션이 수행될 때 비용이 커지게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리컴포지션에 관한 내용은 이전에 다루었지만 간단하게 다시 설명하면 리컴포지션은 상태가 변경된 부분만 재생성한다고 했습니다. 그러면 아무리 트리의 깊이가 깊어지더라도 상관없는 거 아닌가라고 생각할 수 있겠지만 결국 리컴포지션을 하기 위해서는 &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;slot table에 기록되어 있는 정보를 확인하고 상태를 기록하는 위치부터 읽는 부분까지 탐색을 해야 합니다. 그 과정에서 탐색할 Composable 이 많다면 비용이 증가하게 됩니다.&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;/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;위 트리구조 이미지로 예시를 들어보면 Text 와 Button 들은 Sub1, 2, 3 까지 상태를 호이스팅 하고 Sub1, 2, 3 에서 상태를 관리하게 되면 Sub1, 2, 3 은 Stateful 이 되는것이고 Text 와 Button 들은 Stateless 가 되는것 입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상으로 상태 호이스팅 과 stateful, stateless 개념을 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝까지 읽어주셔서 감사드립니다.&lt;/p&gt;</description>
      <category>안드로이드 앱 개발/Compose</category>
      <category>Android</category>
      <category>Compoae</category>
      <category>State Hoisting</category>
      <category>Stateful</category>
      <category>Stateless</category>
      <category>상태 호이스팅</category>
      <category>안드로이드</category>
      <category>컴포즈</category>
      <author>Developer성현</author>
      <guid isPermaLink="true">https://han-studio.tistory.com/71</guid>
      <comments>https://han-studio.tistory.com/71#entry71comment</comments>
      <pubDate>Tue, 18 Nov 2025 17:01:59 +0900</pubDate>
    </item>
    <item>
      <title>리컴포지션(ReComposition)</title>
      <link>https://han-studio.tistory.com/70</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;앱은 사용하는 과정에서 UI들의 상태값이 변경이 됩니다. 당연히 상태가 변경되면 화면은 UI를 새로 그려야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 XML을 사용한 View 방식은 UI의 속성이 변경되면 자동으로 해당 UI만 새로 렌더링을 하여 보여주는 방식이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;리컴포지션 이란&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Compose 방식은 UI 상태를 기준으로 함수를 재구성하는 방식을 사용합니다. 즉 상태가 변경되면 함수를 부분적으로만 다시 호출하게 됩니다. 이를 &lt;b&gt;리컴포지션이라고&lt;/b&gt; 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 다시 호출한다는 시점에서만 보면 너무 비효율이 아닌가 라는 생각이 들게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 컴포저블 함수에 여러 버튼, 텍스트들이 존재하는데 그중 하나의 상태만 변경돼도 컴포저블 함수가 다시 호출이 되면 렌더링을 위한 GPU사용량이 많아지게 되니 성능이 안 좋은 거 아닌가 라는 생각이 듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Compose는 화면을 그릴 때 내부적으로 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Composeable 함수의 UI 요소의 상태와 계층구조 위치정보 등을 &lt;/span&gt;Composition 트리를 만들어 두게 됩니다. 그래서 리컴포지션을 수행할 때 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Composition트리의 정보와 비교하여&lt;/span&gt;&amp;nbsp;상태가 변경되지 않은 UI는 그대로 유지하고 변경된 UI 만 다시 렌더링 하기 때문에 성능에 문제가 없다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 성능적으로는 XML View 방식과 거의 동일하다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 더 자세한 구조는 이후에 코드와 함께 설명하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;리컴포지션 이 발생하지 않는다면?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 당연히 값이 변경되더라도 UI 상태를 변경되지 않게 됩니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;const val LOG = &quot;MainActivity&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1763021712802&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Composable
fun MyCount(){

    Log.d(LOG, &quot;Composable 생성&quot;)

    Scaffold() {
        var countValue: Int = 0
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier
                .padding(it)
                .fillMaxSize()
        ) {
            Button(
                onClick = {
                    countValue++

                    Log.d(LOG, countValue.toString())
                }
            ) {
                Text(
                    text = countValue.toString()
                )
            }
        }
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼을 클릭하면 countValue 값이 1씩 증가하도록 하였습니다. 그리고 text 컴포저블에 출력하도록 하였고 log 에도 출력하게 만들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Logcat 창에서 Log 을 보시면 정상적으로 카운트가 되는걸을 볼 수 있습니다. 하지만 UI 에는 반영이 되지 않고 있습니다.&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;분명히 위에서는 UI상태가 변경이 되면 리컴포지션을 통해 컴포저블 함수가 재구성되면서 변경된 UI도 다시 렌더링이 돼야 합니다.&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;/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;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 어떻게 해야 UI상태가 변경됐는지를 compos runtime 시스템이 감지할 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법은 MutableState 를 사용하면 됩니다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;MutableState&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 에는 옵저버 패턴이 구현되어 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;그래서 값이 변경이 된 것을 확인하고 compos runtime를 실행시키게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;그러면 리컴포지션 을 수행하게 되고 MutableState&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 객체의 상태를 읽고있는 컴포저블 UI만 다시 렌더링을 수행하게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Composable
fun MyCount(){

    Scaffold() {
        val countValue = mutableIntStateOf(0)

        Log.d(LOG, countValue.intValue.toString())
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier
                .padding(it)
                .fillMaxSize()
        ) {
            Button(
                onClick = {
                    countValue.intValue++
                }
            ) {
                Text(
                    text = countValue.intValue.toString()
                )
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 MutableState&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt; 를 사용한 코드입니다. Log 도 약간 변경하였습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;countValue 변수에 값을 담는 구조가 바뀌었습니다. 기존에는 단순히 정수를 담고 있었지만 이번에는 파라미터로 정수를 받는 mutableIntStateOf라는 메서드를 사용해서 객체를 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;countValue에&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이 객체는 MutableState&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; 타입의 객체를 반환하게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;countValue의 객체에 있는 값을 변경하면 상태변경을 감지하고 리컴포지션을 수행하게 됩니다.&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;/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;리컴포지션은 상태가 변경되는 부분을 재구성한다고 했습니다. 해당 코드에는 버튼을 클릭하면 countValue.intValue 에 1씩 증가하도록 되어 있습니다. 그리고 Text 컴포저블 함수의 text와 Log에서&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; countValue.intValue를 읽고 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;즉 컴포저블 함수가 재구성되면서 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;mutableIntStateOf&lt;span&gt; 도 새로 만들어지기 때문에 계속 초기값만 담고 있는 것입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;추가설명&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;MutableState&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; 은 mutableStateOf 메서드를 사용하여 객체를 생성합니다. 그리고 이는 제네릭 타입입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;하지만 코드에서는 mutableIntSataeOf를 사용하였습니다. 이는 정수타입이며 이 객체의 타입은 MutableIntState 가 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p 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;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;물론 정수뿐 아니라 다양한 데이터 타입도 가능합니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p 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;color: #333333; text-align: start;&quot;&gt;제가 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;mutableStateOf&lt;span&gt; 말고 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;mutableIntSataeOf를 사용한 이유는 박싱 때문입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;mutableStateOf를 사용하더라고 결국 Int를 담으면 mutableIntSataeOf으로 박싱이 일어나기 때문입니다.&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;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;사실 어떤 걸 사용해도 상관없지만 IDE에서 경고를 띄우네요&lt;/span&gt;&lt;/span&gt;&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;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;리컴포지션에서도 데이터 유지하기&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 UI 상태를 변경하기 위해서는 리컴포지션을 통해서 재구성해야 한다고 했지만 문제는 객체 또한 재구성이 돼버려 초기값만 가지는 문제가 발행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이러한 문제를 해결하기 위해서는 어떻게 해야 할까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방법은 여러 가지가 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 리컴포지션 영역에서 제외시키기(추천 X)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분이 리컴포지션의 핵심 원리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;지금까지 위에서 작성한 글에서는 저의 표현이 부족하여 잘 와닿지 않으셨을 거라 생각됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 적절할지 모르겠지만 비유적으로 설명하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글을 작성하고 나서 변경해야 할 부분이 생기면 글을 처음부터 다시 작성하지 않고 변경할 부분만 지우고 다시 작성을 하게 되죠 리컴포지션이 동작하는 방식도 동일합니다. 변경할 부분만 새로 변경하고 다른 부분은 그대로 유지하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 리컴포지션이 실행되는 영역은 어떻게 나뉘게 될까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 컴포저블함수가 구성되는 영역으로 나뉘게 됩니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Composable
fun ComposableA(){
    ComposableB()
    ComposableC()
}

@Composable
fun ComposableB(){
    Text(
        text = &quot;&quot;
    )
}

@Composable
fun ComposableC(){
    Text(
        text = &quot;&quot;
    )
    Button(
        onClick = {}
    ) { }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;컴포저블함수_트리구조.png&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brDD0V/dJMcacuGZXx/oKEGckSVwDbG6oIlFEG541/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brDD0V/dJMcacuGZXx/oKEGckSVwDbG6oIlFEG541/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brDD0V/dJMcacuGZXx/oKEGckSVwDbG6oIlFEG541/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrDD0V%2FdJMcacuGZXx%2FoKEGckSVwDbG6oIlFEG541%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;374&quot; height=&quot;291&quot; data-filename=&quot;컴포저블함수_트리구조.png&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 컴포저블 함수를 트리구조로 표현한 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 ComposableA에서 상태변경만 발생하고 ComposableB에서 이 상태를 읽고 있다면 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;ComposableB에서만 리컴포지션이 발생하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 데이터를 유지해야 하는 곳에서는 상태를 읽지 않기만 하면 데이터는 유지된다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 실제로 동작하는지를 확인해 보겠습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;@Composable
fun MyCount(){

    Scaffold() {
        val countValue = mutableIntStateOf(0)

        //Log.d(LOG, countValue.intValue.toString())
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier
                .padding(it)
                .fillMaxSize()
        ) {
            Button(
                onClick = {
                    countValue.intValue++
                }
            ) {
                Text(
                    text = countValue.intValue.toString()
                )
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Log 부분을 주석처리 하여 상위 컴포저블함수에서는 상태를 읽지 않도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행시켜 보면 실제로 데이터가 정상적으로 카운트될 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이 방법은 권장하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 리컴포지션이 어떻게 수행되는지 원리를 알아보기 위해 작성한 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제로 앱을 개발할 때는 이런 방법은 절대 사용하지 않습니다.&lt;/b&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;2. remember 사용(권장 O)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법이 가장 많이 사용되는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;remember 은 리컴포지션이 발생해도 데이터를 유지할 수 있습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Composable
fun MyCount(){

    Scaffold() {
        val countValue = remember { mutableIntStateOf(0) }

        Log.d(LOG, countValue.intValue.toString())
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier
                .padding(it)
                .fillMaxSize()
        ) {
            Button(
                onClick = {
                    countValue.intValue++
                }
            ) {
                Text(
                    text = countValue.intValue.toString()
                )
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;remember는 고차함수 형태로 받을 수 있습니다. 그래서 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;remember에 mutableStateOf를 넣으면 리컴포지션이 발생해도 데이터를 유지할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;데이커를 유지할 수 있는 이유는 slot table에 데이터를 저장하고 있기 때문입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금 자세히 알아보겠습니다. 앱의 Activity 가 생성되면 Composition 객체가 생성이 되고 Activity 가 소멸되면 같이 사라지게 됩니다. 그리고 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Composition&lt;span&gt; 내부 slot table에 Compose 메서드의 정보들이 들어있습니다. 그리고 remember&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 상태를 관리하는 데이터도 저장이 되기 때문에 리컴포지션이 발생하더라도 slot table 에 데이터가 저장되어 있기 때문에 유지할 수 있게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;3. rememberSaveable 사용&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이거는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;remember은 Activity 가 재생성이 되면 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Composition&lt;span&gt; 객체도 소멸되고 다시 만들어지게 되므로 데이터가 사라지게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;예를 들어 화면을 회전을 하거나 다크모드 라이트모드로 변경하게 되면 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Activity&lt;span&gt; 가 새로 만들어지게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p 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;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;하지만 rememberSaveable를 사용하면 Composition&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 이 다시 만들어지게 돼도 데이터를 유지할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이 원리는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Activity&lt;span&gt; 가 소멸되기 전에 Bundle에 저장되고 Activity&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 가 새로 만들어지면서 Composition&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt; 객체가 다시 생성이 되면 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Bundle 에 저장된 Composition&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; 데이터로 복원하기 때문입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Composable
fun MyCount(){

    Scaffold() {
        val countValue = rememberSaveable { mutableIntStateOf(0) }

        Log.d(LOG, countValue.intValue.toString())
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier
                .padding(it)
                .fillMaxSize()
        ) {
            Button(
                onClick = {
                    countValue.intValue++
                }
            ) {
                Text(
                    text = countValue.intValue.toString()
                )
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만들면 회면을 회전하거나 테마를 변경하더라도 데이터가 유지될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. viewModel 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법은 여기서 설명하기에는 글이 너무 길어지기에 따로 다루도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글은 조금 많이 길었지만 끝까지 읽어 주셔서 감사합니다.&lt;/p&gt;</description>
      <category>안드로이드 앱 개발/Compose</category>
      <category>Android</category>
      <category>compose</category>
      <category>Composition</category>
      <category>recomposition</category>
      <category>리컴포지션</category>
      <category>안드로이드</category>
      <category>컴포즈</category>
      <category>컴포지션</category>
      <author>Developer성현</author>
      <guid isPermaLink="true">https://han-studio.tistory.com/70</guid>
      <comments>https://han-studio.tistory.com/70#entry70comment</comments>
      <pubDate>Fri, 14 Nov 2025 21:45:12 +0900</pubDate>
    </item>
    <item>
      <title>[ C언어 ] 자료구조_트리순회</title>
      <link>https://han-studio.tistory.com/69</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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 알아본 선형 자료구조들은 순회방법이 한 가지였습니다. 하지만 트리는 비선형 자료구조이기 때문에 순회방법이 여러 가지가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 순회방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 순회방법은 3가지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 전위순회(VLR)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 중위순회(LVR)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 후위순회(LRV)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 3가지 순회방법은 루트노드를 중심으로 왼쪽 서브트리 오른쪽 서브트리 중 어느 곳을 먼저 방문할 것인지를 의미합니다.&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-origin-width=&quot;321&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZRD5E/dJMcaaXTCvF/vMS0ulbl8XXvGs30auRGV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZRD5E/dJMcaaXTCvF/vMS0ulbl8XXvGs30auRGV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZRD5E/dJMcaaXTCvF/vMS0ulbl8XXvGs30auRGV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZRD5E%2FdJMcaaXTCvF%2FvMS0ulbl8XXvGs30auRGV0%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;321&quot; height=&quot;252&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 트리에서 3가지 방식으로 순회를 해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 전위순회: A -&amp;gt; B -&amp;gt; D -&amp;gt; E -&amp;gt; C -&amp;gt; F -&amp;gt; G&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 중위순회: D -&amp;gt; B -&amp;gt; E -&amp;gt; A -&amp;gt; F -&amp;gt; C -&amp;gt; G&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 후위순회: D -&amp;gt; E -&amp;gt; B -&amp;gt; F -&amp;gt; G -&amp;gt; C -&amp;gt; A&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이런 순회는 어떻게 할 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진트리 구조는 순환적인 구조를 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 이 구조는 순환함수 재귀함수를 사용하면 쉽게 구현할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 순회 구현&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 노드를 구현할 구조체를 만들어 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1762237900340&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef char element;

typedef struct Tree {
	element data;
	struct Tree* left;
	struct Tree* right;

}Tree;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 순회할 함수를 만들어 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1762237946948&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void preorder(Tree* tree)
{
	if (tree != NULL) {
		printf(&quot;[%c] &quot;, tree-&amp;gt;data);
		preorder(tree-&amp;gt;left);
		preorder(tree-&amp;gt;right);
	}
}

void inorder(Tree* tree)
{
	if (tree != NULL) {
		inorder(tree-&amp;gt;left);
		printf(&quot;[%c] &quot;, tree-&amp;gt;data);
		inorder(tree-&amp;gt;right);
	}
}

void postorder(Tree* tree)
{
	if (tree != NULL) {
		postorder(tree-&amp;gt;left);
		postorder(tree-&amp;gt;right);
		printf(&quot;[%c] &quot;, tree-&amp;gt;data);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면 조건문으로 트리가 NULL 이 아니라면 본인을 다시 호출하는 구조로 되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 다른 점은 함수 내부기준으로 루트노드에 값을 언제 확인하는지 순서가 다르다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 순회방법 정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 위 순회방법들은 어떤 경우에 사용하는 게 좋을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 순서 상관없이 모든 노드를 순회하기만 하면 된다 라면 어떤 방식을 사용해도 상관없지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하위 디렉터리 개수나 크기등을 측정해야 한다면 후위순회를 사용해야 하겠죠&lt;/p&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>자료구조/C언어</category>
      <category>tree</category>
      <category>이진트리</category>
      <category>이진트리 순회</category>
      <category>자료구조</category>
      <category>트리</category>
      <author>Developer성현</author>
      <guid isPermaLink="true">https://han-studio.tistory.com/69</guid>
      <comments>https://han-studio.tistory.com/69#entry69comment</comments>
      <pubDate>Tue, 4 Nov 2025 15:44:22 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드 생명 주기(Life Cycle)</title>
      <link>https://han-studio.tistory.com/68</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 생명주기 란&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드 OS는 앱이 시작하고 끝나는 과정에서 단계별로 나뉘어 실행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱을 개발하기 위해 프로젝트를 처음 생성하면 기본적으로 onCreate() 함수가 오버라이드 되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수는 앱이 실행될 때 가장 처음으로 호출되는 함수로 C, Java, Kotlin 프로그래밍을 할 때 main() 함수와 같은 위치의 함수라고 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드는 onCreate() 함수 이외에도 앱이 실행되고 종류 되는 단계별로 호출되는 함수가 존재합니다.&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;2. 액티비티(Activity) 상태&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생명주기는 activity 상태가 변경되는 과정이라고 보면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;액티비티 생명주기.png&quot; data-origin-width=&quot;459&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mH9Pd/dJMcaa4Eul9/nxsVQo3ia5Muj0sHYRWlw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mH9Pd/dJMcaa4Eul9/nxsVQo3ia5Muj0sHYRWlw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mH9Pd/dJMcaa4Eul9/nxsVQo3ia5Muj0sHYRWlw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmH9Pd%2FdJMcaa4Eul9%2FnxsVQo3ia5Muj0sHYRWlw0%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;459&quot; height=&quot;549&quot; data-filename=&quot;액티비티 생명주기.png&quot; data-origin-width=&quot;459&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Activity의 상태는 5단계로 구분됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Activity 가 시작될 때의 과정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;초기화 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분에서는 Activity 가 생성되기 위한 시스템을 준비하는 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리에 Activity인스턴스를 로드하는 등의 작업이 실행되며 이 부분은 개발자가 관여할 수 없는 부분입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;생성 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분에서 개발한 Activity 화면이 메모리에 올라가게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 아직 화면에 그려지지는 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시작 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서부터 화면이 사용자에게 보이게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 버튼입력과 같은 상호작용은 아직 못합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;재개 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분이 실제로 앱을 사용하는 단계입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤로 가기 버튼이나 finish() 함수를 호출하기 전까지 계속 이 단계를 유지합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Activity 가 종료될 때의 과정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;재개 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분이 실제로 앱을 사용하는 단계입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뒤로 가기 버튼이나 finish() 함수를 호출하기 전까지 계속 이 단계를 유지합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시작 단계&lt;/b&gt;&lt;/p&gt;
&lt;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;&lt;b&gt;생성 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분에서 개발한 Activity 화면이 메모리에 내려가고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면에서 사라지게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;초기화 단계&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분에서 Activity 가 제거되기 위한 시스템을 준비하는 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리에 Activity 인스턴스를 삭제하는 등의 작업이 실행되며 이 부분은 개발자가 관여할 수 없는 부분입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 생명주기 호출 순서&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 단계들은 앱을 실행하고 종료하는 과정에서 시스템에 의해 자동으로 전환되며 전환될 때 콜백함수가 호출이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콜백 함수들은 위 이미지에 나와있는 순서대로 실행이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지를 보시면 onStart()와 함께 onRestart() 콜백함수도 같이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;onRestart() 이 함수는 시작 단계에서 생성 단계로 내려왔다가 다시 시작 단계로 올라갈 때 호출되는 함수입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱이 실행되는 과정에서 실제로 어떻게 생명주기 가 동작하는지 확인해 보기 위해 Log를 찍어 보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        Log.d(TAG, &quot;onCreate&quot;)
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            LifeCycleTheme(
                darkTheme = false
            ) {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -&amp;gt;
                    Box(
                        contentAlignment = Alignment.Center,
                        modifier = Modifier
                            .fillMaxSize()
                    ){
                        Text(
                            text = &quot;LifeCycle&quot;,
                            fontSize = 32.sp,
                            modifier = Modifier
                                .padding(innerPadding)
                        )
                    }
                }
            }
        }
    }

    override fun onStart() {
        super.onStart()
        Log.d(TAG, &quot;onStart&quot;)

        finish()
    }

    override fun onRestart() {
        super.onRestart()
        Log.d(TAG, &quot;onRestart&quot;)
    }

    override fun onResume() {
        super.onResume()
        Log.d(TAG, &quot;onResume&quot;)
    }

    override fun onPause() {
        super.onPause()
        Log.d(TAG, &quot;onPause&quot;)
    }

    override fun onStop() {
        super.onStop()
        Log.d(TAG, &quot;onStop&quot;)
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, &quot;onDestroy&quot;)
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 Compose 코드는 신경 쓸 필요는 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 앱 실행&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;167&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9FtL4/dJMcad1nDMB/dipBGfv4C8k5wRORGkslw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9FtL4/dJMcad1nDMB/dipBGfv4C8k5wRORGkslw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9FtL4/dJMcad1nDMB/dipBGfv4C8k5wRORGkslw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9FtL4%2FdJMcad1nDMB%2FdipBGfv4C8k5wRORGkslw1%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;167&quot; height=&quot;78&quot; data-origin-width=&quot;167&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 앱 종료(홈버튼 클릭) &amp;amp; 전원버튼 클릭 또는 화면 자동꺼짐&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;166&quot; data-origin-height=&quot;55&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFjEl5/dJMcacnRIol/KKIxIMuA93cMQsxJz9AKn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFjEl5/dJMcacnRIol/KKIxIMuA93cMQsxJz9AKn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFjEl5/dJMcacnRIol/KKIxIMuA93cMQsxJz9AKn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFjEl5%2FdJMcacnRIol%2FKKIxIMuA93cMQsxJz9AKn1%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;166&quot; height=&quot;55&quot; data-origin-width=&quot;166&quot; data-origin-height=&quot;55&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 앱 재실행&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;176&quot; data-origin-height=&quot;81&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEQ6Zx/dJMcae63x2P/060eS2KOx3Ft1AmDR8V0n0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEQ6Zx/dJMcae63x2P/060eS2KOx3Ft1AmDR8V0n0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEQ6Zx/dJMcae63x2P/060eS2KOx3Ft1AmDR8V0n0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEQ6Zx%2FdJMcae63x2P%2F060eS2KOx3Ft1AmDR8V0n0%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;176&quot; height=&quot;81&quot; data-origin-width=&quot;176&quot; data-origin-height=&quot;81&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 앱 종료(뒤로 가기 버튼 클릭)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;171&quot; data-origin-height=&quot;83&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AychG/dJMcajAwLkY/gmfKXDZXhbVT5E7PsrEMA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AychG/dJMcajAwLkY/gmfKXDZXhbVT5E7PsrEMA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AychG/dJMcajAwLkY/gmfKXDZXhbVT5E7PsrEMA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAychG%2FdJMcajAwLkY%2FgmfKXDZXhbVT5E7PsrEMA1%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;171&quot; height=&quot;83&quot; data-origin-width=&quot;171&quot; data-origin-height=&quot;83&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 앱이 실행되고 종료될 때 생명주기를 따르게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 버그 또는 시스템에 의해 다르게 동작하는 경우도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱이 실행되는 과정에서 사용자가 의도적으로 강제종료 하거나 시스템 또는 코드에 문제가 발생하면 생명주기를 따라 앱이 종료되지 못하는 경우도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 코드에 문제가 있는 경우&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;override fun onStart() {
    super.onStart()
    Log.d(TAG, &quot;onStart&quot;)

    finish()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의도적으로 시스템에 문제를 만들기 어렵기 때문에 onStart 함수 내부에 finish() 종료함수를 호출해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;181&quot; data-origin-height=&quot;117&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMsGfJ/dJMcacVHHki/9HU7fd1t33zUovKqaTIOCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMsGfJ/dJMcacVHHki/9HU7fd1t33zUovKqaTIOCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMsGfJ/dJMcacVHHki/9HU7fd1t33zUovKqaTIOCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMsGfJ%2FdJMcacVHHki%2F9HU7fd1t33zUovKqaTIOCk%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;181&quot; height=&quot;117&quot; data-origin-width=&quot;181&quot; data-origin-height=&quot;117&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 onResume와 onPause 함수가 호출되지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 사용자가 강제종료 했을 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강제종료 나는 건 앱이 뒤로 가기 버튼 또는 finish()을 사용하여 정상적으로 종료되는 경우를 제외하고 최근목록 탭에서 앱을 스와이프 또는 모두 갇기 기능을 통해 종료하는 경우를 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우에는 일반적으로 onStop 까지는 호출되지만 onDestroy는 호출이 안됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 시스템에 의해 강제종료되는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 코드에 문제가 생긴 경우 에러가 발생하여 종료되는 경우도 있지만 홈 버튼을 눌러 onStop 만 호출되어 프로세스가 살아있는 경우에도 시스템 자원이 부족할 경우 사용하지 않은 앱으로 간주되어 시스템이 자동으로 메모리에서 프로세스를 회수하게 됩니다.&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;4. 생명주기가 중요한 이유&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱을 사용하지 않는 시간 화면을 꺼놓는 경우, 앱을 종료하지 않고 다른 앱을 사용할 때와 같은 경우 에 만약 계속 리소스(카메라, 센서 등) 자원을 사용하고 있으면 하드웨어 자원이 낭비되고 배터리 또한 소모량이 많아지게 됩니다. 그래서 onPause 또는 onStop 에서 리소스 자원을 해제해 주는등의 작업을 해 주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 앱을 재실행 할때 onRestart, onStart 에서 리소스 를 다시 로드하는 작업을 수행할 수 있습니다.&lt;/p&gt;</description>
      <category>안드로이드 앱 개발</category>
      <category>Andriod</category>
      <category>life cycle</category>
      <category>안드로이드</category>
      <category>안드로이드 생명주기</category>
      <author>Developer성현</author>
      <guid isPermaLink="true">https://han-studio.tistory.com/68</guid>
      <comments>https://han-studio.tistory.com/68#entry68comment</comments>
      <pubDate>Sun, 2 Nov 2025 22:19:04 +0900</pubDate>
    </item>
    <item>
      <title>[ C언어 ] 자료구조_트리(Link)</title>
      <link>https://han-studio.tistory.com/67</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 트리 자료구조란&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리 자료구조는 이름대로 나뭇가지를 모방하여 자료들을 구조화한 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전까지 했던 array, linkedlist, stack, queue, deque 자료구조 들은 선형으로 이루어진 자료구조였지만 이번 Tree 자료구조는 비선형 자료구조입니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 80.6977%; height: 256px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 256px;&quot;&gt;
&lt;td style=&quot;width: 40.3488%; height: 256px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트리1.png&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm3OEA/dJMcafLEnJm/X8JV6K40EYlh0a6gkoQJU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm3OEA/dJMcafLEnJm/X8JV6K40EYlh0a6gkoQJU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm3OEA/dJMcafLEnJm/X8JV6K40EYlh0a6gkoQJU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm3OEA%2FdJMcafLEnJm%2FX8JV6K40EYlh0a6gkoQJU0%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;321&quot; height=&quot;252&quot; data-filename=&quot;트리1.png&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 40.3489%; height: 256px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트리2.png&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m4XqZ/dJMcaeeT9hT/ftZMJlRPFgpKLuBKcOMBck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m4XqZ/dJMcaeeT9hT/ftZMJlRPFgpKLuBKcOMBck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m4XqZ/dJMcaeeT9hT/ftZMJlRPFgpKLuBKcOMBck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm4XqZ%2FdJMcaeeT9hT%2FftZMJlRPFgpKLuBKcOMBck%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;341&quot; height=&quot;332&quot; data-filename=&quot;트리2.png&quot; data-origin-width=&quot;341&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리구조는 크게 부모 노드와 자식 노드로 분류할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 트리에서는 A가 부모 노드이고 왼쪽에 연결되어 있는(B) 노드와 오른쪽에 연결되어 있는(C) 노드는 A의 자식노드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 (B) 노드 입장에서는 (D)와 (E) 노드가 자식노드이고 (B) 노드가 부모노드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가족관계도 와 동일한 구조라고 보시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 트리 구성과 용어&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트리3.png&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byXug1/dJMcaiVUwHv/bvLkPK5dMwKsXTtRJ0zEN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byXug1/dJMcaiVUwHv/bvLkPK5dMwKsXTtRJ0zEN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byXug1/dJMcaiVUwHv/bvLkPK5dMwKsXTtRJ0zEN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyXug1%2FdJMcaiVUwHv%2FbvLkPK5dMwKsXTtRJ0zEN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;441&quot; height=&quot;332&quot; data-filename=&quot;트리3.png&quot; data-origin-width=&quot;441&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리구조의 명칭을 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;루트노드&lt;/b&gt;: 이는 트리에서 가장 상위에 위치해 있는 단 하나의 노드를 의미합니다. 위 그림에서는 A노드가 루트노드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;부모노드&lt;/b&gt;: 자식노드 입장에서 한 단계 위에 있는 노드를 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자식노드&lt;/b&gt;: 부모 노드의 하위에 있는 노드를 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;후손노드&lt;/b&gt;: 이는 자식노드에서 확장된 의미로 특정 노드의 하위에 있는 모든 노드를 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;형제노드&lt;/b&gt;: 이는 같은 레벨에 위치한 노드를 의미합니다. 레벨 2에 위치해 있는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;B와 C는&lt;span&gt; &lt;/span&gt;&lt;/span&gt;형제노드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단말노드&lt;/b&gt;: 이는 자식 노드가 하나도 없는 노드입니다. 위 트리에서는 E, F, G, H, I 가 단말 노드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;차수&lt;/b&gt;: 이는 자식노드의 개수를 의미합니다. 위 트리에서 C 노드의 자식노드는 F, G, H 3개 이기 때문에 차수는 3입니다.&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;3. 일반트리, 이진트리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일반트리&lt;/b&gt;는 자식노드의 개수가 정해지지 않기 때문에 무한하게 구성할 수 있습니다. 이는 장점으로 볼 수 있지만 단점은 프로그램을 만들 때 복잡해질 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 효율적이고 쉽게 제어할 수 있는 형태의 &lt;b&gt;이진트리&lt;/b&gt;가 만들어졌습니다. 이는 자식 노드를 최대 2개로 제한하여 구성하도록 만든 트리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반트리는 주로 파일시스템 조직도 등 현실과 관련된 구조를 만들 때 주로 사용되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진트리는 탐색 연산 등을 수행할 때 많이 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상황에 따라 일반트리 와 이진트리를 선택해서 사용해야 하지만 이 블로그에서는 구현하기 쉽고 편한 이진트리 만 다루겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 이진트리의 종류와 특징&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진트리에는 특수한 규칙이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;포화&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;완전&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;기타&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트리1.png&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kytni/dJMcagqf26w/idAdqL6of6hkcTixgISyC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kytni/dJMcagqf26w/idAdqL6of6hkcTixgISyC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kytni/dJMcagqf26w/idAdqL6of6hkcTixgISyC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fkytni%2FdJMcagqf26w%2FidAdqL6of6hkcTixgISyC1%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;321&quot; height=&quot;252&quot; data-filename=&quot;트리1.png&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트리5.png&quot; data-origin-width=&quot;281&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSFl2K/dJMcacBooz5/b6ybkNrL2yE63FewsZnMH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSFl2K/dJMcacBooz5/b6ybkNrL2yE63FewsZnMH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSFl2K/dJMcacBooz5/b6ybkNrL2yE63FewsZnMH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSFl2K%2FdJMcacBooz5%2Fb6ybkNrL2yE63FewsZnMH0%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;281&quot; height=&quot;252&quot; data-filename=&quot;트리5.png&quot; data-origin-width=&quot;281&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트리6.png&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mNytX/dJMcadG4hmx/OAZG2S92gIhjBp19bm7E8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mNytX/dJMcadG4hmx/OAZG2S92gIhjBp19bm7E8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mNytX/dJMcadG4hmx/OAZG2S92gIhjBp19bm7E8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmNytX%2FdJMcadG4hmx%2FOAZG2S92gIhjBp19bm7E8K%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;321&quot; height=&quot;252&quot; data-filename=&quot;트리6.png&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진트리는 위와 같이 3가지로 분류할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그전에 한 가지 규칙을 설명드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진트리의 각 노드에는 레벨 순서대로 왼쪽에서 오른쪽으로 순서대로 번호를 붙일 수 있습니다. 위 트리에서 알파벳은 노드번호의 순서대로 부여한 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;포화&lt;/b&gt; 이진트리: 각 레벨에 노드가 모두 차있는 트리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;완전&lt;/b&gt; 이진트리: 모든 노드가 레벨 순서 그리고 왼쪽부터 오른쪽으로 순서대로 있어야 합니다. 중간에 노드가 하나라도 비어있으면 성립이 안됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기타&lt;/b&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;5. 이진트리 구현방법&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트리4.png&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;262&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6pwYo/dJMcaaKlnJy/WOucI0CcSMABgjkliR3njK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6pwYo/dJMcaaKlnJy/WOucI0CcSMABgjkliR3njK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6pwYo/dJMcaaKlnJy/WOucI0CcSMABgjkliR3njK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6pwYo%2FdJMcaaKlnJy%2FWOucI0CcSMABgjkliR3njK%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;571&quot; height=&quot;262&quot; data-filename=&quot;트리4.png&quot; data-origin-width=&quot;571&quot; data-origin-height=&quot;262&quot;/&gt;&lt;/span&gt;&lt;/figure&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;pre id=&quot;code_1761916860123&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct Tree {
	element data;
	struct Tree* left;
	struct Tree* right;

}Tree;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 구조체로 이렇게 만들면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1761916932886&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main() {

	Tree node7 = { 7, NULL, NULL };
	Tree node6 = { 6, NULL, NULL };
	Tree node5 = { 5, NULL, NULL };
	Tree node4 = { 4, NULL, NULL };
	Tree node3 = { 3, &amp;amp;node6, &amp;amp;node7 };
	Tree node2 = { 2, &amp;amp;node4, &amp;amp;node5 };
	Tree node1 = { 1, &amp;amp;node2, &amp;amp;node3 };

	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이렇게 연결을 하면 트리구조가 만들어집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 트리 자료구조에 대해 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에는 이진트리의 순회방법을 포스팅하겠습니다. 감사합니다.&lt;/p&gt;</description>
      <category>자료구조/C언어</category>
      <author>Developer성현</author>
      <guid isPermaLink="true">https://han-studio.tistory.com/67</guid>
      <comments>https://han-studio.tistory.com/67#entry67comment</comments>
      <pubDate>Fri, 31 Oct 2025 22:25:31 +0900</pubDate>
    </item>
    <item>
      <title>[ kotlin ] 자료구조_Stack, Queue, Deque</title>
      <link>https://han-studio.tistory.com/66</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;서문&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료구조에서 가장 대표적인 stack, queue, deque에 대해 알아보고 사용해 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시라고 위 자료구조를 모르신다면 이전에 C언어 자료구조 파트에서 Array와 LinkedList를 사용해서 구현해 보고 동작방식을 포스팅한 적이 있으니 아래 링크에서 봐주시거나 유튜브에 잘 나와 있으니 사전에 학습해 주시기 바랍니다.&lt;/p&gt;
&lt;figure id=&quot;og_1761059578673&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;'자료구조/C언어' 카테고리의 글 목록&quot; data-og-description=&quot; &quot; data-og-host=&quot;han-studio.tistory.com&quot; data-og-source-url=&quot;https://han-studio.tistory.com/category/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0/C%EC%96%B8%EC%96%B4&quot; data-og-url=&quot;https://han-studio.tistory.com/category/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0/C%EC%96%B8%EC%96%B4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/GaQT9/hyZL2jnLDJ/EPRAaqDUFxnQkOTQwVWBG1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/Ch9Hx/hyZMaBIHU3/fZlkZeOA2NBQGUovzKeYh0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/c8Cvdx/hyZLZAbgBC/a2fgKMkMcp2KU0K03i1NhK/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://han-studio.tistory.com/category/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0/C%EC%96%B8%EC%96%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://han-studio.tistory.com/category/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0/C%EC%96%B8%EC%96%B4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/GaQT9/hyZL2jnLDJ/EPRAaqDUFxnQkOTQwVWBG1/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/Ch9Hx/hyZMaBIHU3/fZlkZeOA2NBQGUovzKeYh0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/c8Cvdx/hyZLZAbgBC/a2fgKMkMcp2KU0K03i1NhK/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&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;'자료구조/C언어' 카테고리의 글 목록&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;han-studio.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(유튜브를 추천드립니다. ^^)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;1. kotlin에서는 stack, queue 기능을 제공하지 않는다.&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kotlin의 철학은 실용성과 간결성인데 기본이 되는 자료구조를 제공하지 않는다는 건 정말 이상합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제공하지 않는다면 C언어처럼 직접 구현해서 사용하라는 것일까요? 당연히 아니겠죠 ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 아시겠지만 Kotlin 은 Java와 호환이 가능합니다. 즉 Java에서 구현되어 있는 코드도 접근이 가능하다는 말이고 이는 이전에 포스팅한 적이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Java 에는 stack, deque 가 이미 구현되어 있습니다. 즉 Kotlin에서는 Java에 있는 클래스를 가져다 사용하면 됩니다.&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;background-color: #f3c000;&quot;&gt;2. Stack 의 사용법(권장 X)&lt;/span&gt;&lt;/h3&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;val stack: Stack&amp;lt;String&amp;gt; = Stack()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stack 선언은 이렇게 하면 됩니다. 물론 클래스 타입은 없어도 되지만 데이터 타입은 추론이 불가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 초기값을 넣어줄 수 없기 때문입니다. 그래서&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;val stack = Stack&amp;lt;String&amp;gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 해줘야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입추론이 안 되는 이유는 Stack 클래스 내부의 생성자는 파라미터를 받지 않기 때문입니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Stack&amp;lt;E&amp;gt; extends Vector&amp;lt;E&amp;gt; {
    /**
     * Creates an empty Stack.
     */
    public Stack() {
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;그리고 Vector이라는 클래스를 상속받고 있습니다. 이걸로 유추해 보아 현재 이 Stack 클래스는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Vector라는 클래스를 사용해서 Stack를 구현하고 있다고 볼 수 있습니다. 여기에 심각한 문제가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Vector&lt;span&gt; 클래스는 배열을 동적으로 할당받을 수 있는 클래스입니다. 이를 통해 Stack에 값을 넣을 공간을 할당받을 수 있지만 속도가 느리고 구식이라는 것입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;종합적으로 분석해서 결론은 &lt;b&gt;사용하지 말자!입니다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;그래도 사용은 해 보겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;val stack = Stack&amp;lt;String&amp;gt;()

stack.push(&quot;사과&quot;)
stack.push(&quot;딸기&quot;)

println(&quot;전체 항목: $stack&quot;)

stack.push(&quot;복숭아&quot;)

println(&quot;전체 항목: $stack&quot;)

println(&quot;꺼내기: ${stack.pop()}&quot;)

println(&quot;전체 항목: $stack&quot;)

println(&quot;확인하기: ${stack.peek()}&quot;)

println(&quot;꺼내기: ${stack.pop()}&quot;)

println(&quot;전체 항목: $stack&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;332&quot; data-origin-height=&quot;198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d5zzVF/dJMb9Mpmmih/rafsKbrY6eCgBMt1kZfkEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d5zzVF/dJMb9Mpmmih/rafsKbrY6eCgBMt1kZfkEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d5zzVF/dJMb9Mpmmih/rafsKbrY6eCgBMt1kZfkEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5zzVF%2FdJMb9Mpmmih%2FrafsKbrY6eCgBMt1kZfkEk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;179&quot; data-origin-width=&quot;332&quot; data-origin-height=&quot;198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옛날 클래스 이기는 하지만 요소들을 문자열로 만들어 주는 기능은 구현되어 있네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;3. Stack의 사용법(권장 O)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 Kotlin(Java 포함)에서는 어떻게 Stack을 사용하면 될까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 Kotlin 은 Stack와 Queue를 제공하지 않는다고 했습니다. 하지만 ArrayDeque를 제공해 주고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Deque&lt;span&gt;자료구조는 Kotlin와 Stack를 결합한 형태 이기 때문에 Deque을&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 사용하면 당연히 나머지 2개도 사용할 수 있게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;*중요*&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;ArrayDeque&lt;span&gt; 은 Kotlin에서도 따로 구현되어 있지만 동일한 이름으로 Java 에도 존재합니다. 하지만 코틀린에 맞게 제작되었기 때문에 코틀린 컬렉션을 같이 사용할 수도 있으니 코틀린 ArrayDeque&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 사용을 권장합니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 실제로 사용해 보겠습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;val stack: ArrayDeque&amp;lt;String&amp;gt; = ArrayDeque()

stack.addLast(&quot;a&quot;)
stack.addLast(&quot;b&quot;)
println(stack)

stack.addLast(&quot;c&quot;)
println(stack)

println(&quot;후입: ${stack.last()}, 선입: ${stack.first()}&quot;)

println(&quot;꺼내기: ${stack.removeLast()}&quot;)
println(stack)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;213&quot; data-origin-height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbJf6t/dJMb8Y4llVN/Kn3dqLFYAhalUtfpZXNmxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbJf6t/dJMb8Y4llVN/Kn3dqLFYAhalUtfpZXNmxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbJf6t/dJMb8Y4llVN/Kn3dqLFYAhalUtfpZXNmxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbJf6t%2FdJMb8Y4llVN%2FKn3dqLFYAhalUtfpZXNmxk%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;213&quot; height=&quot;146&quot; data-origin-width=&quot;213&quot; data-origin-height=&quot;146&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;정상적으로 동작은 하지만 코드가 조금 어색합니다... stack는 일반적으로 삽압 함수는 push() 삭제함수는 pop()이지만 위 코드에서는 addLast()가 push()를 대신하고 removeLast()가 pop()를 대신하고 있습니다. 이는 Deque를 사용하니 어쩔 수 없습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재미있는 것을 보여 드리겠습니다. Java 에도 동일한 이름의 클래스가 있다고 말씀드렸는데 한번 사용해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt; Java_ ArrayDeque &amp;gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;val stack: java.util.ArrayDeque&amp;lt;String&amp;gt; = java.util.ArrayDeque(listOf(&quot;a&quot;, &quot;b&quot;))

stack.push(&quot;a&quot;)
stack.push(&quot;b&quot;)
println(stack)

stack.push(&quot;c&quot;)
println(stack)

println(&quot;후입: ${stack.last()}, 선입: ${stack.first()}&quot;)

println(&quot;꺼내기: ${stack.pop()}&quot;)
println(stack)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일한 코드이지만 push, pop를 사용하고 있습니다. 이 코드가 일반적으로는 훨씬 직관적으로 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 Kotlin에서 같은 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;ArrayDeque&lt;span&gt; 클래스를 제공하고 있는 것을 보면 Koltin에서 제공하는 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;ArrayDeque를 사용하는 것을 추천하고 있다고 생가할 수 있을 거 같습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;정확한 이유는 저도 잘 모르겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;4. Queue의 사용법&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;queue 도 물론 Kotlin에서 제공하는&amp;nbsp;ArrayDeque을&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 사용해서 구현해야 합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;사용법은 위 Stack과 거의 동일합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 꺼낼 때 removeLast() 대신에 removeFirst()를 사용하면 됩니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;val queue: ArrayDeque&amp;lt;String&amp;gt; = ArrayDeque() // 혹은 LinkedList()

queue.addLast(&quot;a&quot;)
queue.addLast(&quot;b&quot;)
println(queue)

queue.addLast(&quot;c&quot;)
println(queue)

println(&quot;후입: ${queue.last()}, 선입: ${queue.first()}&quot;)

println(&quot;꺼내기: ${queue.removeFirst()}&quot;)
println(queue)
println(&quot;꺼내기: ${queue.removeFirst()}&quot;)
println(queue)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;197&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c86nco/dJMb9fLMydH/m9q4a36PTVcDKSy8mjuPL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c86nco/dJMb9fLMydH/m9q4a36PTVcDKSy8mjuPL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c86nco/dJMb9fLMydH/m9q4a36PTVcDKSy8mjuPL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc86nco%2FdJMb9fLMydH%2Fm9q4a36PTVcDKSy8mjuPL0%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;197&quot; height=&quot;202&quot; data-origin-width=&quot;197&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;5. Deque의 사용법&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;deque의 사용법은 위에서 사용해 보았기 때문에 설명이 필요 없겠지만 그래도 한번 사용은 해 보겠습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;val deque: ArrayDeque&amp;lt;String&amp;gt; = ArrayDeque() // addFirst, addLast 모두 가능

deque.addLast(&quot;a&quot;)
deque.addLast(&quot;b&quot;)
println(deque)

deque.addFirst(&quot;c&quot;)
deque.addFirst(&quot;d&quot;)
println(deque)

println(&quot;앞쪽: ${deque.last()}, 뒷쪽: ${deque.first()}&quot;)

println(&quot;앞에서 꺼내기: ${deque.removeLast()}&quot;)
println(deque)
println(&quot;뒤에서 꺼내기: ${deque.removeFirst()}&quot;)
println(deque)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TCEDr/dJMb9LDZAv6/x1C1VZzH9lQ7vSEJvkk2Bk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TCEDr/dJMb9LDZAv6/x1C1VZzH9lQ7vSEJvkk2Bk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TCEDr/dJMb9LDZAv6/x1C1VZzH9lQ7vSEJvkk2Bk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTCEDr%2FdJMb9LDZAv6%2Fx1C1VZzH9lQ7vSEJvkk2Bk%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;225&quot; height=&quot;196&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;6. Deque의 추가설명&lt;/span&gt;&lt;/h3&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;val deque: ArrayDeque&amp;lt;String&amp;gt; = ArrayDeque(listOf(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;)) // addFirst, addLast 모두 가능

deque.addLast(&quot;a&quot;)
deque.addLast(&quot;b&quot;)
println(deque)

deque.addFirst(&quot;c&quot;)
deque.addFirst(&quot;d&quot;)
println(deque)

println(&quot;앞쪽: ${deque.last()}, 뒷쪽: ${deque.first()}&quot;)

println(&quot;앞에서 꺼내기: ${deque.removeLast()}&quot;)
println(deque)
println(&quot;뒤에서 꺼내기: ${deque.removeFirst()}&quot;)
println(deque)

deque.addAll(3, setOf(&quot;D&quot;, &quot;E&quot;, &quot;E&quot;, &quot;F&quot;))
println(deque)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;deque는 원래 앞뒤에서만 삽입 삭제가 가능하지만 위 코드를 보면 이상하게 index로 접근해서 중간에 setOf의 컬렉션 타입으로 추가가 가능합니다.&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;이는 명확하게 잘못된 방법이지만 Kotlin에서는 이 기능을 제공하고 있습니다. 사실 제공을 한다기보다는 컬렉션 타입과의 호환을 위해 제거하지 않았다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArrayDeque의 내부를 간단하게 살펴보겠습니다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;public class ArrayDeque&amp;lt;E&amp;gt; : AbstractMutableList&amp;lt;E&amp;gt; { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;public actual abstract class AbstractMutableList&amp;lt;E&amp;gt; protected actual constructor() : 
MutableList&amp;lt;E&amp;gt;, AbstractList&amp;lt;E&amp;gt;() { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;public interface MutableList&amp;lt;E&amp;gt; : List&amp;lt;E&amp;gt;, MutableCollection&amp;lt;E&amp;gt; { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;public interface MutableCollection&amp;lt;E&amp;gt; : Collection&amp;lt;E&amp;gt;, MutableIterable&amp;lt;E&amp;gt; {&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 내부적으로 내려가면 Collection 인터페이스를 상속받고 있다는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 ArrayDeque 은 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Collection&lt;span&gt;타입과 호환이 가능하도록 설계를 했다고 볼 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이상으로 Kotlin에서의 Stack, Queue, Deque를 알아보고 사용해 보았습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;부족한 글이지만 끝까지 읽어 주셔서 감사드립니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;아마 잘못된 부분도 있을 거라고 생각합니다. 잘못된 부분이 있다면 글로 남겨주시면 감사드리겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>kotlin</category>
      <category>deque</category>
      <category>koltin</category>
      <category>Kotlin자료구조</category>
      <category>Queue</category>
      <category>Stack</category>
      <author>Developer성현</author>
      <guid isPermaLink="true">https://han-studio.tistory.com/66</guid>
      <comments>https://han-studio.tistory.com/66#entry66comment</comments>
      <pubDate>Thu, 23 Oct 2025 01:11:58 +0900</pubDate>
    </item>
    <item>
      <title>[ C언어 ] 자료구조_덱(배열_Array)</title>
      <link>https://han-studio.tistory.com/65</link>
      <description>&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. 덱 자료구조 설명&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;이미지1.png&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;102&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/li9IP/dJMb8XYEpl8/j1I4aJEdiNTNhJ0BQIqp7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/li9IP/dJMb8XYEpl8/j1I4aJEdiNTNhJ0BQIqp7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/li9IP/dJMb8XYEpl8/j1I4aJEdiNTNhJ0BQIqp7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fli9IP%2FdJMb8XYEpl8%2Fj1I4aJEdiNTNhJ0BQIqp7k%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;381&quot; height=&quot;102&quot; data-filename=&quot;이미지1.png&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;102&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;덱 은 이전에 알아본 스택과 큐를 결합한 형태의 자료구조입니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;앞뒤로 데이터를 넣을 수도 있고 꺼낼 수도 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. 덱 자료구조 구현(배열)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덱은 이전에 포스팅한 원향큐에 조금만 코드를 추가하면 됩니다.&lt;/p&gt;
&lt;figure id=&quot;og_1760625778491&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;[ C언어 ] 자료구조_큐(Array)&quot; data-og-description=&quot;[ C언어 ] 자료구조_스택(배열)스택은 추상 자료구조중 하나로 값이 들어가면 스택에 쌓이고 나올때는 마지막으로 들어간 순서대로 값이 나오는 구조입니다.스택은 간단하게도 2가지의 기본 연&quot; data-og-host=&quot;han-studio.tistory.com&quot; data-og-source-url=&quot;https://han-studio.tistory.com/62&quot; data-og-url=&quot;https://han-studio.tistory.com/62&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/psVeD/hyZLyivXkZ/KbdXowzeedWKyMAysLVzeK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gCiiI/hyZLsWTQwS/VoQN6alaFgzzbuFRxkXfS1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cSp0BJ/hyZLqY5r0Z/3fWNRrKDgGhp5DsSkIKPU0/img.png?width=791&amp;amp;height=540&amp;amp;face=0_0_791_540&quot;&gt;&lt;a href=&quot;https://han-studio.tistory.com/62&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://han-studio.tistory.com/62&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/psVeD/hyZLyivXkZ/KbdXowzeedWKyMAysLVzeK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/gCiiI/hyZLsWTQwS/VoQN6alaFgzzbuFRxkXfS1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cSp0BJ/hyZLqY5r0Z/3fWNRrKDgGhp5DsSkIKPU0/img.png?width=791&amp;amp;height=540&amp;amp;face=0_0_791_540');&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;[ C언어 ] 자료구조_큐(Array)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[ C언어 ] 자료구조_스택(배열)스택은 추상 자료구조중 하나로 값이 들어가면 스택에 쌓이고 나올때는 마지막으로 들어간 순서대로 값이 나오는 구조입니다.스택은 간단하게도 2가지의 기본 연&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;han-studio.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서는 rear 쪽에서 삽입하고 frount 쪽에서 삭제를 하였지만 반대방향으로도 동작할 수 있도록 바꿔주기만 하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;*이번 덱 자료구조는 위 코드와는 달리 조금 수정해서 새로 구현하였습니다*&lt;/u&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;Deque_Array.h&lt;/p&gt;
&lt;pre id=&quot;code_1760626058657&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef int element;
#define DEQUE_SIZE 10
typedef struct Deque {
	element data[DEQUE_SIZE + 1];
	int frount;
	int rear;
}Deque;

int init(Deque* dq);

int frount_add(Deque* dq, element data);

int rear_add(Deque* dq, element data);

element frount_remove(Deque* dq);

element rear_remove(Deque* dq);

int size(Deque* dq);

void deque_print(Deque* dq);&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;원형큐 는 공백상태와 포화상태를 구분하기 위해 index 하나의 공간은 비워야 한다고 위 블로그에서 말했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 실제 size 는 10이 아닌 9 이기 때문에 이번 덱 자료구조를 구현할 때는 10 + 1을 하여 실제 데이터를 담을 수 있는 공간을 10으로 만들었습니다.&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;Deque_Array.c&lt;/p&gt;
&lt;pre id=&quot;code_1760626286971&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &quot;Deque_Array.h&quot;

int is_empty(Deque* dq)
{
	return dq-&amp;gt;frount == dq-&amp;gt;rear;
}

int is_full(Deque* dq)
{
	return ((dq-&amp;gt;rear + 1) % (DEQUE_SIZE + 1)) == dq-&amp;gt;frount;
}

int init(Deque* dq)
{
	dq-&amp;gt;frount = 0;
	dq-&amp;gt;rear = 0;
	return 0;
}

int frount_add(Deque* dq, element data)
{
	if (is_full(dq)) return 1;

	dq-&amp;gt;data[dq-&amp;gt;frount] = data;
	dq-&amp;gt;frount = (dq-&amp;gt;frount + DEQUE_SIZE) % (DEQUE_SIZE + 1);

	return 0;
}

int rear_add(Deque* dq, element data)
{
	if (is_full(dq)) return 1;

	dq-&amp;gt;rear = (dq-&amp;gt;rear + 1) % (DEQUE_SIZE + 1);

	dq-&amp;gt;data[dq-&amp;gt;rear] = data;

	return 0;
}

element frount_remove(Deque* dq)
{
	if (is_empty(dq))
	{
		exit(1);
	}

	dq-&amp;gt;frount = (dq-&amp;gt;frount + 1) % (DEQUE_SIZE + 1);

	return dq-&amp;gt;data[dq-&amp;gt;frount];

}

element rear_remove(Deque* dq)
{
	if (is_empty(dq))
	{
		exit(1);
	}

	element save = dq-&amp;gt;data[dq-&amp;gt;rear];
	dq-&amp;gt;rear = (dq-&amp;gt;rear + DEQUE_SIZE) % (DEQUE_SIZE + 1);

	return save;
}

int size(Deque* dq)
{
	return dq-&amp;gt;rear - dq-&amp;gt;frount;
}

void deque_print(Deque* dq)
{
	int i = dq-&amp;gt;frount;

	while (i != dq-&amp;gt;rear)
	{
		i = (i + 1) % (DEQUE_SIZE + 1);
		printf(&quot;[%d] &quot;, dq-&amp;gt;data[i]);
	}
	printf(&quot;\n&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main.c&lt;/p&gt;
&lt;pre id=&quot;code_1760626309767&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &quot;Deque_Array.h&quot;

int main()
{
	Deque deque;

	init(&amp;amp;deque);

	frount_add(&amp;amp;deque, 1);
	deque_print(&amp;amp;deque);

	frount_add(&amp;amp;deque, 2);
	deque_print(&amp;amp;deque);

	rear_add(&amp;amp;deque, 3);
	deque_print(&amp;amp;deque);

	rear_add(&amp;amp;deque, 4);
	deque_print(&amp;amp;deque);


	printf(&quot;삭제 [%d]\n&quot;, rear_remove(&amp;amp;deque));
	deque_print(&amp;amp;deque);
	printf(&quot;삭제 [%d]\n&quot;, rear_remove(&amp;amp;deque));
	deque_print(&amp;amp;deque);
	printf(&quot;삭제 [%d]\n&quot;, rear_remove(&amp;amp;deque));
	deque_print(&amp;amp;deque);
	printf(&quot;삭제 [%d]\n&quot;, rear_remove(&amp;amp;deque));
	deque_print(&amp;amp;deque);
    
	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행결과&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;235&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sBhgx/dJMb9NofoML/k26mvTkgpLQl5nH4Gm0Gb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sBhgx/dJMb9NofoML/k26mvTkgpLQl5nH4Gm0Gb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sBhgx/dJMb9NofoML/k26mvTkgpLQl5nH4Gm0Gb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsBhgx%2FdJMb9NofoML%2Fk26mvTkgpLQl5nH4Gm0Gb0%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;193&quot; height=&quot;220&quot; data-origin-width=&quot;235&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상으로 배열을 사용하여 자료구조 덱을 구현 해 보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝까지 글을 읽어주셔서 감사합니다.&lt;/p&gt;</description>
      <category>자료구조/C언어</category>
      <category>array</category>
      <category>C</category>
      <category>deque</category>
      <category>덱</category>
      <category>자료구조</category>
      <author>Developer성현</author>
      <guid isPermaLink="true">https://han-studio.tistory.com/65</guid>
      <comments>https://han-studio.tistory.com/65#entry65comment</comments>
      <pubDate>Thu, 16 Oct 2025 23:54:31 +0900</pubDate>
    </item>
  </channel>
</rss>