4. (알고리즘) 정렬


정렬 알고리즘

  • 정렬 이란 특정 기준에 따라 데이터 구성~을 의미하다
  • 일반적으로 문제 상황에 따라 수식과 같은 적절한 정렬 알고리즘을 사용한다.

  • 정렬 알고리즘데이터를 정렬하면 이진 검색이것이 가능해진다(이진 검색의 전처리이기도 하기 때문에 정렬 알고리즘이 중요하다.

    )

다양한 정렬 알고리즘에 대해 자세히 알아보세요.

정렬 선택


  • 선택 처리되지 않은 데이터 중 가장 작은 데이터를 선택하고 앞의 데이터로 교체를 반복합니다.

    하다.


    즉, 정렬되지 않은 데이터 중에서 가장 작은 데이터를 선택하여 첫 번째 데이터로 교체한 후 다음으로 작은 데이터를 선택하는 과정을 반복한다.

선택 정렬 알고리즘 코드(Python)

# 선택 정렬을 사용하여 오름차순 정렬
arr = (7, 5, 9, 0, 3, 1, 6, 2, 4, 8)

for i in range(len(arr)):
    min_idx = i # 가장 작은 원소의 인덱스
    for j in range(i + 1, len(arr)): 
        if arr(min_idx) > arr(j):
            min_idx = j
    arr(min_idx), arr(i) = arr(i), arr(min_idx)

print(arr)
>>> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  • 시간적 복잡성~이다 O(N^2) 오전.
    선택 정렬은 가장 작은 숫자를 N번 찾아 앞으로 이동합니다.

    또한 구현 방법에 따라 약간의 오류가 있을 수 있으나 총 연산 횟수는 N + (N – 1) + (N – 2) + … + 2 입니다.


    이것은 (N^2 + N -2) / 2로 표현할 수 있으며 Big-O 표기법에서는 단순히 O(N^2)입니다.

정렬 선택 데이터 개수가 10,000개 이상이면 선택 정렬 속도가 빠르게 느려지는 것을 확인하였다.

할수있다.

데이터 수(N) 정렬 선택 빠른 종류 기본 정렬 라이브러리
N=100 0.0123초 0.00156초 0.00000753초
N=1,000 0.354초 0.00343초 0.0000365초
N=10,000 15.475초 0.0312초 0.000248초

측정 시간은 컴퓨터마다 다를 수 있습니다.

상대적인 개념으로 이해합시다.


삽입으로 정렬


  • 삽입으로 정렬특정 데이터를 적절한 위치에 붙여넣습니다.


    함께 삽입으로 정렬 특정 데이터가 올바른 위치에 놓이기 전에 데이터가 이 시점까지 이미 정렬되었다고 가정합니다.


    정렬된 데이터 목록에서 일치하는 위치를 찾은 후 해당 위치에 삽입됩니다.


    선택 정렬보다 구현하기 어렵지만 실행 시간 측면에서 선택 정렬에 비해 효율적인 알고리즘으로 알려져 있다.

붙여넣을 알고리즘 코드 정렬(Python)

# 삽입 정렬을 사용하여 오름차순 정렬
arr = (7, 5, 9, 0, 3, 1, 6, 2, 4, 8)

for i in range(1, len(arr)):
    # 인덱스 i부터 1까지 감소하며 반복
    for j in range(i, 0, -1):
        # 인덱스 i부터 1까지 감소하며 반복하는 문법
        # 이것을 사용한 이유는, 삽입 정렬의 경우 특정한 데이터의 왼쪽에 있는 데이터들은 이미 정렬이 된 상태이므로
        # 자기보다 작은 데이터를 만났다면 더 이상 데이터를 살펴볼 필요가 없기 때문이다.

if arr(j) < arr(j - 1): arr(j), arr(j - 1) = arr(j - 1), arr(j) # 자기보다 작은 데이터를 만나면 그 위치에서 멈춤 else: break print(arr) >>> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  • 시간적 복잡성~이다 O(N^2)오전.
    선택 정렬과 마찬가지로 이중 반복 때문에 O(N^2)입니다.


    삽입으로 정렬현재 목록에 있는 대부분의 데이터가 정렬되어 있으면 매우 빠릅니다.

    최상의 경우 에)의 시간복잡도를 갖는다

