알고리즘이란?

알고리즘은 어떠한 문제를 해결하기 위한 일련의 절차를 공식화한 형태로 표한한 것이다. 예를 들어 일상 속에서는

다음과 같은 알고리즘을 찾을 수 있다.

  • 집에서 학교로 가는 길 찾기
  • 샌드위치 만드는 방법
  • 매점에 가서 물건 구매

최단 거리 혹은 최단 시간 내에 학교에 가는 길을 찾는 것, 샌드위치를 만들기 위한 재료를 준비하고 조리 순서를 진행하는것, 매점에서 물건을 집고 계산하는 것까지 모두 알고리즘이라 할수 있다.

프로그래밍에서 알고리즘은 input 값을 통해 output 값을 얻기 위한 계산 과정을 의미한다. 이러한 문제를 해결할때,

정확하고 효율적으로 결과값을 얻기 위해서 알고리즘이 필요하다.

알고리즘의 조건

좋은 알고리즘을 만들기 위해서는 다음과 같은 조건을 충족하여야 한다.

  • 입력 : 외부에서 제공되는 자료가 0개 이상 존재
  • 출력 : 적어도 2개 이상의 서로 다른 결과를 내어야 한다. 즉 모든 입력에 하나의 출력이 나오면 안됨.
  • 명확성 : 수행 과정은 명확하고 모호하지 않은 명령어로 구성되어야 한다.
  • 유한성 : 유한 번의 명령어를 수행 후 유한 시간 내에 종료한다.
  • 효율성 : 모든 과정은 명백하게 실행 가능(검증 가능)한 것이어야 한다.

공부 순서

사용할 언어와 그 언어에 대한 문법과 클래스를 어느정도 알고 있다는 가정하에 아래와 같은 순서로 공부.

  1. 기본 개념 이해
  2. 기본 알고리즘 코드 학습
  3. 쉬운 문제 풀기
  4. (어려운 개념 이해 & 문제 풀기)

알고리즘 공부 시작하기

1. 기본 개념 이해

* 알고리즘에 필요한 기본 개념

3줄 요약:

  • 시간 복잡도
  • 자료구조
  • 정렬

시간 복잡도

문제를 해결하는데 걸리는 시간과 입력의 함수 관계 프로그램을 작성할 때에 입력의 크기에 따라서 프로그램이 계산하는 횟수가 크게 달라진다.
입력된 자료의 양과 알고리즘 실행에 걸리는 시간 사이에는 어느 정도의 관계가 있다. 이것을 알고리즘의 시간 복잡도라 한다.

cf. 메모리 공간을 얼마나 차지하느냐를 계산하는 공간 복잡도라는 개념도 있지만,
저장 기술의 발달로 인해 현재는 시간 복잡도를 우선 고려하는 경우가 많다.

시간 복잡도를 나타낼 떄에는 Big O표기법을 이요. 예를 들어, 1부터 n까지의 합을 구한다고 할떄 다음과 같은 두가지 방법이 있다.

// 방법 1
int n, res = 0;
for (int i = 1; i <= n;, i++) {
    res += i;
}
System.out.println(res);
// 방법 2
int n, res = 0;
res = n*(n+1)/2;
System.out.println(res);

코드를 살펴보면 방법1에서는 for를 이용해 n번의 연산을 하기 때문에 o(n)의 시간 복잡도를 가진다. 반면 방법2에서는 n의 크기와 상관 없이 1번의 연산을 하기 때문에 o(1)의 시간 복잡도를 가진다.

맨 위에서 부터 시간 복잡도가 낮고 빠르고, 아래로 갈수록 시간 복잡도가 높고 느려진다. 제한된 시간 안에 올바르게 output을 출력하면 시간 복잡도를 낮춰야 할 것임을 알수 있다.

자료구조

자료구조란, 데이터 사이의 관계를 반영한 저장구조 및 그 조작 방법을 뜻한다. 컴퓨터의 프로그램을 실행하면 CPU에서 메모리로 데이터를 이동해서 처리하는데, 이 때 메모리를 효율적으로 사용하기 위해 데이터에 맞는 특성의 자료구조를 사용하는 것이 중요하다.

