๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Algorithm

[Algorithm] ํ€ต ์ •๋ ฌ (Quick Sort)

๐Ÿ’กํ€ต ์ •๋ ฌ(Quick sort) ์•Œ๊ณ ๋ฆฌ์ฆ˜?

  • ์ฐฐ์Šค ์•คํ„ฐ๋‹ˆ ๋ฆฌ์ฒ˜๋“œ ํ˜ธ์–ด๊ฐ€ ๊ฐœ๋ฐœํ•œ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜
  • ๋‹ค๋ฅธ ์›์†Œ์™€์˜ ๋น„๊ต๋งŒ์œผ๋กœ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋น„๊ต ์ •๋ ฌ์— ์†ํ•จ
  • ๋ถ„ํ•  ์ •๋ณต ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •๋ ฌ
    1. ๋ฆฌ์ŠคํŠธ ๊ฐ€์šด๋ฐ์„œ ํ•˜๋‚˜์˜ ์›์†Œ๋ฅผ ๊ณ ๋ฆ„, ์ด ์›์†Œ๋ฅผ ํ”ผ๋ฒ— ์ด๋ผ๊ณ  ํ•œ๋‹ค.
    2. ํ”ผ๋ฒ— ์•ž์—๋Š” ํ”ผ๋ฒ—๋ณด๋‹ค ๊ฐ’์ด ์ž‘์€ ๋ชจ๋“  ์›์†Œ๋“ค์ด ์˜ค๊ณ , ํ”ผ๋ฒ— ๋’ค์—๋Š” ๋น„ํŽ๋ณด๋‹ค ๊ฐ’์ด ํฐ ๋ชจ๋“  ์›์†Œ๋“ค์ด ์˜ค๋„๋ก ํ”ผ๋ฒ—์„ ๊ธฐ์ค€์œผ๋กœ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‘˜๋กœ ๋‚˜๋ˆˆ๋‹ค. -> ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‘˜๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์„ ๋ถ„ํ• ์ด๋ผ๊ณ  ํ•œ๋‹ค.
    3. ๋ถ„ํ• ์„ ๋งˆ์นœ ๋’ค์— ํ”ผ๋ฒ—์€ ๋” ์ด์ƒ ์›€์ง์ด์ง€ ์•Š๋Š”๋‹ค.
    4. ๋ถ„ํ• ๋œ ๋‘ ๊ฐœ์˜ ์ž‘์€ ๋ฆฌ์ŠคํŠธ์— ๋Œ€ํ•ด ์žฌ๊ท€์ ์œผ๋กœ ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•œ๋‹ค. -> ๋ฆฌ์ŠคํŠธ์˜ ํฌ๊ธฐ๊ฐ€ 0์ด๋‚˜ 1์ด ๋ ๋•Œ๊นŒ์ง€ ์žฌ๊ท€๋ฅผ ๋ฐ˜๋ณต

๐Ÿ’ก๊ตฌ์ฒด์ ์œผ๋กœ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํŒŒํ—ค์ณ๋ณด์ž

  • ํ€ต ์ •๋ ฌ์€ ๋‹ค์Œ์˜ ๋‹จ๊ณ„๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค.
    • ๋ถ„ํ•  : ์ž…๋ ฅ ๋ฐฐ์—ด์„ ํ”ผ๋ฒ—์„ ๊ธฐ์ค€์œผ๋กœ ๋น„๊ท ๋“ฑํ•˜๊ฒŒ 2๊ฐœ์˜ ๋ถ€๋ถ„ ๋ฐฐ์—ด๋กœ ๋‚˜๋‰˜์–ด์ง„๋‹ค. (์™ผ์ชฝ : ํ”ผ๋ฒ—์„ ์ค‘์‹ฌ์œผ๋กœ ์ž‘์€ ์ˆ˜๋“ค, ์˜ค๋ฅธ์ชฝ : ํ”ผ๋ฒ—์„ ์ค‘์‹ฌ์œผ๋กœ ํฐ ์ˆ˜๋“ค)
    • ์ •๋ณต : ๋ถ€๋ถ„ ๋ฐฐ์—ด์„ ์ •๋ ฌํ•œ๋‹ค. ๋ถ€๋ถ„ ๋ฐฐ์—ด์˜ ํฌ๊ธฐ๊ฐ€ ์ถฉ๋ถ„ํžˆ ์ ์ง€ ์•Š์œผ๋ฉด ์ˆœํ™˜ ํ˜ธ์ถœ์„ ์ด์šฉํ•˜์—ฌ ๋‹ค์‹œ ๋ถ„ํ•  ์ •๋ณต ๋ฐฉ๋ฒ•์„ ์ ์šฉ
    • ๊ฒฐํ•ฉ : ์ •๋ ฌ๋œ ๋ถ€๋ถ„ ๋ฐฐ์—ด๋“ค์„ ํ•˜๋‚˜์˜ ๋ฐฐ์—ด๋กœ ํ•ฉ๋ณ‘ํ•œ๋‹ค.