※ 일반적으로 퀵소트와 비교 삽입으로 정렬 이 비효율적이지만 “거의 정렬된” 상황에서는 퀵 정렬 알고리즘보다 더 효율적입니다.


빠른 다양성


  • 빠른 종류 기준 데이터(피벗) 조정 및 기준보다 큰 데이터와 작은 데이터 위치 변경 정렬 방법.
    일반적인 상황에서 가장 일반적으로 사용되는 정렬 알고리즘 중 하나이며 병합 정렬과 함께 대부분의 프로그래밍 언어에서 정렬 라이브러리의 기반을 형성합니다.

가장 간단한 퀵 정렬에서는 첫 번째 데이터가 참조 데이터(피벗)로 설정됩니다.

퀵 정렬 알고리즘 코드(Python)

# 퀵 정렬을 사용하여 오름차순 정렬
arr = (7, 5, 9, 0, 3, 1, 6, 2, 4, 8)

def quick_sort(array, start, end):
    if start >= end:    # 원소가 1개인 경우 종료
            return
    pivot = start  # 피벗은 첫 번째 원소
    left = start + 1
    right = end
    while left <= right:
        # 피벗보다 큰 데이터를 찾을 때까지 반복
        while left <= end and array(left) <= array(pivot):
            left = left + 1
        # 피벗보다 작은 데이터를 찾을 때까지 반복
        while right > start and array(right) >= array(pivot):
            right = right -  1
        if left > right:    # 엇갈렸다면 작은 데이터와 피벗을 교체
            array(right), array(pivot) = array(pivot), array(right)
        else:   # 엇갈리지 않았다면 작은 데이터와 큰 데이터를 교체
                array(left), array(right) = array(right), array(left)
    # 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬 수행
    quick_sort(array, start, right - 1)
    quick_sort(array, right + 1, end)

quick_sort(arr, 0, len(arr) - 1)

print(arr)
>>> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

Python을 활용한 Quicksort 알고리즘 코드

# Python의 장점을 살린 퀵 정렬
def quick_sort_better(array):
    # 리스트가 하나 이하의 원소만을 담고 있다면 종료
    if len(array) <= 1:
        return array

    pivot = array(0)    # 피벗은 첫 번째 원소
    tail = array(1:)    # 피벗을 제외한 리스트

    left_side = (x for x in tail if x <= pivot)
    right_side = (x for x in tail if x > pivot)

    # 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬을 수행하고, 전체 리스트를 반환
    return quick_sort_better(left_side) + (pivot) + quick_sort_better(right_side)

print(quick_sort_better(arr))
>>> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
  • 시간 복잡도는 평균적인 경우입니다.

    O(NlogN)그리고 최악의 경우 O(N^2)의 시간복잡도를 갖는다

※ 데이터 개수가 많을수록 빠른 종류 위에서 설명한 선택 정렬 및 삽입 정렬보다 압도적으로 빠릅니다.


그러나 위의 코드와 같이 맨 왼쪽 데이터로 패닝하면 “데이터가 이미 정렬된 상태”일 때 느리게 작동합니다.


(이를 해결하려면 피벗 값을 설정할 때 별도의 로직을 추가해야 합니다.

– 파이썬의 표준 정렬 라이브러리를 사용하여 O(NlogN) 보장)

데이터 수(N)/시간 복잡도 O(N^2) (선택 정렬, 삽입 정렬) O(NlogN)(퀵 정렬), 최악의 경우는 O(N^2)
N=1,000 약 1,000,000 약 10,000
N=1,000,000 약 1,000,000,000,000(1조) 약 20,000,000

위의 표는 데이터의 개수에 따라 얼마나 많은 작업이 필요한지를 보여주고 있으며 정확한 작업 수를 비교한 것은 아닙니다.


병합, 정렬


  • 병합, 정렬정렬되지 않은 모든 데이터를 하나의 단위로 나눈 후 분할된 데이터를 병합하여 정렬하는 방식입니다.


    즉, 데이터를 공유합니다.

    그런 다음 크기를 비교하고 정렬합니다(정복). 마지막으로 병합하십시오.
    병합할 목록이 더 이상 없을 때까지 반복합니다.

병합, 정렬

병합 정렬 알고리즘 코드(Python)

