출처: https://www.whatwant.com

 

[ Terminology & Problem ]

이번에 살펴보고자 하는 알고리즘은 "Longest Common Subsequence (LCS)" 이다.
어떤 문제를 해결하고자 하는 것인지 설명하기 전에 용어에 대한 정의부터 살펴보겠다.

 

출처: https://www.whatwant.com

 

여기에서 주의깊게 살펴봐야 할 것은 "Substring"인데, 연속적인 character를 의미한다.

 

출처: https://www.whatwant.com

 

반면, "Subsequence"는 비연속적인 character 순서를 포함한다.

 

출처: https://www.whatwant.com

 

2개의 string이 주어졌을 때, 공통적으로 있는 subsequence를 "Common Subsequence"라고 한다.

그리고 "Common Subsequence" 중에서 가장 긴 길이를 갖는 것을 "Longest Common Subsequence (LCS)"라고 한다.

 

이런 LCS를 구하는 방법을 찾는 것이 이번 목표이다 ^^

 

[Brute force approach]

착실하게 (무식하게?) 찾는 방법은 다음과 같다.

 

출처: https://www.whatwant.com

 

당연히 이렇게 찾는 것은 말이 안된다.

입력 string의 갯수가 n개라고 했을 때 2의 n승만큼 subsequence가 나오기 때문이다.

 

[Notation]

이후 설명할 내용에서 사용하는 notation을 정리하면 다음과 같다.

 

 

[Idea]

똑똑하게 해결하기 위한 아이디어는 다음과 같다.

 

출처: https://www.whatwant.com

 

복잡해보이는데, 가만히 살펴보면 엄청 당연한 이야기를 하고 있다.

 

특정 위치의 chracter가 같다면 LCS는 그 같은 값은 일단 LCS에 포함되는 것이고,

각 입력 string에서 동일한 값보다 1씩 작은 string의 LCS값을 더해주면 전체 LCS가 된다.

 

반면, 특정 위치의 chracter가 같지 않다면 LCS는 입력 string중 하나의 값을 1 차감한 내역으로 다시 LCS를 구하면 된다.

 

 

[ Longest Common Subsequece - Dynamic Programming Algorithm ]

위의 아이디어를 정리하면 다음과 같은 알고리즘이 된다.

 

 

이걸 어떻게 하는 것인지 살펴보자.

 

다음과 같은 2개의 string이 입력되었을 때 다음과 같은 표를 그리고 초기화 하자.

  - X = ABCBDAB

  - Y = BDCABA

 

출처: https://www.whatwant.com

 

앞에서 정리한 알고리즘을 기반으로 하나씩 값을 채워나가면 된다.

 

출처: https://www.whatwant.com

 

① x ≠ y 이므로 둘 중 큰 값 선택해야 하는데, 둘 모두 0이므로, 0

② ③ 상동

④ ⑥ x = y 이므로, 왼쪽 대각선 위의 값 + 1

⑤ x ≠ y 이므로 둘 중 큰 값 선택해야 하는데, ④ 값이 1이므로, 1

 

그리고, 어느 곳에서 값을 받아갔는지 화살표로 표기 해줘야 한다.

 

이런식으로 하나씩 값을 작성해 나가면 다음과 같이 된다.

 

출처: https://www.whatwant.com

 

LCS값이 어떻게 되었는지는 다음과 같이 추적해볼 수 있다.

 

출처: https://www.whatwant.com

 

화살표를 보면 알겠지만, 정답이 하나만 있는 것은 아니다.

 

출처: https://www.whatwant.com

 

[Pseudo Code]

손으로 진행했던 것을 코드로 만들어 보자.

 

출처: https://www.whatwant.com

 

손으로 진행했던 것과 차이가 있는 부분 위주로만 설명해봤다.

위 표에서 화살표를 살짝 끄적였는데, code에서는 b array를 통해 기록하도록 했다.

 

결과를 출력하기 위한 코드는 다음과 같다.

 

 

[Time & Space]

code를 보면 직관적으로 파악 가능한 것 처럼 Time complexity는 다음과 같다.

 

 

Space는 b array + c array 공간이 추가적으로 필요하기에 다음과 같다.

 

 

그런데, Space를 줄일 수 있는 경우가 있다.

실제 String 정보까지는 필요없고, 길이값만 필요하다고 하면 다음과 같이 작은 space만 필요로 한다.

 

 