๐Ÿ’ก ํ€ต ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์˜ˆ์ œ

  • ํ”ผ๋ฒ—์„ ์ž…๋ ฅ ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ๋ฒˆ์งธ ๋ฐ์ดํ„ฐ๋กœ ํ•œ๋‹ค.
  • low, high ์ธ๋ฑ์Šค ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‘๊ฐœ์˜ ๋ถ€๋ถ„ ๋ฆฌ์ŠคํŠธ๋กœ ๋‚˜๋ˆˆ๋‹ค.
  • 1ํšŒ์ „ : ํ”ผ๋ฒ— = 5 
    1. low : ์™ผ์ชฝ์—์„œ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํƒ์ƒ‰, ํ”ผ๋ฒ—๋ณด๋‹ค ํฐ ๋ฐ์ดํ„ฐ(8)์„ ์ฐพ์œผ๋ฉด ๋ฉˆ์ถ˜๋‹ค.
    2. high : ์˜ค๋ฅธ์ชฝ์—์„œ ์™ผ์ชฝ์œผ๋กœ ํƒ์ƒ‰, ํ”ผ๋ฒ—๋ณด๋‹ค ์ž‘์€ ๋ฐ์ดํ„ฐ(2)์„ ์ฐพ์œผ๋ฉด ๋ฉˆ์ถ˜๋‹ค.
    3. low์™€ high๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋‘๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋กœ ๊ตํ™˜ํ•œ๋‹ค.
    4. ์ด ํƒ์ƒ‰๊ณผ ๊ตํ™˜ ๊ณผ์ •์€ low์™€ high๊ฐ€ ์—‡๊ฐˆ๋ฆด๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•œ๋‹ค.
  • 2,3ํšŒ์ „ : ์œ„์™€ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฐ˜๋ณตํ•œ๋‹ค.

 

๐Ÿ’ก C++ ์ฝ”๋“œ

#include <iostream>
using namespace std;

// ๋‘ ๊ฐ’์„ ์„œ๋กœ ๋ฐ”๊พธ๋Š” swap ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ
void swap(int *a, int *b, int temp){
    temp = *b;
    *b = *a;
    *a = temp;
}

// ๋ถ€๋ถ„์ •๋ ฌ ( -> pivot์˜ ์œ„์น˜ ๋ฆฌํ„ด )
int partition(int list[], int left, int right){
    int pivot, temp;
    int low, high;

    pivot = list[left];
    low = left;
    high = right+1;

    // ์ „์ฒด do-while ๋ฌธ : low์™€ high๊ฐ€ ๊ต์ฐจํ•  ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต = ๊ต์ฐจํ•  ๊ฒฝ์šฐ stop!!
    do{
        //low๋ฅผ ๋จผ์ € ์ฆ๊ฐ€์‹œํ‚ค๋ฉด์„œ ์‹œ์ž‘
        //low๊ฐ€ right๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ ๊ฐ™๊ณ  && list[low]๊ฐ€ pivot๋ณด๋‹ค ์ž‘์„ ๊ฒฝ์šฐ ๋™์•ˆ ๋ฐ˜๋ณต
        do{
            low++;
        }while(low<=right && list[low]<pivot);

        //high๋ฅผ ๋จผ์ € ์ฆ๊ฐ€์‹œํ‚ค๋ฉด์„œ ์‹œ์ž‘
        //high๊ฐ€ left๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™๊ณ  && list[high]๊ฐ€ pivot๋ณด๋‹ค ํด ๊ฒฝ์šฐ ๋™์•ˆ ๋ฐ˜๋ณต
        do{
            high--;
        }while(high>=left && list[high]>pivot);

        // ๋‚ด๋ถ€ ๋‘๊ฐœ์˜ do-while ๋ฌธ์„ ๊ฑฐ์ณ์„œ ๋‚˜์˜จ low์™€ high์˜ ๊ฐ’์—์„œ
        // low์™€ high๊ฐ€ ๊ต์ฐจํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ๋‘ list[low]์™€ list[high]์˜ ๊ฐ’์„ ๋ฐ”๊พธ์–ด ์ค€๋‹ค.
        if(low<high){
            swap(&list[low], &list[high], temp);
        }

    }while(low<high);

    //low์™€ high๊ฐ€ ๊ต์ฐจํ–ˆ์œผ๋ฉด, list๋ฅผ ๋น ์ ธ๋‚˜์™€ list[left](=pivot)๊ณผ list[high]๋ฅผ ๊ตํ™˜ํ•œ๋‹ค.
    swap(&list[left], &list[high], temp);

    return high;
}

