Loading [MathJax]/jax/output/CommonHTML/jax.js

[Algorithm Part 3] 3. Divide-and-Conquer algorithms

2023. 7. 12. 15:31Algorithm

이번 글에서는, divide-and-conquer 기법을 활용한 유명 알고리즘에 대해 살펴볼 것이다.


1. Quicksort

Problem

정렬 문제다. 즉, 크기가 n인 배열(=S)을 정렬하는 문제다.

Algorithm

  1. pivot item(=S[0])으로 배열 S를 partition(=분할)한다.
    1. pivot item보다 작으면 pivot 왼쪽으로 이동
    2. pivot item보다 크면 pivot 오른쪽으로 이동
  2. 분할된 2개 부분 배열을 각각 정렬한다. (만약, 부분 배열을 더 분할할 수 있다면, 재귀를 통해 정렬한다.)
  3. 정렬된 부분 배열 2개와 pivot item을 연결시켜, original 배열을 정렬한다.

Analysis

base operation: pivot item과 S[i]간의 비교 연산

input size: n(=size of array)

worst-case time complexity (already sorted):

W(n)=W(0)+W(n1)+n1=n(n1)2Θ(n2)

average-case time complexity (randomly shuffled):

A(n)=np=11n[A(p1)+A(np)]+n1=2nnp=1A(p1)+n1=1.38(n+1)lgnΘ(nlgn)


2. Stressen's Matrix Multiplication Algorithm

Problem

행렬 곱 연산

Algorithm

  1. 행렬 A, B를 각각 4개의 부분 행렬(A11,A12,A21,A22 and B11,B12,B21,B22)로 나눈다.
  2. 분할된 부분 행렬의 합을 가지고 행렬 곱 연산을 진행한다. (만약, 부분 행렬의 합을 더 나눌 수 있다면, 재귀를 통해 행렬 곱 연산을 한다.)
    1. M1=(A11+A22)(B11+B22)
    2. M2=(A21+A22)B11
    3. M3=A11(B12B22)
    4. M4=A22(B21B11)
    5. M5=(A11+A12)B22
    6. M6=(A21A11)(B11+B12)
    7. M7=(A12A22)(B21+B22)
  3. 7개 행렬(M1M7)을 기반으로 , A, B의 행렬 곱 연산을 진행한다.

[M1+M4M5+M7M3+M5M2+M4M1+M3M2+M6]

Analysis 1

base operation: 행렬 곱

input size: n (=A,B의 행, 열의 개수)

every-case time complexity:

T(n)=7T(n2)=nlg7n2.81Θ(n2.81)

Analysis 2

base operation: 행렬 합 및 차

input size: n (=A, B의 행, 열의 개수)

every-case time complexity:

T(n)=7T(n2)+18(n2)2=6nlg76n26n2.816n2Θ(n2.81)

 

행렬 곱은 적어도 Θ(n2)의 시간 복잡도를 갖고 있으며, 이를 만족하는 알고리즘은 아직 발견되지 않았다.


3. Multiplication of Large Integers

Problem

n자리수 정수 u, v의 곱 연산

Algorithm

  1. n자리수 정수를 2개 n/2자리수 정수로 표현(or 분할)한다.
    (u=x×10n/2+y,v=w×10n/2+z)
  2. n/2자리수 정수의 곱 연산을 진행한다. (만약, n/2자리수 정수를 더 분할할 수 있다면, 재귀를 통해 곱 연산을 한다.)
    1. x×w
    2. (x+y)×(w+z)
    3. yz
  3. n/2자리수 정수의 곱 연산을 기반으로, uv의 곱 연산을 진행한다.

uv=xw×10n+[(x+y)(w+z)(xw+yz)]×10n/2+yz

Analysis

base operation: 한자리 숫자 조작(=manipulation)

input size: n(= u, v의 자리수)

worst-case time complexity:

W(n)=3W(n2)+cn=cnlg3n1.58Θ(n1.58)


4. RSelect (=randomize)

Problem

kth order statistic problem 즉, 크기가 n인 배열(=S)에서 k번째로 작은 item을 찾는 문제다.

이는 정렬 문제보다 쉬운 문제다.

Algorithm

  1. pivot item(=S[0])으로 배열 S를 partition(=분할)한다.
    1. pivot item보다 작으면 pivot 왼쪽으로 이동
    2. pivot item보다 크면 pivot 오른쪽으로 이동
  2. 만약 pivot index(=j)가 k일 경우, pivot item 반환. 그렇지 않으면,
    1. k가 pivot index보다 작다면, 왼쪽 부분 배열에서 k번째로 작은 item을 찾는다.
    2. k가 pivot index보다 크다면, 오른쪽 부분 배열에서 kj번째로 작은 item을 찾는다.
    3. 만약, 부분 배열을 더 분할할 수 있다면, 재귀를 통해 item을 찾는다.
  3. 부분 배열에서 찾은 item이 solution이다.

Analysis

base operation: pivot item과 S[i]간의 비교 연산

input size: n(=size of array)

worst-case time complexity (already sorted):

W(n)=W(n1)+n1=n(n1)2Θ(n2)

average-case time complexity (randomly shuffled):

A(n)=1nnp=1A(p1)+n1=(n1)(1+1/2+1/4+)2nΘ(n)


5. DSelect (=deterimistic)

Problem

kth order statistic problem 즉, 크기가 n인 배열(=S)에서 k번째로 작은 item을 찾는 문제다.

Algorithm

  1. pivot(=MoM)을 구한다.
    1. 크기가 5인 부분 배열의 중앙값을 모두 구해, 중앙값 집합(m=(m1,m2,,mn/5))을 만든다.
    2. m의 중앙값(=Median-of-Median)을 구한다. 즉, m에서 m/5번째로 작은 item을 찾는다. (만약, m을 더 나눌 수 있다면, 재귀를 통해 MoM을 구한다.)
  2. 만약 MoM index(=j)가 k일 경우, MoM item 반환. 그렇지 않으면,
    1. k가 pivot index보다 작다면, 왼쪽 부분 배열에서 k번째로 작은 item을 찾는다.
    2. k가 pivot index보다 크다면, 오른쪽 부분 배열에서 kj번째로 작은 item을 찾는다.
    3. 만약, 부분 배열을 더 분할할 수 있다면, 재귀를 통해 item을 찾는다.
    4. 이때, 3n10<j<7n10을 만족한다.
  3. 부분 배열에서 찾은 item이 solution이다

Analysis

base operation: pivot item과 S[i]간의 비교 연산

input size: n(=size of array)

worst-case time complexity (already sorted):

W(n)=n+W(n/5)+n1+W(7n10)Θ(n)