또 다른 경우로는 다음과 같은 case가 있을 수 있다.

 

출처: https://www.whatwant.com

 

LCS에 대해서는 여기까지~

반응형

라이선스 이슈를 피해서 Anaconda 사용하는 방법에 대해서 이미 포스팅을 했었다.

  - 회사에서 Anaconda 사용하기 (Miniconda + conda-forge)

 

 

그런데, Ubuntu 운영체제를 기준으로 작성했다보니

Windows 환경을 사용하는 분들의 불만 아닌 불만이 있는 것 같아서... Windows 버전도 추가로 작성해본다.

 

① Miniconda 설치

② conda-forge 등록

③ conda 가상환경 생성

④ Jupyter Notebook 설치 

 

 

 

① Miniconda 설치

  - Windows 버전의 Miniconda3 Installer를 다운로드 받아서 설치하면 된다.

    . https://docs.anaconda.com/free/miniconda/

 

Miniconda

 

  - 약 78MB 정도의 용량의 설치파일이 다운로드 된다.

 

Installer

 

  - 이후 옵션은 모두 default로 해서 설치를 진행하도록 하자 (경로 등록 등도 일단 그냥 무시하자)

 

 

Complete

 

  - 우리는 설명서 따위는 보지 않는 ...... ^^

 

② conda-forge 등록

  - Windows 키보드를 눌러보면 새로 설치된 앱을 확인할 수 있다.

 

실행

 

  - 본인 취향대로 골라서 실행하면 되지만, 여기에서는 밑에 있는 "Anaconda Prompt (miniconda3)"를 선택했다.

 

prompt

 

  - 명령어는 다음과 같다.

(base) C:\Users\whatw>conda config --add channels conda-forge

(base) C:\Users\whatw>conda config --set channel_priority strict

(base) C:\Users\whatw>conda config --show channels
channels:
  - conda-forge
  - defaults

 

③ conda 가상환경 생성

  - 일단 conda 가상환경을 생성해야 한다. 이 때, 사용할 Python 버전을 지정하면 된다.

 

conda

 

  - 중간에 계속 설치를 진행할 것인지 묻는 부분이 나오는데, 그냥 엔터 때리면(?) 된다.

(base) C:\Users\whatw>conda create -n p39 python=3.9.15
Channels:
 - conda-forge
 - defaults
Platform: win-64
Collecting package metadata (repodata.json): done

...

done
#
# To activate this environment, use
#
#     $ conda activate p39
#
# To deactivate an active environment, use
#
#     $ conda deactivate

 

  - 설치 완료 부분을 보면 가상환경을 실행하는 방법과 종료하는 방법을 알려준다.

 

④ Jupyter Notebook 설치

  - 앞에서 생성한 가상환경 內 Jupyter Notebook을 설치해야하기에 우선 가상환경을 실행하자.

 

active

 

  - 프롬프트 앞 부분을 보면 현재 실행중인 환경 정보를 알려준다. 항상 신경쓰자.

 

  - 이제는 Jupyter Notebook 패키지를 설치하자.

(p39) C:\Users\whatw>pip install jupyter notebook ipykernel
Collecting jupyter
  Downloading jupyter-1.0.0-py2.py3-none-any.whl.metadata (995 bytes)
Collecting notebook
  Downloading notebook-7.1.2-py3-none-any.whl.metadata (10 kB)

...

 

  - 커널도 등록하자

(p39) C:\Users\whatw>python -m ipykernel install --user --name p39 --display-name "python 3.9"
Installed kernelspec p39 in C:\Users\whatw\AppData\Roaming\jupyter\kernels\p39

 

  - 'Jupyter Notebook'이 실행될 경로를 하나 만든 뒤, 그 곳에서 실행하자.

 

execute

 

  - 갑자기 웹브라우저가 아래와 같이 실행되면 성공한 것이다.

 

jupyter notebook

 

  - 오른쪽 "New" 버튼을 통해 notebook을 생성하자.

 

hello

 

잘 된다!

 

반응형

출처 : https://www.whatwant.com

 

이번에 살펴볼 것은 한글로 말하자면, "막대 자르기" 알고리즘이다.

어떤 문제를 해결하기 위한 알고리즘인지 알아보자.

 

[Problem]

n만큼의 길이를 갖고 있는 막대기가 있다고 하자.

 

출처 : https://www.whatwant.com

 