자료구조를 모두 나열하자면 아래 표와 같이 다양한 종류가 있다.

  • 선형 자료구조 : 한 종류의 데이터가 선처럼 길게 나열된 자료구조.
  • 비선형 자료구조 : 선형 자료구조가 아닌 모든 자료구조.i 번째 값을 탐색한 뒤의 i+1이 정해지지 않은 구조.

정렬

1. 버블정렬(Bubble sork)
버블정렬은 가장 쉬운 정렬 알고리즘이지만 시간복잡도가 좋은 퍼포먼스를 내지 못해서 실제로는 잘 사용되지 않는다.
시간복잡도는 O(n^2)이며 공간복잡도는 하나의 배열만 사용하여 정렬을 진행하기 때문에 O(n)이다.
***버블정렬 소스코드

버블정렬 파이썬 코드 찾아서 넣기
  • 버블 정렬 -> 가장 쉽지만, 시간 복잡도가 높아 효율적이진 않다.
  • 선택 정렬 -> 버블 정렬과 알고리즘이 유사하다. 가장 큰 수를 찾아 배열의 마지막 위치와 교환한다.
  • 삽입 정렬 -> 인덱스를 설정하여 현재 위치의 값을 아래쪽으로 순회하며 알맞은 곳에 넣어준다.
  • 병합 정렬 -> 정렬한 리스트를 반으로 쪼개며 좌우 리스트를 분할해 정렬 후 병합한다. 가장 많이 쓰이는 정렬중 하나.
  • 힙 정렬 -> 힙이라는 자료구조를 통해 내림차순으로 숫자를 넣은 후, 역순으로 꺼내어 정렬한다.
  • 퀵 정렬 -> pivot기준으로 좌측과 우측으로 작은 값과 긑 값을 재배치하고 분할하여 정렬한다.

1. Linear Layout

- (Linear)선

- Orientation - 방향(Linear Layout 에서는 방향이 중요함)

- Weight(가중치)

- Gravity

 

2. Relative Layout

- (Relative) 관계를 뜻함,상대

- 뷰끼리의 관계를 설정

 

3. Constraint Layout

- (Constraint) 강제,앵커

- 복잡한 뷰를 그릴때 조금더 유용함

 

Linear Layout 샘플 코드 - Orientation : Vertical

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <View
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#ED4A4A"
        />
    <View
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#44E10C"
        />
    <View
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#0C10E1"
        />
</LinearLayout>

화면

Linear Layout 샘플 코드 - Orientation : Horizontal

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="horizontal">

    <View
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#ED4A4A"
        />
    <View
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#44E10C"
        />
    <View
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#0C10E1"
        />
</LinearLayout>

화면

Linear Layout 샘플 코드 - Weight

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="horizontal"
    android:weightSum="3">

    <View
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:background="#ED4A4A"
        />
    <View
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:background="#44E10C"
        />
    <View
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:background="#0C10E1"
        />
</LinearLayout>

weightSum = "3"은 화면의 가로 전체를 3으로 잡고 아래에 나오는 View 3개에 각각 weight를 1로 주면 아래와 같이 균등하게 가로전체비율중 1/3씩 차지하게된다.

 

화면

LinearLayout 샘플코드 - Gravity(gravity-center)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="horizontal"
    android:weightSum="3"
    android:gravity="center">

    <View
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:background="#ED4A4A"
        />
    <View
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:background="#44E10C"
        />
    <View
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:background="#0C10E1"
        />
</LinearLayout>

화면

 

Collection의 함수형 API

* filter : 컬렉션에서 조건에 맞는 항목만 추출해 새로운 컬렉션을 반환한다.

* map : 컬렉션에 항목을 변환하여 새로운 컬렉션을 만들고 반환단다.

* flatmap : 컬렉션의 포함된 항목들을 평평하게 펼친 뒤 변환하여 새로운 컬렉션을 반환한다.

* find : 함수의 조건을 만족하는 항목 한 개를 반환한다.

* group by : 컬렉션을 여러 그룹으로 이뤄진 맵으로 변경한다.

클래스의 가시성 변경자

클래스에서 가시성 변경자는 클래스의 메소드 혹은 필드에 대해 접근을 허용하는지 결정하는 역할.