void quickSort(int list[], int left, int right){
    // ์ •๋ ฌ ๋ฒ”์œ„๊ฐ€ 2๊ฐœ์ด์ƒ์˜ ๋ฐ์ดํ„ฐ๋ผ๋ฉด, (๋ฆฌ์ŠคํŠธ์˜ ํฌ๊ธฐ๊ฐ€ 0์ด๋‚˜ 1์ด ์•„๋‹ˆ๋ฉด)
    if(left<right){
        // pivot์˜ ์œ„์น˜
        int pivot_lo = partition(list, left, right);

        // pivot์„ ์ œ์™ธํ•œ 2๊ฐœ์˜ ๋ถ€๋ถ„ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆœํ™˜ ํ˜ธ์ถœ (= ์žฌ๊ท€)
        // <<left~pivot์˜ ๋ฐ”๋กœ ์•ž>>
        quickSort(list, left, pivot_lo-1);
        // << pivot์˜ ๋ฐ”๋กœ ๋’ค~right>>
        quickSort(list, pivot_lo+1,right);
    }

}

int main(){

    int list[9] = {5, 3, 8, 4, 9, 1, 6, 2, 7};
    int n = 9;
    // ๋ฐฐ์—ด์˜ ์‹œ์ž‘ = 0, ๋ฐฐ์—ด์˜ ๋ = 9-1=8
    quickSort(list,0,n-1);

    cout<<"*****quickSort ํ›„*****"<<endl;

    for(int i = 0 ; i < 9 ; i++){
        cout<<list[i]<<endl;
    }
}

 

๐Ÿ’ก ํ€ต ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ํŠน์ง•

  • ์žฅ์ 
    1. ์†๋„๊ฐ€ ๋น ๋ฅด๋‹ค.
      • ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ์˜ ์ด๋™์„ ์ค„์ด๊ณ  ๋จผ๊ฑฐ๋ฆฌ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตํ™˜ํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ,
      • ํ•œ ๋ฒˆ ๊ฒฐ์ •๋œ ํ”ผ๋ฒ—๋“ค์ด ์ถ”ํ›„ ์—ฐ์‚ฐ์—์„œ ์ œ์™ธ๋˜๋Š” ํŠน์„ฑ ๋•Œ๋ฌธ์ด๋‹ค.
    2. ์ถ”๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ํ•„์š”๋กœ ํ•˜์ง€ ์•Š๋Š”๋‹ค. 
      • ๋น„๊ต๋งŒ์„ ํ†ตํ•ด์„œ ๊ตฌํ˜„
      • O(log n) ๋งŒํผ์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•„์š”๋กœ ํ•œ๋‹ค.
  • ๋‹จ์ 
    1. ์ด๋ฏธ ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ์— ๋Œ€ํ•ด์„œ๋Š” ํ€ต ์ •๋ ฌ์˜ ๋ถˆ๊ท ํ˜• ๋ถ„ํ• ์— ์˜ํ•ด ์˜คํžˆ๋ ค ์ˆ˜ํ–‰์‹œ๊ฐ„์ด ๋” ๋งŽ์ด ๊ฑธ๋ฆฐ๋‹ค.
      • ํ•ด๊ฒฐ๋ฐฉ๋ฒ• : ๋ฆฌ์ŠคํŠธ ๋‚ด์˜ ๋ช‡๊ฐœ์˜ ๋ฐ์ดํ„ฐ ์ค‘์—์„œ ํฌ๊ธฐ์ˆœ์œผ๋กœ ์ค‘๊ฐ„ ๊ฐ’(medium)์„ ํ”ผ๋ฒ—์œผ๋กœ ์„ ํƒ

 