이 막대기를 잘라서 팔아야 하는데, 길이에 따라서 판매되는 가격이 다르다고 했을 때

어떻게 잘라서 팔아야 최대 이익이 나오는지를 찾아내야 하는 것이 문제이다.

 

 

위와 같이 막대기 길이에 따른 수익은 제시가 된다.

알아야 할 notation 규칙은 다음과 같다.

 

 

[Brute force approach]

"n = 4" 만큼의 길이를 갖고 있는 막대기가 있고, 길이에 따른 가격은 다음과 같다.

 

출처 : https://www.whatwant.com

 

이 때, 나올 수 있는 모든 경우의 수를 다 살펴보자면 다음과 같다.

 

출처 : https://www.whatwant.com

 

최대 수익을 얻기 위해서는 ⑶번과 같이 2개 묶음으로 나누는 경우가 10만큼의 수익을 얻을 수 있다.

그런데, 이처럼 모든 경우의 수를 나열해서 모두 계산해보기에는 너무 비효율적이다.

 

[Rod-Cutting Algorithm]

일단 다음과 같은 계산식을 살펴보자.

 

 

n 길이의 막대기가 있을 때, i 길이의 가격과  'n - i' 길이일 때의 최대 수익의 합이 최대인 i값을 찾는 것을 의미 한다.

 

출처 : https://www.whatwant.com

 

다음과 같은 문제가 주어졌다고 해보자.

 

 

r[i], s[i] 값은 다음과 같이 계산해볼 수 있다.

 

 

그러면 다음과 같은 결과를 얻을 수 있다.

 

 

이렇게 만들어진 표가 있다면,

8 길이만큼의 막대기가 주어졌을 때 다음과 같이 활용할 수 있다.

 

출처 : https://www.whatwant.com

 

[Pseudo Code]

 

 

[Time & Space]

이 알고리즘에서는 r[n], s[n] 값을 저장하기 위한 메모리 공간을 필요로 한다.

길이 n 값에 선형으로 비례하는 만큼 사용하기 때문에 다음과 같이 정리할 수 있다.

 

 

소요 시간은 Pseudo Code를 보면 중복 for문이 사용되는 부분을 잘 살펴봐야 하는데,

다음과 같이 정리 해볼 수 있다.

 

 

수고하셨습니다 !!!

반응형

출처: https://www.whatwant.com

 

왠지 이름만 들어도 어려울 것 같은 느낌이 팍팍 드는, Dynamic Programming !!!

 

연구비를 타내기 위해 그냥 있어보이려고 멋지게 작명하다보니 이런 이름을 가졌다고 한다.

사람 사는게 다 그렇지 뭐~ ^^

 

"Dynamic Programming"은 뭔가 계산하는 알고리즘이라기 보다는

작은 문제를 풀어서 그 중간 결과를 기록해 놓음으로써 다시 재계산하지 않도록 하는 방법이다.

 

여러 유형의 문제를 Dynamic Programming으로 푸는 것을 살펴볼텐데

그 첫번째로 살펴볼 것이 바로 "Assembly-line scheduling" 이다.

 

 

[Definition]

'Assembly-line'이라는 것에 대한 정의 부터 살펴보자.

 

출처: https://ko.dict.naver.com/#/entry/koko/db51c8c4d1144a24b1d8103e3ebd94e3

 

컨베이어벨트를 따라 단계별로 부품 조립하는 것을 생각하면 된다.

 

출처: https://www.whatwant.com

 

- station : 조립 단계. 제품 조립은 n개의 station을 거치면 완성이 된다.

- a : 각 station 단계에서 소요되는 시간

- line : 하나의 컨베이어 벨트로 생각하면 된다.

- e : line에 조립을 시작하도록 하기 위해 소요되는 시간

- x : 조립 완료된 제품을 전달하기 위해 소요되는 시간

- t : line을 옮기기 위해 소요되는 시간

 

 

[Problem]

여러 line으로 구성된 assembly-line이 있을 때,

어떤 경로가 가장 짧은 소요 시간으로 조립할 수 있는지 최적의(가장 빠른) 경로를 찾는 방법은?

 

 

[Solution-1]

가장 확실하고 무식한(?) 방법으 모든 경우의 수를 구해서 찾는 방법이다.

 

하지만, 말 그대로 무식한 방법이기에 ... 경우의 수가 너무 크다.

 

 

 

[Solution-2]