'private, protected,default,public'키워드로 사용했던 접근 제어자와 같은 의미이다.

 

* Java의 가시성

- default : 같은 패키지에서 접근 가능

- private : 클래스 내부에서만 사용 가능하며 외부에 비공개

- protected : 클래스와 상속받은 하위 클래스에서반 사용 가능

- public : 외부에서 모두 접근 가능

 

* Kotlin의 가시성 : 코틀린은 가시성 변경자의 일부가 다른데다가 또 함수나 프로퍼티가 꼭 클래스 내부에만 존재하는 것이 아니기 때문에 의미가 추가된다

- internal
  - 클래스 멤버 : 같은 모듈에서 접근가능

  - 최상위 선언 : 같은 모듈에서 접근가능

- private

 - 클래스 멤버 : 클래스 내부에서만 사용 가능하며 외부에 비공개

 - 최상위 선언 : 같은 파일에서만 접근 가능

- protected

 - 클래스 멤버 : 클래스와 상속받은 하위 클래스에 서 사용 가능

 - 최상위 선언 : 최상위 선언에서는 사용 불가

- public

 - 클래스 멤버 : 모든 곳에서 접근 가능

 - 최상위 선언 : 모든곳에서 접근 가능

 

Java와 달리 코틀린은 같은 패키지에서 접근 가능한 'default' 속성이 따로 없다. 대신에 같은 모듈일때 접근 가능한 변경자로서 'internal'키워드가 존재한다.

'모듈'이란 한꺼번에 컴파일되어 묶이는 하나의 프로젝트 단위이다.

Singleton 패턴

Object 클래스를 이해하기 위해서는 먼저 singleton패턴에 대한 간단한 이해가 필요하다. singleton패턴은 객체 지향에서 꽤 자주 사용하는 패턴으로 간단하게 말하면 한 개의 인스턴스 생성을 보장하고 코드 어디에서나 접근 가능하게 하는 것

객체의 생성을 제한하여 한 개의 인스턴스만 생성되도록 하는 것, 또한 객체에 접근할 수 있는 방법을 공개하여 누구나 객체를 사용할 수 있도록 하는것.

 

public class Singletonjava{
	
    // 생성자를 private로 감춘다.
	private SingletonJava(){}
    
    //생성된 객체를 private로 감추고 프로그램 시작할 때 초기화 한다.
    //인스턴스 생성방법은 처음 사용할때 초기화 하는 방법, 쓰레드 동기화 방법등 다양한 방법이 있다.
    private static Singletonjava instance = new SingletonJava();
    
    //외부에서 생성된 instance에서 접근 할수 있는 방법을 제공
    public static Singletonjava getInstance(){
    	return instance;
    }
    
    public void log(String text){
    	System.out.print(text);
    }
}

테스트 코드

@Test
public void testSingletonJava(){
	// 생성자를 private로 감춰서 new로 생성불가 - 주석을 풀면 에러 발생
    // SingletonJava singletonJava = new Singletonjava();
    
    //외부에 공개된 getInstance() 메소드로 객체에 접근
    SingletonJava singletonJava = SingletonJava.getInstance();
    
    // 객체의 메소드 사용가능
    singletonJava.log("hi, singleton");
}

코틀린으로 싱글톤 구현하기

object SingletonKotlin{
	fun log(text:String){
    	println(text)
    }
}

'object'키워드는 "해당 클래스가 싱글턴임"을 알려 준다. 어차피 싱글턴 패턴은 거의 뻔한 코드를 사용하는 것이므로 그냥 키워드로 제공하는 것이다. 단순히 object키워드를 사용하는 것만으로 java에서 꽤 복잡하게 작성한 코드들을 생략 가능하게 되는 것이다.

'공부내용정리 > 안드로이드' 카테고리의 다른 글

Collection의 함수형 API  (0) 2021.10.11
(Kotlin) 클래스의 가시성 변경자  (0) 2021.10.10
코틀린 프로퍼티 위임  (0) 2021.10.06
Java의 정적 유틸리티 클래스  (0) 2021.08.25
코틀린 함수  (0) 2021.08.25

프로퍼티 위임

