티스토리 뷰

코드카타

 

예상 대진표

 

문제

 

 

입출력 예시

 

A: 4 -> 2 -> 1, B: 7 -> 4 -> 2

 

 

풀이

class Solution {
    fun solution(N: Int, A: Int, B: Int): Int {
        var a = A
        var b = B
        var res = 0
        
        while (a != b) {
            // 각 라운드에서 다음번호로 변경 (부전승 처리)
            a = (a + 1) / 2
            b = (b + 1) / 2
            res++
        }

        return res
    }
}

번호의 규칙성을 찾아 아래에서 위로 올라가면서 번호를 초기화 하는 방식으로 구현했다.

 

1 ~ 8의 번호가 있을 때, 단순히 2로 나눈 몫은 "0 1 1 2 2 3 3 4" 이지만

1을 더했을 경우 "1 1 2 2 3 3 4 4"가 되므로 원하고자 하는 결과값을 얻을 수 있다.

 

a와 b의 번호가 순서상관없이 1, 2에 해당한다면

서로 만나게 되는 마지막 라운드란 뜻이므로 반복문을 종료한다.

 


 

Kotlin 문법 강의 5주차 정리

 

유용한 기능 정리

 

자료형 변환

fun main() {
    var n1 = 10
    var n2 = 10.2

    var n3 = n1.toDouble() // 10.0
    var n4 = n2.toInt() // 10
}

변수의 자료형을 변환하려면 to자료형() 메소드를 활용하면 된다.

 

 

업/다운 캐스팅

fun main() {
    var birds = mutableListOf<Bird>()
    var name = readln()

    // 업 캐스팅(as Bird는 생략가능)
    birds.add(Sparrow(name) as Bird)
    birds[0].fly()
    
    // 다운 캐스팅(오류 발생)
    var s1:Sparrow = birds.get(0)
}

open class Bird(name: String) {
    var name: String
    init { this.name = name }
    fun fly() { println("${name}이/가 날고 있다.") }
}

class Sparrow(name: String): Bird(name) {}

업캐스팅은 자식 클래스의 객체를 부모 클래스 타입으로 변환하는 것이고,

다운캐스팅은 부모 클래스 타입의 객체를 자식 클래스 타입으로 변환하는 것이다.

 

상속 관계에서 자식 클래스는 부모 클래스로 형변환이 가능하다.

 

위 예제코드의 다운 캐스팅 구문이 오류가 나는 이유는

Sparrow형 변수에 bird형 변수를 대입하려 하기 떄문이다.

bird는 Sparrow보다 기본적으로 많은 정보를 갖고 있기에 대입이 불가하다.

 

 

자료형 타입 확인

fun main() {
    val name = "주영"

    if(name is String) println("name은 String 타입입니다")
    else println("name은 String 타입이 아닙니다")
}

코틀린은 is 키워드를 사용하여 자료형의 타입을 확인할 수 있다.

 

 

데이터 묶기

fun main() {
    
   val pair = Pair(1, 2)
   val triple = Triple(1, 2, 3)
   
   println(pair.first)
   println(pair.second)
   print(triple.third)
}

코틀린에서 Pair와 Triple은 각각 두 개 또는 세 개의 값으로

이루어진 튜플을 표현하는 클래스이다.

 

 

Scope Functions

fun main() {
    var str1 = "Hello"

    // 객체를 인자로 받아 블록을 실행하고, 블록의 결과를 반환
    str1.let { println(it.length) }

    // let과 동일하나 객체를 this로 참조 (this는 생략가능)
    str1.run { println(this.length) }

    // 객체를 인자로 받지만, 확장 함수가 아니기에 객체를 직접 호출하지 않는다.
    with(str1) { println(this) }

    // 중괄호 블록안에 자신의 객체를 전달하고 객체를 반환
    var str2 = ""
    str1.apply { str2 = this }
    str1.also { str2 = it }
}

객체를 사용할때 임시로 Scope(중괄호)를 만들어 편리한 코드 작성을 도와주는 함수들이다.

 

 

 

확장 함수

 

확장 함수란?

외부에서 클래스의 메소드를 추가할 때 확장함수를 사용한다.

 

원하는 메소드가 있지만 내가 설계한 클래스가 아닐 때

해당 클래스에 원하는 메소드를 추가하려고 보통 쓰인다.

 

확장 함수를 이용하면 원본 클래스의 일관성을 유지할 수 있다.

 

 

확장 함수 정의

fun 클래스명.함수명() {
    // 함수 구현 로직
}

이런 식으로 클래스의 확장 함수를 정의할 수 있다.

 

 

 

비동기 프로그래밍

 

비동기 작업의 개념

비동기 작업은 작업을 실행하는 동안 해당 작업의 완료를 기다리지 않고

다른 작업을 계속 수행할 수 있도록 하는 프로그래밍 방식입니다.

 