๐Ÿ’ก ํ€ต ์ •๋ ฌ์˜ ์‹œ๊ฐ„๋ณต์žก๋„

ํ€ต ์ •๋ ฌ์˜ ์„ฑ๋Šฅ์€ ํ”ผ๋ด‡ ์„ ํƒ์ด ์ขŒ์šฐํ•œ๋‹ค!

  • ๊ฐ€์žฅ ์ž‘์€ ์ˆซ์ž๋˜๋Š” ๊ฐ€์žฅ ํฐ ์ˆซ์ž๊ฐ€ ์„ ํƒ๋˜๋ฉด, ํ•œ๋ถ€๋ถ„์œผ๋กœ ์น˜์šฐ์น˜๋Š” ๋ถ„ํ• ์„ ์•ผ๊ธฐ-> ์ตœ์•…!

1๏ธโƒฃ ์ตœ์„ ์˜ ๊ฒฝ์šฐ

  • ์ˆœํ™˜ ํ˜ธ์ถœ์˜ ๊นŠ์ด
    • ๋ฐฐ์—ด์˜ ์›์†Œ๊ฐœ์ˆ˜ n์ด 2์˜ ๊ฑฐ๋“ญ ์ œ๊ณฑ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜์ž ( n = 2^k )
    • n = 2^3 ์ผ ๊ฒฝ์šฐ, 2^3 -> 2^2 -> 2^1 -> 2^0 ์ˆœ์œผ๋กœ ์ค„์–ด๋“ค์–ด ์ˆœํ™˜ ํ˜ธ์ถœ์˜ ๊นŠ์ด๊ฐ€ 3์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
    • n = 2^k ์ผ ๊ฒฝ์šฐ, ์ˆœํ™˜ ํ˜ธ์ถœ์˜ ๊นŠ์ด๋Š” k์ด๊ณ  k = logโ‚‚n ์ด๋‹ค.
    • logโ‚‚n
  • ๊ฐ ์ˆœํ™˜ ํ˜ธ์ถœ ๋‹จ๊ณ„์—์„œ์˜ ๋น„๊ต ์—ฐ์‚ฐ
    • ํ‰๊ท  n ๋ฒˆ
  • ์ด๋™ ํšŸ์ˆ˜  = ๋น„๊ต ํšŸ์ˆ˜๋ณด๋‹ค ์ ์œผ๋ฏ€๋กœ ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋น„๊ตํšŸ์ˆ˜ = ์ˆœํ™˜ ํ˜ธ์ถœ์˜ ๊นŠ์ด * ๊ฐ ์ˆœํ™˜ ํ˜ธ์ถœ ๋‹จ๊ณ„์˜ ๋น„๊ต ์—ฐ์‚ฐ = nlogโ‚‚n
  • ์ตœ์„ ์˜ ๊ฒฝ์šฐ T(n) = O(nlogโ‚‚n)

 

 

2๏ธโƒฃ ์ตœ์•…์˜ ๊ฒฝ์šฐ

  • ๋ฆฌ์ŠคํŠธ๊ฐ€ ๊ณ„์† ๋ถˆ๊ท ํ˜•ํ•˜๊ฒŒ ๋‚˜๋ˆ„์–ด์ง€๋Š” ๊ฒฝ์šฐ ( ํŠนํžˆ ์ด๋ฏธ ์ •๋ ฌ๋œ ๋ฆฌ์ŠคํŠธ์— ๋Œ€ํ•ด์„œ ํ€ต ์ •๋ ฌ์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ ) 
  • ์ˆœํ™˜ ํ˜ธ์ถœ์˜ ๊นŠ์ด
    • ๋ฐฐ์—ด์˜ ์›์†Œ๊ฐœ์ˆ˜ n์ด 2์˜ ๊ฑฐ๋“ญ ์ œ๊ณฑ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•˜์ž ( n = 2^k ) 
    • ์ˆœํ™˜ ํ˜ธ์ถœ์˜ ๊นŠ์ด๋Š” n
    • n
  • ๊ฐ ์ˆœํ™˜ ํ˜ธ์ถœ ๋‹จ๊ณ„์—์„œ์˜ ๋น„๊ต ์—ฐ์‚ฐ
    • ํ‰๊ท  n ๋ฒˆ
  • ์ด๋™ ํšŸ์ˆ˜  = ๋น„๊ต ํšŸ์ˆ˜๋ณด๋‹ค ์ ์œผ๋ฏ€๋กœ ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋น„๊ตํšŸ์ˆ˜ = ์ˆœํ™˜ ํ˜ธ์ถœ์˜ ๊นŠ์ด * ๊ฐ ์ˆœํ™˜ ํ˜ธ์ถœ ๋‹จ๊ณ„์˜ ๋น„๊ต ์—ฐ์‚ฐ = n^2
  • ์ตœ์•…์˜ ๊ฒฝ์šฐ T(n) = O(n^2)

 

 

