퀵정렬과 병합정렬(Quick Sort and Merge Sort)

2023. 5. 15. 17:12·Computer Science
728x90

퀵정렬과 병합정렬(Quick Sort and Merge Sort)

🔍 자세히보기 : 퀵정렬(퀵소트)과 병합정렬은 많이 활용되고 비교되는 것이다.

  • 퀵 정렬의 시간복잡도는 최악의 경우 O(n²)이며 평균의 경우 O(nlogn)이다.
    • 최악: 피벗에 의한 원소들의 부분집합이 1개와 n-1개로 분할되는 경우가 반복되는 경우
  • 병합 정렬은 성능의 저하 없이 항상 O(nlogn)이다.
  • 퀵 정렬은 불안전 정렬이고, 병합 정렬은 안정 정렬이다.
    • 동일한 값에 대해 기존의 순서가 유지되는 것이 안정 정렬이다.
  • 퀵 정렬이 사용 되는 이유
    • 퀵 정렬은 피벗이라는 별도의 노드를 지정해두고 재귀적으로 수행을 하기 때문에 통상적으로 병합정렬보다 더 빠르다.
    • 병합 정렬은 전체 데이터를 기준으로 처음과 끝을 계속해서 탐색하기 때문에 퀵소트에 비해 느리다.
    • 한정적인 범위에서 데이터를 정렬하기 때문에 캐시를 덜 활용하고, 하드웨어적으로 효율적이다.
  • 병합 정렬이 활용되는 이유
    • 퀵 정렬보다 빠르지는 않지만, 안정(stable) 정렬이기 때문에 데이터가 중복되었더라도 영향을 덜 받기 때문이다.
    • 퀵 정렬은 성능이 우수함에도 성능 편차가 크고, 피벗(노드) 설정 등의 다루기 어려운 점이 존재하기 때문에 실무에서는 활용되기가 어렵다.

[Quick sort] vs [Merge sort]

퀵정렬(Quick Sort)

  1. 퀵소트의 최선의 경우

2. 퀵소트의 최악의 경우

  • 퀵정렬은 불안정 정렬의 대표적인 경우로서, 노드의 값이 중복되는 경우에는 계속해서 swap(교환)을 시도한다.
  • 퀵정렬은 최악의 경우에 첫번째 노드를 피벗으로 설정하고 불균형하게 분할정복을 시도하여 성능이 안 좋아진다.
    • 속도는 알고리즘을 처리하고 결과를 도출하는 속도(주로 소프트웨어에 영향을 주고 받음)
    • 성능은 메모리에 영향을 주는 정도(주로 하드웨어에 영향을 주고 받음)
# 퀵소트 파이썬 코드 case - 1 : 전체코드
def quick_sort(node, first, last):
    def partition(first,last):
        pivot = node[last]
        left = first
        # print(pivot, first,last)    # 확인용

        for right in range(first, last):
            if node[right] < pivot:
                node[left], node[right] = node[right], node[left]
                left += 1
        node[left], node[last] = node[last], node[left]

        return left

    # 첫번째 노드가 마지막 노드보다 작은 경우, 재귀진행
    if first < last:
        pivot = partition(first, last)
        quick_sort(node, first, pivot - 1)
        quick_sort(node, pivot + 1, last)

node = [54, 26, 93, 17, 77, 31, 44, 55, 20]
quick_sort(node, 0, 8)
print(node)
# 퀵소트 파이썬 코드 case - 2 : 전체코드
def quick_sort(ARRAY):
    ARRAY_LENGTH = len(ARRAY)
    if ARRAY_LENGTH <= 1:
        return ARRAY
    else:
        PIVOT = ARRAY[0]
        GREATER = [element for element in ARRAY[1:] if element > PIVOT]
        LESSER = [element for element in ARRAY[1:] if element <= PIVOT]
        return quick_sort(LESSER) + [PIVOT] + quick_sort(GREATER)

ARRAY = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print(quick_sort(ARRAY))

병합정렬(Merge Sort)

  • 병합정렬 알고리즘을 구현하는 접근 방식은 두 부분으로 나뉩니다.
  • 첫 번째 부분은 분할정복 방법의 분할 구성 요소를 수행합니다.
    • 첫 번째 부분에서의 주요 코드구현은 초기 리스트를 더 작은 구성 요소로 나눕니다.
    • 초기 리스트 분할은 분리된 각 구성 요소를 더 이상 분할할 수 없는 경우에만 중지됩니다.