스마트한 방법을 찾아보자.

 

▷ Idea

어느 시점(S)에서 자기 순서까지 올 수 있는 방법은 2가지 경우 밖에 없다.

 

출처: https://www.whatwant.com

 

자기가 있는 동일한 line의 직전 단계에서 오는 방법과, 다른 line의 직전 단계에서 오는 2가지의 경우이다.

 

 

그러면, 그 2가지의 경우 중에 가장 빠른 것을 선택하면 되게 되는 것이다.

 

▷ How to

그러면 예시를 살펴보자.

 

출처: https://www.whatwant.com

 

각 단계에서 소요되는 시간을 더해가면서 정리하면 된다.

보다 더 짧은 시간을 선택하면 되기 때문에 □로 표기된 값들이 선택된 결과들이다.

 

이렇게 선택하는 과정에서 소요되는 Running Time은 어떻게 될까?

각 Station에서 2개씩 값을 보면 되기 때문에 2n의 Running Time이 필요하고,

entry + exit 과정이 있기 때문에 이를 정리하면 다음과 같다.

 

 

Brute-force 방법으로 할 때에는 어느 시점(S)에서 자기한테 까지 오는 모든 경우의 수를 살펴보지만

지금 방식에서는 바로 직전의 2가지 경우만 살펴보기 때문에 n에 비례하는 복잡도를 갖게 되었다.

 

 

그러면, 중간에 각 S단계에 따른 값들을 어떻게 저장하면 될까?

 

 

위와 같은 표 내용만 기록/기억 하고 있으면 되는 것이다.

그런데, 이 것만 가지고는 어떤 경로로 구성된 것인지 알기가 어렵다.

 

출처: https://www.whatwant.com

 

이 내용을 기록할 표가 하나 더 필요한 것이다.

 

 

그런데, 2개의 테이블이 모두 필요할까?

 

경로만 확인 가능해도 되는 경우에는 L table만 있으면 된다.

S table은 현재 값과 직전 값만 알면 되고, 최적해(S* = 38) 값만 저장하면 된다.

 

S table에서 S3를 계산할 때 S2 값만 알면 된다. 즉, S1의 내용은 필요 없다.

메모리를 굳이 table 전체 크기만큼 잡아 놓지 않아도 된다는 것이다.

 

 

L table 값만 알면 최적 경로를 찾을 수 있기 때문이다.

 

반대로 S 값을 갖고 있는 table만 있어도 L 값 table 없이 경로를 찾아낼 수는 있다.

하지만 L 값 table을 사용하는 것이 훨씬 더 편하기에 L Table을 이용하는 것이다.

 

 

▷ Pseudo Code

코드로 구현해보면 다음과 같다.

 

출처: https://www.whatwant.com

 

뭔가 복잡해보이는데, 살펴보기 편하게 구분해보면 다음과 같다.

 

출처: https://www.whatwant.com

 

결과를 출력하는 부분은 아래와 같이 구현해볼 수 있다.

 

 

실행 결과는 다음과 같이 나올 것이다.

 

 

 

▷ Space consumption

일단 기본적으로는 S table과 L table 모두 필요로 한다는 전제 하에 다음과 같은 메모리 사용량을 필요로 한다.

 

 

 

▷ Running time

하나의 요소 別 소요 시간이 Θ(1) 소요시간이 걸린다고 했을 때, 전체 소요 시간은 Θ(n)이라고 할 수 있다.

 

 

 

뭔가 심오한 Dynamic Programming의 세계이다~

반응형

출처: https://www.whatwant.com

 

"Radix"가 뭘까?

'기수(基數)'는 0~9까지 기본이 되는 수를 의미하는데, 여기에서는 '진법(進法)'의 의미가 더 큰 것 같다.

 

https://en.dict.naver.com/#/entry/enko/17ef262637ad4f04a48f2e6a0186dbbd

 

"Radix Sort"의 다른 호칭은 다음과 같다.

- 기수 정렬

- Bucket Sort

- Digital Sort

 

Radix Sort 알고리즘도 역사가 오래된 아이인데, 1923년에 이미 천공카드 분류 방법으로 널리 사용되었단다.

(어!? 천공카드가 뭔지 아는 것 만으로도 년식 인증인가!?)

 

 

① MSD (Most Significant Digit,  최상위 유효숫자)

  - 앞(큰) 자리 부터 정렬을 해 나가는 방식이다.

 