3๏ธโƒฃ ํ‰๊ท 

  • ํ‰๊ท  T(n) = O(nlogโ‚‚n)
  • ํฌ๊ธฐ๊ฐ€ n์ธ ๋ฐฐ์—ด ์ค‘ ์–ด๋–ค ํ•˜๋‚˜๊ฐ€ pivot์œผ๋กœ ์„ ํƒ๋  ํ™•๋ฅ  = 1/n
  • ์ตœ๋Œ€ n ๋ฒˆ ์—ฐ์‚ฐ์„ ์›์†Œ n๊ฐœ๊ฐ€ ์ง„ํ–‰ = n^2
  • ์ด๊ฒŒ ์ด logโ‚‚n ๊ฐœ์˜ ์ธต์œผ๋กœ ๊ตฌ์„ฑ
  • 1/n * n^2 * logโ‚‚n = nlogโ‚‚n

์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‹œ๊ฐ„๋ณต์žก๋„ ์ •๋ฆฌ

 

 


๐Ÿ’ก ํ€ต ์ •๋ ฌ์˜ ์„ฑ๋Šฅ ํ–ฅ์ƒ ๋ฐฉ๋ฒ•

  • ์ž…๋ ฅ์˜ ํฌ๊ธฐ๊ฐ€ ๋งค์šฐ ํด๋•Œ, ํ€ต ์ •๋ ฌ์˜ ์„ฑ๋Šฅ์„ ๋” ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„œ ์‚ฝ์ž… ์ •๋ ฌ์ด ๋™์‹œ์— ์‚ฌ์šฉ
  • ์ž…๋ ฅ์˜ ํฌ๊ธฐ๊ฐ€ ์ž‘์„ ๋•Œ์—๋Š” ํ€ต ์ •๋ ฌ์ด ์‚ฝ์ž… ์ •๋ ฌ๋ณด๋‹ค ๋น ๋ฅด์ง€๋งŒ์€ ์•Š๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์žฌ๊ท€ํ˜ธ์ถœ๋กœ ์ˆ˜ํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ!
  • ๋ถ€๋ถ„๋ฌธ์ œ์˜ ํฌ๊ธฐ๊ฐ€ ์ž‘์•„์ง€๋ฉด ๋”์ด์ƒ์˜ ๋ถ„ํ• (์žฌ๊ท€ํ˜ธ์ถœ)์„ ์ค‘๋‹จํ•˜๊ณ  ์‚ฝ์ž… ์ •๋ ฌ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

+ ์‘์šฉ

  • ํ€ต ์ •๋ ฌ์€ ์ปค๋‹ค๋ž€ ํฌ๊ธฐ์˜ ์ž…๋ ฅ์— ๋Œ€ํ•ด์„œ ๊ฐ€์žฅ ์ข‹์€ ์„ฑ๋Šฅ์„ ๋ณด์ด๋Š” ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜
  • ์‹ค์งˆ์ ์œผ๋กœ ์–ด๋Š ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜๋ณด๋‹ค ์ข‹์€ ์„ฑ๋Šฅ์„ ๋ณด์ธ๋‹ค.
  • ์ƒ๋ฌผ ์ •๋ณด ๊ณตํ•™์—์„œ ํŠน์ • ์œ ์ „์ž๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ฐพ๋Š”๋ฐ ์ ‘๋ฏธ ๋ฐฐ์—ด๊ณผ ํ•จ๊ป˜ ํ€ต ์ •๋ ฌ์ด ํ™œ์šฉ๋œ๋‹ค.

 

Reference

 

[์•Œ๊ณ ๋ฆฌ์ฆ˜] ํ€ต ์ •๋ ฌ(quick sort)์ด๋ž€ - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io