데이터 불러오기, 파일 다운 같이 시간이 오래 걸리는 작업들은 비동기 처리를 해줘야 한다.

 

 

동기 프로그래밍과의 차이

동기적 프로그래밍은 작업들을 순차적으로 실행하기에

요청을 보내고 결과값을 받을 때까지 작업을 멈춘다.

 

그러나 비동기 프로그래밍은 요청을 보낸 뒤 또 다른 작업을 수행한다.

즉, 동기는 한 가지씩 작업을 수행하고, 비동기는 다양한 일을 한 꺼번에 수행한다.

 

 

 

쓰레드

 

쓰레드란?

쓰레드는 로직을 동시에 실행할 수 있도록 도와준다.

 

프로그램은 하나의 메인 쓰레드(실행흐름)이 존재한다.

메인 쓰레드에 여러 개의 자식 쓰레드를 생성해 동시처리가 가능하다.

 

 

쓰레드의 형태

하나의 프로세스에는 여러개의 쓰레드들이 별도의 메모리 영역인 STACK을 가진다. 

 

 

 종속성 추가

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC")

Gradle Scripts/build.gradle.kts (Moudle : App) 파일에 들어가서 

dependencies 블록 안에 해당 종속성을 추가해 쓰레드를 사용할 수 있다.

 

 

예시 코드

fun main() {
    thread(start = true) {
        for(i in 1..10) {
            println("Thread1: 현재 숫자는 ${i}")
            runBlocking {
                launch {
                    delay(1000)
                }
            }
        }
    }

    thread(start = true) {
        for(i in 50..60) {
            println("Thread2: 현재 숫자는 ${i}")
            runBlocking {
                launch {
                    delay(1000)
                }
            }
        }
    }
}

1초마다 서로 다른 범위의 숫자를 출력하도록 하는 프로그램이다.

Thread1과 Thread2은 서로 CPU 자원경쟁을 하며 출력 순서는 보장되지 않는다.

 

쓰레드의 이런 특징을 이용해 경마 프로그램 같은 걸 만들 수 있다.

 

 

 

코루틴

 

코루틴이란?

코루틴이란 비동기 프로그래밍을 가능하게 하는 프로그래밍 구성 요소로

쓰레드보다 더욱 가볍게 사용할 수 있는 것이 특징이다.

 

 

빌더

일반적으로 launch와 async라는 빌더를 가장 많이 사용하며

launch는 결과값이 없는 코루틴 async는 결과값이 있는 코루틴에 해당한다.

 

launch는 Job객체로 코루틴을 관리한다.

 

 

스코프

코루틴은 스코프로 범위 지정이 가능한데

앱이 실행된 이후에 계속 수행되어야 할 때는 Global Scope를,

필요할 때만 생성하고 사용 후 정리해야 할 때는 CoroutineScope를 사용한다.

 

 

사용할 쓰레드 지정

코루틴은 실행할 쓰레드를 Dispatcher로 지정할 수 있다.

Dispatchers.Main: UI와 상호작용하기 위한 메인쓰레드
Dispatchers.IO: 네트워크나 디스크 I/O작업에 최적화되어있는 쓰레드
Dispatchers.Default: 기본적으로 CPU최적화되어있는 쓰레드

안드로이드에서는 Dispatcher간의 변환을 해야하는 작업을 고려해야 한다.

 

 

 

쓰레드와 코루틴

 

동시성 프로그래밍

쓰레드와 코루틴은 동시성 프로그래밍을 위한 기술이다.

서로 다른 쓰레드끼리의 정보교환을 하려할 때 컨텍스트 스위칭이 필요하다.

 

 

쓰레드와 코루틴의 차이

 

쓰레드는 작업 하나의 단위에 해당하며 각 쓰레드가 독립적으로 Stack 메모리 영역을 가진다.

운영체제 커널에 의해 컨텍스트 스위칭을 진행하여 동시성을 보장한다.

 

쓰레드 A가 B의 결과를 기다리고 있을 때 A를 블로킹 상태라 정의한다.

A는 B의 결과가 나올 때까지 해당자원을 사용하지 못한다.

 

 

 

코루틴은 작업 하나하나의 단위가 Coroutine Object에 해당하며 여러 작업 각각에 Object를 할당한다.

소스 코드를 통해 컨텍스트 스위칭 시점을 마음대로 정할 수 있다.

 

오브젝트 A가 B의 결과를 기다릴 때 A는 Suspend로 바뀐다.

A를 수행하던 쓰레드는 그대로 유효하며, B도 A와 동일한 쓰레드에서 실행된다.

 

 

요약

코루틴은 하나의 쓰레드를 잘개 쪼개서 사용하는 기술이다.

코루틴은 쓰레드보다 CPU 자원을 절약하기에 구글에서 사용을 적극 권장하고 있다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함