출처: https://www.whatwant.com

 

  - 중간에 가로로 있는 구분선 위치 정보는 중요하다.

  - 단계 별로 구분선 안에서만 정렬이 이루어져야 하기 때문이다.

 

② LSD (Least Significant Digit, 최하위 유효숫자)

  - MSD 방식과 정반대로 뒤(작은) 자리 부터 정렬을 해보자.

 

출처: https://www.whatwant.com

 

  - Stable 이라는 속성을 정말 잘 이용한 방법으로 보인다.

  - MSD와 다르게 가로줄(각 단계에서의 구분 위치) 정보를 관리할 필요가 없다.

  - 아랫 자리들이 이미 sorting이 되어있기 때문에 윗 자리 sorting을 하면 전체가 sorting 된다.

 

③ Pseudo Code

  - 너무 추상적일 수 있지만, 일단 다음과 같이 Pseudo Code를 정리할 수 있다.

 

출처: https://www.whatwant.com

 

  - 여기에서 중요한 것은 "stable sort" 방식이어야 한다는 점이다.

 

④ Running Time

  - 우리는 바로 전에 훌륭한 stable sort 알고리즘 중 하나를 공부했었다 → Counting Sort !!!

  - Counting Sort 알고리즘을 이용해서 Radix Sort를 해본다고 가정하면, 다음과 같다.

 

출처: https://www.whatwant.com

 

  - 위 내용을 정리하자면, 다음과 같다.

 

출처: https://www.whatwant.com

 

⑤ Changing d and k

  - 우리가 지금까지 다루는 방식은 다음과 같다.

출처: https://www.whatwant.com

 

  - 하지만, 이것을 좀 다르게 처리할 수도 있다.

 

출처: https://www.whatwant.com

 

  - 응?! 10진법이 아니라 100진법(진수)으로 처리할 수도 있다는 것이다.

 

⑥ optimal r

  - 일단 아래 그림을 잘 살펴보고 각 변수값의 정의를 확인하자.

  - n개의 b-bit 숫자가 있다고 했을 때, r 묶음으로 처리를 하는 경우이다.

 

출처: https://www.whatwant.com

 

  - 이럴 때, 우리는 다음의 최적해 r 값을 찾아야 하는 것이다.

 

출처: https://www.whatwant.com

 

  - 2 가지 경우로 나누어서 생각해보자.

 

출처: https://www.whatwant.com

 

  - 위의 경우는 입력값 개수에 비해서 b값이 많이 작을 경우이다.

    . 이 때는 굳이 나누지 말고 통으로 (하나로) 묶어서 정렬을 해도 충분하다는 의미이다.

 

  - 다른 경우는 다음과 같다.

 

출처: https://www.whatwant.com

 

  - 입력값 개수보다 값 자체가 길면, 좀 나누어서(log n 정도) 정렬을 하는 것이 좋다는 의미이다.

 

⑦ extra memory

  - 앞에서 살펴봤겠지만, 일단 Radix Sort는 in place 알고리즘은 아니다.

 

⑧ memory copy

  - d 값만큼 정렬 step이 발생하는데, 이 때마다 값들을 복사해야하는데 이로 인한 cost가 크다.

 

 

 

뭔가 좀 어수선하게 설명이 되었는데,

전체적인 흐름은 파악이 되었을거라 기대해본다.

반응형

 

 

이런 타이틀을 왜 이제야 알았을까~

나와 같은 라떼 아저씨/아줌마들에게 정말 가성비 좋은 게임이다 !!!

 

 

게임이 하나가 아닌 엄청 많은 게임이 포함되어 있는 합본이다 !!!

 

 

이런 이런.... "뽀글뽀글" .... "BUBBLE BOBBLE" 이다 !!!

 

 

엄청 잘 정리되어있다.

 

 

당연히 게임 조작법을 너무나 친절하게 알려주고 있다.

 

 

난이도를 포함해서 게임 자체에 대한 설정도 원하는대로 할 수 있다.

 

 

"Game Description" 메뉴를 통해 배경 스토리도 알 수 있다.

 

 

"Hints and Tips" 메뉴를 들어가면 ...

 

 

CHEATS 내역까지도 설명을 해준다.

 

 

게임 디자이너의 인터뷰 영상까지 있다 !!!!

실제 인터뷰 영상을 보여준다 !!!

 

 