코틀린은 클래스 뿐아니라 프로퍼티에서도 위임을 제공한다. 프로퍼티 위임은 Getter,Setter 연산자를 위임할 수 있게 해주며 매우 유용한 3가지 방법을 제공한다.

lazy properties 값의 초기화를 처음 프로퍼티를 사용할 때 초기화 한다.
observable properties 프로퍼티에 값이 변경되면 옵저버에게 알려준다.
storing properties 필드가 아닌 맵에 속성을 지정한다.

* 코틀린은 프로퍼티의 위임을 위해 기본적으로 3가지 방법을 추가로 제공한다.

1. Lazy 위임 

- 프로퍼티의 초기화를 인스턴스 생성 시점이 아니라 프로퍼티를 사용하는 시점에 초기화 하는 것

- 사용하는 이유 : 초기화가 오래 걸리는 속성이 있을 경우, 인스턴스 생성 시점에 모든초기화를 진행한다면 전체적인 성능이 매우 저하되기 때문,

 

2. Ovservable 위임

- 주로 관찰하고자 하는 대상(프로퍼티)에 변경 사항이 생길 때, 변경된 사실을 관측자에게 알려주는 것.

 

3. 프로퍼티를 Map객체에 위임하는 것

- Map이란 : 특정 Key에 해당하는 Value를 저장하는 자료구조.

 

 

정적 유틸리티 클래스

객체 상태 정보가 없고, 정적 함수만을 제공하는 클래스를 말한다.'정적 유틸리티 클래스'가 존재하는 이유는,Java에서는 모든 함수가 클래스 내부에 있어야 하기 때문인데, 예제를 통해 어떤 경우가 있는지 알아보도록 하자.

 

토스트 메시지 (Java)

Toast.makeText(getApplicationContext(), "" + number = "는 2의 배수입니다.", Toast.LENGTH_SHORT).show();

토스트 메시지(Kotlin)

Toast.makeText(applicationContext,"${number} 는 2의 배수입니다.", Toast.LENGTH_SHORT).show()

토스트 메시지를 호출하는 코드가 너무 길다는 생각이 든다. 토스트 메세지를 호출할 때 관심이 있는 것은 '메세지 내용'과 '얼마나 길게 표시하는지'의 정보일 것이다. 토스트 메세지는 코드 전체에서 사용하는 코드이므로 좀더 간편ㅇ하게 사용할 수 있도록 함수로 만들어 보자.

 

먼저 Java의 경우를 생각해 보자.아래의 2개의 함수를 사용하면 간단하게 사용가능하다.

// 짧은 토스트 메세지를 보여주는 함수
public void toastShort(String message){
	Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}

// 긴 토스트 메세지를 보여주는 함수
public void toastLong(String message){
	Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}

이제 한번 사용해 보자