# 병합 정렬을 사용하여 오름차순 정렬
arr = (7, 5, 9, 0, 3, 1, 6, 2, 4, 8)

def merge(left, right):
    sorted_list = ()
    i, j = 0, 0

    while i < len(left) and j < len(right):
        if left(i) <= right(j):
            sorted_list.append(left(i))
            i = i + 1
        else:
            sorted_list.append(right(j))
            j = j + 1

    # 남은 값들을 삽입한다.

while i < len(left): sorted_list.append(left(i)) i = i + 1 while j < len(right): sorted_list.append(right(j)) j = j + 1 return sorted_list def merge_sort(array): if len(array) <= 1: return array mid = len(array) // 2 left = merge_sort(array(:mid)) right = merge_sort(array(mid:)) return merge(left, right) print(merge_sort(arr)) >>> (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)


  • 시간 복잡도는 O(NlogN)오전. (최악의 경우, 평균 및 최상의 경우의 시간 복잡도는 동일함)
    크기가 N인 목록을 반으로 나눕니다.

    한 번 분할 N/2 2개의 조각이 형성되고 나뉩니다.

    N/4 4개를 만듭니다.


    이것을 반복하여 피날레 N/N 덩어리 N개가 나타난다
    즉, 매번 분할 과정이 반으로 줄어들기 때문에 각 분할마다 병합 과정을 수행한다.

    O(NlogN)의 시간복잡도를 갖는다


정렬 카운팅


  • 정렬 카운팅특정 조건에서만 사용할 수 있지만 매우 빠르게 작동하는 정렬 알고리즘입니다.

    오전.
    (여기에는 특별한 조건이 적용됩니다.

    정렬 카운팅 데이터의 크기 범위가 제한적일 때 사용할 수 있으며 정수 형태로 표현할 수 있다.

    )
    일반적으로 가장 큰 데이터와 가장 작은 데이터의 차이가 1,000,000을 넘지 않아야 효과적으로 사용할 수 있습니다.


    정렬 카운팅동일한 값으로 여러 날짜가 나타나는 경우에 유효합니다.

    사용(예: 학생 성적, 차량 속도 데이터)

계수 정렬 알고리즘 코드(Python)

# 계수 정렬을 사용하여 오름차순 정렬
# 단, 리스트의 모든 원소의 값이 0보다 크거나 같다고 가정
arr = (7, 5, 9, 0, 3, 1, 6, 2, 9, 1, 4, 8, 0, 5, 2)
# 모든 범위를 포함하는 리스트 선언 (모든 값은 0으로 초기화)
count = (0) * (max(arr) + 1)    # (0)이 array이 최대값만큼의 개수가 만들어져야 하므로 list index의 특성 +1을 해줌

for i in (arr):
    # 데이터에 해당하는 인덱스의 값 증가
    count(i) = count(i) + 1

# 리스트에 기록된 정렬 정보 확인
for i in range(len(count)):
    for j in range(count(i)):
        # 띄어쓰기를 구분으로 계수 정렬 이용한 오름차순 정렬
        print(i, end = ' ')

>>> 0 0 1 1 2 2 3 4 5 5 6 7 8 9 9
  • 시간복잡도는 데이터의 개수가 N이고 데이터의 최대값(양수)이 K일 때 최악의 경우이다.

    오(엔+케이) 보장하다

※ 계수 정렬은 때때로 심각한 비효율을 초래할 수 있습니다.

예를 들어 날짜가 0과 999,999 두 개뿐이라 하더라도 목록의 크기는 100만 개로 설정해야 합니다.

그것은 매우 비효율적입니다.


코딩 테스트의 정렬 알고리즘

  1. 정렬 라이브러리로 해결되는 문제: 표준 정렬 라이브러리를 사용하여 정렬 기술을 아는 것은 단순히 문제입니다.

  2. 정렬 알고리즘의 원리에 대한 질문: 문제를 풀기 위해서는 Selection Sort, Insertion Sort, Quick Sort, Merge Sort, Counting Sort의 원리를 알아야 합니다.

  3. 더 빠른 정렬이 필요한 문제: 퀵정렬 기반의 정렬 기법으로는 해결할 수 없지만, 카운트 정렬과 같은 다른 정렬 알고리즘을 사용하거나 문제에서 기존 알고리즘을 구조적으로 개선하여 해결할 수 있습니다.