아~ 추억이 방울 방울~

 

 

뉴질랜드 스토리 !!!

 

 

오락실에서 했던 그 게임 그대로다 !!!

 

 

눈물이 찔끔 나올 정도로.... 추억이 떠오른다 !!!

 

 

 

지금 시점에서 PS2 게임 자체의 그래픽을 보면 아쉬움이 가득인데,

이 게임들의 그래픽은 더더욱 아쉬울 수도 있지만, 추억 하나로 모든게 극복이 된다.

 

TAITO에서 만든 명작들이 포함된 게임인데, 어떤 것들이 있냐면 ...

 

1978 SPACE INVADERS 스페이스 인베이더
1979 SPACE INVADERS PART 2 스페이스 인베이더 파트2
1980 PHEONIX 피닉스
1981 COLONY 7 콜로니 7
1982 ELECTRIC YO-YO 일렉트릭 요요
1982 JUNGLE HUNT 정글 헌트
1982 ZOO KEEPER 주키퍼
1983 ELEVATOR ACTION 엘레베이터 액션
1984 GREAT SWORDSMAN 그레이트 소드맨
1985 RETURN OF THE INVADERS 리턴 오브 더 인베이더
1986 BUBBLE BOBBLE 버블 보블 (뽀글뽀글)
1986 GLADIATOR 글래디에이터 (황금성)
1986 TOKIO 토키오
1987 EXZISUS 이그지저스
1987 PLUMP POP 플럼 팝
1987 RAINBOW ISLANDS 레인보우 아일랜드
1987 RASTAN 라스턴
1987 SUPER QIX 슈퍼 퀵스
1987 OPERATION WOLF 오퍼레이션 울프
1988 OPERATION THUNDERBOLT 오퍼레이션 썬더볼트
1988 THE NEW ZEALAND STORY 뉴질랜드 스토리
1989 BATTLE SHARK 배틀 샤크
1989 CONTINENTAL CIRCUS 컨티넨털 서커스
1989 PLOTTING 플로팅
1989 VOLFIED 볼피드
1990 SPACE GUN 스페이스 건
1990 THE NINJA KIDS 닌자 키즈
1990 THUNDERFOX 썬더 폭스
1993 TUBE IT 튜브 잇

이 게임들을 한 번씩만 해본다고 해도.... 정말 가성비 타이틀이다 !!!

 

오락실 게임 특성상 타이밍 이슈가 있기에

에뮬레이터로 진행하려면 문제가 없을까!? 우려를 했지만 전혀 문제가 없었다.

 

하지만, 이건 정말.... 거실로 뛰어가 PS2 전원을 키고 고고씽~~~~!!!!!

 

등짝 스매싱을 하려다가 .... 같이 추억을 곱씹고 있는 우리집 대장님!!!! ^^

 

반응형

출처: https://www.whatwant.com

 

이번에 살펴볼 Sorting algorithm은 앞에서 공부한 것들과 궤를 달리한다.

 

지금까지 공부한 것은 비교(comparison) 기반의 정렬이었지만

이번에는 counting 방식으로 정렬을 하는 계수 정렬(Counting sort)이다.

 

① basic counting sort

  - 비교 행위 없이 입력값 하나씩 읽어가며 개수만 세는 것으로 정렬이 된다.

 

출처: https://www.whatwant.com

 

② extra memory

  - 개수를 세기 위한 C(count array)가 추가로 필요하다. (= in place 알고리즘이 아니다!)

 

③ No stable

  - 입력값의 순서가 유지되는 것을 "stable 하다"고 한다.

 

  - 위 그림에서 3개의 "3" 입력값에 대해서 살펴보면,

    . (빨간색) index 값으로 표현해보면 '3-3', '6-3', '8-3'이라고 할 수 있다. 각 '3'은 다른 '3'이다.

    . 이 때, 출력값(output array)에서 '5-3', '6-3', '7-3'이 있는데,

    . 입력값의 순서가 유지된 것이라고 할 수 있을까?

 

출처: https://www.whatwant.com

 

  - Counting sort는 stable 할 수 없는 algorithm 이다.

 

④ Stabled(Advanced) Counting Sort

  - Counting sort 를 Stable 하도록 만들 수 있다.

 

  - Encoding ..... 기존 count array를 기반으로 누적값을 저장하는 C' array를 만들어줘야 한다.

 