def test_recur_divide(list):
    # 1. 리스트의 길이를 저장합니다.
    list_length = len(list)

    # 2. 리스트의 길이가 1이 될때까지, 즉 분할할 수 없을 때까지 아래 로직을 반복 수행합니다.
    if list_length == 1:
        return list

    # 3. 리스트의 중간 지점을 식별하고 리스트를 left_partition과 right_partition으로 분할합니다.
    mid_point = list_length // 2

    # 4. 모든 파티션이 분할할 수 없는 작은 구성 요소로 분할되도록 하려면,
    # 아래처럼 test_recur_divide 함수가 재귀적으로 호출됩니다.
    # test_recur_divide 함수 안에 매개변수는 두가지로 나뉘어서 전달됩니다.

    # left_partition은 리스트의 0번째 인덱스부터 중간지점 인덱스까지의 값을 전달받고,
    # right_partition은 리스트의 (중간지점+1)번째 인덱스부터 마지막지점 인덱스까지의 값을 전달받습니다.
    left_partition = test_recur_divide(list[:mid_point])
    right_partition = test_recur_divide(list[mid_point:])

    # 5. test_recur_divide 함수는 정렬된 왼쪽과 오른쪽 파티션으로 구성된 리스트를 반환합니다.
    return test_sort_combine(left_partition, right_partition)
  • 병합 정렬 알고리즘의 두 번째 부분은 전달받은 리스트 내의 요소를 지정된 순서로 정렬하는 작업입니다.
  • 아래 예시에서 보여지는 알고리즘의 정렬 순서는 오름차순으로 진행됩니다.

# 6. 두 개의 리스트를 받아 두 리스트 내의 요소로 정렬된 리스트를 반환합니다.
def test_sort_combine(left, right):
    # 7. 정렬된 결과값으로 채워질 비어있는 리스트변수 output을 초기화합니다.
    # 리스트를 반복할 때 사용되는 두 개의 변수 i와 j를 초기화합니다.
    output = []
    i = j = 0

    # 8. 두 변수 i와 j가 왼쪽과 오른쪽 리스트의 길이보다 작으면 while 루프를 실행합니다.
    while i < len(left) and j < len(right):
        # 9. 각 반복 동안 두 리스트의 모든 위치에 있는 요소를 비교합니다.
        if left[i] < right[j]:
            # 오름차순으로 정렬하기위해 output변수에는 더 작은 값으로 채워집니다.
            output.append(left[i])
            # 10. 변수 i값을 +1 함으로써 오른쪽으로 한칸 이동시킵니다.
            i += 1
        else:
            output.append(right[j])
            j += 1
    # 11. 남아있는 리스트 요소에서 현재 i, j 값을 기준으로 각각 리스트의 마지막지점 인덱스까지 값을 넣고 결과값을 반환합니다.
    output.extend(left[i:])
    output.extend(right[j:])

    return output
def test_result():
    unsorted_list = [2, 6, 8, 2, 3, 9, 1, 4, 9]
    print(unsorted_list)
    sorted_list = test_recur_divide(unsorted_list)
    print(sorted_list)

test_result()

• sorted_list 변수는 test_recur_divide 함수의 결과를 반환합니다.

728x90
반응형

'Computer Science' 카테고리의 다른 글

Queue(큐) 와 Stack(스택) using Python  (0) 2023.08.11
그래프(Graph) 란?  (0) 2023.05.15
Divide and Conquer(분할 정복)  (0) 2023.05.15
Algorithm Intermediate  (0) 2023.05.15
OOP(Object-Oriented Programming)란?  (0) 2023.05.15
'Computer Science' 카테고리의 다른 글
  • Queue(큐) 와 Stack(스택) using Python
  • 그래프(Graph) 란?
  • Divide and Conquer(분할 정복)
  • Algorithm Intermediate
Balang
Balang
음악 전공생의 개발일지
  • Balang
    Balang
    Balang
  • 전체
    오늘
    어제
  • 반응형
    • All Post (131) N
      • python (36) N
        • selenium (4)
        • algorithm (3)
        • Django (6) N
        • Pandas | Numpy (19)
      • SQL (9)
      • Data Engineer (29)
      • Data Scientist (3)
      • Data Analysis (3)
      • Computer Science (35)
      • Why? (15)
      • 마음가짐 (1)
  • 인기 글

  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.3
Balang
퀵정렬과 병합정렬(Quick Sort and Merge Sort)
상단으로

티스토리툴바