public void onClick(View view) {
	// numberField의 값을 읽어 int 형으로 변환한다.
    int number = Integer.parseInt(numberField.getText().toString());
    
    //if, else if, else 문으로 2의 배수, 3의 배수를 체크해 서로 다른 토스트 메세지를 보여준다.
    if(number % 2 == 0) {
    	toastShort("" + number + "는 2의 배수입니다."
    } else if (number % 3 == 0){
    	toastShort("" + number + "는 3의 배수입니다."
    } else {
    	toastShort("" + number);
    }
}

'공부내용정리 > 안드로이드' 카테고리의 다른 글

Singleton 패턴 및 Object 클래스  (0) 2021.10.06
코틀린 프로퍼티 위임  (0) 2021.10.06
코틀린 함수  (0) 2021.08.25
코틀린 val과 var의 차이  (0) 2021.08.11
Kotlin 변수  (0) 2021.08.08

함수 선언 방법

Java의 경우는 함수를 선언하기 위해 별도의 키워드를 사용하지 않는다. 하지만 코틀린의 함수는 'fun'이라는 키워드를 사용한다

  • 함수 선언 방법
    - Java
    public void function(){
    }​
    - Kotlin
    fun function(){
    }​
    또한 함수에 넣을 별도의 파라미터가 있는 경우, Java는 파라미터의 타입을 적고 파라미터의 이름을 적지만, 코틀린은 변수를 사용할떄와 같이 파라미터의 이름을 먼저 적고 타입을 지정한다.예를 들어 int타입의 이름이 age인 파라미터를 받는다면 다음과 같이 작성한다.
    - Java
    public void function(int age){
    }​
    - Kotlin
    fun function(age:int){
    }​
    함수는 반환값을 가질수 있다고 했는데 Java의 경우는 '반환값의 타입'을 반드시 적어야 한다. 심지어 함수가 반환하는 것이 없는경우, "반환값이 없다"는 의미로 'void'를 표시한다. Java는 함수 반환값의 타입을 함수 이름 앞에 적어야 한다.

    반면에 코틀린은 반환값이 없는 경우 굳이 반환값의 타입을 적을 필요가 없다. 반환값이 있는 경우에는 함수의 선언부 끝에 '콜론(:)'기호를 사용하여 표시한다. 다음은 각각의 언어에서 함수의 반환값이 있는 경우를 보여준다.
    -Java
    public void function(int age){
    }
    
    public int function2(int age){
    	return 0;
    }
    -Kotlin
    fun funtion1(age:int){
    }​
    
    fun function2(age:int){
    	return 0
    }


 

'공부내용정리 > 안드로이드' 카테고리의 다른 글

코틀린 프로퍼티 위임  (0) 2021.10.06
Java의 정적 유틸리티 클래스  (0) 2021.08.25
코틀린 val과 var의 차이  (0) 2021.08.11
Kotlin 변수  (0) 2021.08.08
Kotlin과 Java차이  (0) 2021.08.06
  • val
    - 변경 불가능한 참조를 저장하는 변수로서 특정한 값을 의미하는 'Value'를 나타낸다.
    - val로 선언하면 초기화 이후 '변수의 재 대입'이 불가능하다
    - Java에서 'final'키워드로 선언하는 것과 같다
  •  
  • var
    - 변경 가능한 참조이다. 변경 가능하다는 의미의 'Variable'을 나타낸다
    - Java의 일반적인 변수에 해당한다.

코틀린이 변수 선언할때 키워드 자체로 변수의 변경 가능성을 구분 짓는 이유

- 프로그래밍에서 대부분의 경우 변수의 값을 변경할 필요가 없고, 변수를 불변으로 하는 경우 여러 면에서 유리하다는 것을 알게 되어서.

- 변수를 사용할때 최초 값 대입 이후로 굳이 값을 변경하지 않는 경우가 많다. 특히 임시적으로 사용되는 지역변수, 함수의 파라미터와 같은 경우 대부분 값을 변경하지 않는다

- 반대로 불변으로 선언할 경우, '메모리,멀티쓰레드 안전성, 함수형 코드'등 얻을수 있는 이점이 많다.

- 따라서 코틀린은 가급적 모든 변수를 'val로 선언하여 불변으로 설정하고, 필요한 경우에만 'var'를 쓰도록 권장하고 있다.

'공부내용정리 > 안드로이드' 카테고리의 다른 글

Java의 정적 유틸리티 클래스  (0) 2021.08.25
코틀린 함수  (0) 2021.08.25
Kotlin 변수  (0) 2021.08.08
Kotlin과 Java차이  (0) 2021.08.06
Kotlin에 대하여  (0) 2021.08.06

변수 선언

Java에서는 변수를 사용하기 위해 '변수의 타입을 먼저' 지정하고 그 '다음에 변수의 이름'을 적음

int age = 20;

Kotlin은 변수를 선언할때 'var'혹은 'val'키워드를 사용한다.

val ageVal = 20
var ageVar = 20

코틀린이 2가지 변수선언에 두가지 키워드를 사용하는 것은 변수의 불변성을 보장하기 위한 것이고, 타입을 따로 적지 않는것은 '타입 추론'을 하기 때문이다.

'공부내용정리 > 안드로이드' 카테고리의 다른 글

Java의 정적 유틸리티 클래스  (0) 2021.08.25
코틀린 함수  (0) 2021.08.25
코틀린 val과 var의 차이  (0) 2021.08.11
Kotlin과 Java차이  (0) 2021.08.06
Kotlin에 대하여  (0) 2021.08.06

+ Recent posts