출처: https://www.whatwant.com

 

  - Decoding ..... 누적값을 갖고 있는 C' array와 입력값(A array)를 가지고 출력값(B array)를 만들어준다.

    . 입력값의 제일 끝에서 부터 역으로 하나씩 처리하는 방식이다.

 

출처: https://www.whatwant.com

 

    . 하나 더 해보면, 다음과 같다.

 

출처: https://www.whatwant.com

 

    . 그 다음 "3" 값을 주의 깊게 봐야 한다.

      왜냐하면, 처음에 했던 "3"과 이번에 해야하는 "3"은 다른 "3"이기 때문이다.

 

출처: https://www.whatwant.com

 

    . 뭔가 신기하게 보일 수도 있긴 하지만... 그래서 뭐?

    . 입력값(A array)의 3의 순서에 따라 출력값(B array)의 순서가 정해진다. → Stable 하다 !!!

 

⑤ Pseudo code

  - 왠지 복잡해보이지만, 복잡하지 않은 코드이다.

 

출처: https://www.whatwant.com

 

  - 변수 (메모리) 모습을 그려보면 다음과 같다.

 

출처: https://www.whatwant.com

 

  - 여기에서 k는 입력값의 종류(개수)를 의미한다.

  - 코드를 분석해보면 다음과 같다.

 

출처: https://www.whatwant.com

 

⑥ Running Time

  - 실행 시간은 선형이다.

 

출처: https://www.whatwant.com

 

  - 정리해보면 다음과 같다.

 

출처: https://www.whatwant.com

 

 

그 이름에 걸맞게 입력값을 하나씩 세기만 하면 되는 시간인 것이다 !!!

즉, 앞에서 살펴본 "Lower bounds for (comparison) sort" 제약에 해당하지 않는다 !!!

 

반응형

출처: https://www.whatwant.com

 

[ 공부 순서 ]

① Comparison sorts

② Lower bounds for (comparison) sorting

③ Decision-tree model

 

 

지금까지 공부한 Sorting 방식은 전부 비교(comparison)라는 행위를 이용하고 있다.

그런데, 이러한 Comparison sorting에 있어서 worst-case인 경우

최소한 "n log n" 번 비교를 해야한다는 것에 대한 증명 과정을 살펴보고자 한다.

 

 

① Comparison sorts

  - 정렬(Sorting)을 하기 위해서 크기 비교(comparison)만을 수행하는 알고리즘

  - 종류 : Insertion / Merge / Selection / Heap / Quick

 

② Lower bounds for (comparison) sorting

  - 모든 comparison sort는 worst case 상황에서 최소한  Ω(n log n) 번의 비교를 요구한다.

  → 이후 내용은 본 명제를 증명하는 과정

 

③ Decision-tree model

  - 모든 입력은 동일한 값이 없다고 가정

  - 비교(comparison)는 <, >, ≤, ≥ 4종류가 있지만, ai ≤ aj 하나로 모두 처리 가능

    ( ai ≤ aj 비교를 수행하게 되면 True or False 결과. 그러므로  ai ≤ aj 한 번만 수행하면 됨)

 

  - comparison sort는 decision-tree로 표현(설명) 가능

    . full binary tree

    . leaf는 입력 값들의 순열(permutation)

    . internal node는 어떤 값을 비교하는 지를 표현

 

  - 입력값 크기가 3인 insertion sort는 다음과 같은 decision-tree model로 표현

 

출처: https://www.whatwant.com

 

  - 예시를 하나 돌려보면 다음과 같다.

 

출처: https://www.whatwant.com

 

  - leaf 개수는 어떻게 계산할 수 있을까?

    . 입력값의 개수가 n 일 때, n!

    . 위 예시의 경우, n = 3 이기 때문에 3! = 6

 

  - Left / Right subtrees

    . 특정 node를 기준으로 왼쪽은 ai ≤ aj 값들만 존재, 오른쪽은 ai > aj 값들만 존재

    . 밑의 node들도 모두 동일한 결과

 

출처: https://www.whatwant.com

 

  ★ the worst-case number of comparisons = the height of its decision-tree

    - h : height

    - n : number of element

    - n! : number of leaves

 

출처: https://www.whatwant.com

 

 

음.... 일단 내용은 파악했는데,

그래서 어쩌라고? ^^

 

다음에 살펴볼 counting 방식의 정렬(sorting)은 이와 다르다 !!!

반응형

+ Recent posts