TIL/Python

[TIL] 퀵 정렬 Quick Sort 추가 공부

아람2 2024. 9. 9. 20:41
반응형

09/10 TUE 퀴즈를 대비한 퀵 정렬 추가 공부 

 

퀵 정렬 Quick Sort

분할 정복 알고리즘의 대표 예시 

 

Pivot 값을 중심으로 작은 값/ 큰 값을 계속 나누기 때문에 재귀 함수임

 

방식

1) 르모토 - 월 같은 걸 추가한다 (이건 나중에 추가 공부하고 해주신대)

2) 호어 Hoare - Pivot 으로 판단한다 << DO IT 책에 있는 내용 

(Left + Right) // 2 를 Pivot 으로 설정하고, 

Pivot 기준으로 왼쪽은 작은 값, 오른쪽 큰 값 비교하여 서로 반대인 경우 Swap 

첫번째 비교가 완료되면 Pivot 기준 왼쪽/ 오른쪽으로 또 쪼개서 Pivot 만들어

정렬을 완료한다 

+ Pivot 을 arr[0] 에 줘도 되고, 어디에 주던 본인 마음임

+ while 문 안에서 Pivot 의 위치는 바뀔 수 있지만 Pivot 자체는 바뀌지 않음 

 

* Mutable Sequence

- Mutable ; 변경 가능한 (<-> Immutable 변경 불가한)

- Sequence ; 요소를 수정 가능한 자료형 (List, Tuple, Range, String 등)

 

Quick Sort 를 Python 으로 구현해 보기! 

1번 방법 DO IT 알고리즘입문 CH06 

 

준비 과정 

# Quick Sort - 분할 정복 알고리즘의 대표적인 예시
# (left+right)//2 로 Pivot 을 설정하고
# pl+1, pr-1 을 Pivot 과 비교하여 정렬한다

# QuickSort 함수에 array 와 left, right 설정
# pivot 을 설정하고, left 부터 pivot 까지/ right 부터 Pivot 까지 비교한다

# pl 이 x 보다 작은 경우 pl+1 하며 찾고 pr 이 x 보다 큰 경우 pr-1 하며 찾다가 멈추면 pl 과 pr 을 변경해 준다
# Pivot 을 기준으로 정렬이 완료되면 왼쪽/ 오른쪽 나눠서 또 진행
# 만약 Pivot 의 위치가 변경될 경우 Pivot 의 위치는 바뀌지만 Pivot 은 그대로

# MutableSequence 변경 가능한 시퀀스 (요소 수정 가능)
# Sequence ; List, Tuple, Range, String, etc

 

Qsort 함수 

def qSort(a: MutableSequence, left: int, right: int) -> None:
    pl = left # 제일 왼쪽의 요소 
    pr = right # 제일 오른쪽의 요소 
    x = a[(left+right)//2] # Pivot 설정 

    # pl 이 pr 보다 작을 때 while 문이 돌아간다 
    while pl <= pr:
        # pl 이 가리키는 값이 Pivot 보다 작을 때 pl 을 뒤로 한 칸
        while a[pl] < x: pl += 1
        # pr 이 가리키는 값이 Pivot 보다 클 때 pr 을 앞으로 한 칸
        while a[pr] > x: pr -= 1
        # pl 과 pr 의 움직임이 멈추고 pl 이 pr 보다 앞에 있을 때
        # pl 이 가리키는 값과 pr 이 가리키는 값을 swap 하고
        # pl 뒤로 한 칸, pr 앞으로 한 칸 옮겨준다 
        if pl <= pr:
            a[pl], a[pr] = a[pr], a[pl]
            pl += 1
            pr -= 1

    # pl 이 pr 보다 작은 경우 다시 while 문을 돈다
    # pl 이 pr 보다 큰 경우 while 문을 종료하고 
    # left < pr/ pl < right 의 조건을 충족할 때
    # 기존 Pivot 기준으로 앞부분과 뒷부분으로 나눠 다시 qSort 진행 
    if left < pr: qSort(a, left, pr)
    if pl < right: qSort(a, pl, right)

 

Quick_Sort 함수

# MutableSequence 는 리스트와 같이 변경 가능한 시퀀스를 나타내는 타입 힌트 
# qSort 라는 재귀적 함수를 호출하여 리스트 a 를 정렬
# 리스트 a, 정렬을 시작할 인덱스 0, 끝 인덱스 len(a)-1 를 인자로 전달 

def Quick_Sort(a: MutableSequence) -> None:
    qSort(a, 0, len(a)-1)

 

Main 

if __name__ == '__main__':
    print(" 배열 입력 받기 ")
    num = int(input())

    x = [None] * num # 배열 개수 입력 받고 None 으로 초기화하기 

    for i in range(num): # 배열 하나씩 입력 받기
        x[i] = int(input(f'[x{i}]: '))

    Quick_Sort(x) # Quick Sort 진행 

    print(" 정렬 완료 ")
    for i in range(num): # 정렬 완료 후 차례로 Print 
        print(f'[x{i}]: = {x[i]}')

 

 

 전체 코드

from typing import MutableSequence

def qSort(a: MutableSequence, left: int, right: int) -> None:
    pl = left # 제일 왼쪽의 요소 
    pr = right # 제일 오른쪽의 요소 
    x = a[(left+right)//2] # Pivot 설정 

    # pl 이 pr 보다 작을 때 while 문이 돌아간다 
    while pl <= pr:
        # pl 이 가리키는 값이 Pivot 보다 작을 때 pl 을 뒤로 한 칸
        while a[pl] < x: pl += 1
        # pr 이 가리키는 값이 Pivot 보다 클 때 pr 을 뒤로 한 칸
        while a[pr] > x: pr -= 1
        # pl 과 pr 의 움직임이 멈추고 pl 이 pr 보다 앞에 있을 때
        # pl 이 가리키는 값과 pr 이 가리키는 값을 swap 하고
        # pl 뒤로 한 칸, pr 앞으로 한 칸 옮겨준다 
        if pl <= pr:
            a[pl], a[pr] = a[pr], a[pl]
            pl += 1
            pr -= 1

    # pl 이 pr 보다 작은 경우 다시 while 문을 돈다
    # pl 이 pr 보다 큰 경우 while 문을 종료하고 
    # left < pr/ pl < right 의 조건을 충족할 때
    # 기존 Pivot 기준으로 앞부분과 뒷부분으로 나눠 다시 qSort 진행 
    if left < pr: qSort(a, left, pr)
    if pl < right: qSort(a, pl, right)

def Quick_Sort(a: MutableSequence) -> None:
    qSort(a, 0, len(a)-1)

if __name__ == '__main__':
    print(" 배열 입력 받기 ")
    num = int(input())

    x = [None] * num # 배열 개수 입력 받고 None 으로 초기화하기 

    for i in range(num): # 배열 하나씩 엔터로 입력 받기
        x[i] = int(input(f'[x{i}]: '))

    Quick_Sort(x) # Quick Sort 진행 

    print(" 정렬 완료 ")
    for i in range(num): # 정렬 완료 후 차례로 Print 
        print(f'[x{i}]: = {x[i]}')

 

정렬 결과

 배열 입력 받기 
5
[x0]: 3
[x1]: 2
[x2]: 4
[x3]: 5
[x4]: 1
 정렬 완료 
[x0]: = 1
[x1]: = 2
[x2]: = 3
[x3]: = 4
[x4]: = 5

 

2번 방법은 1번을 함수 하나만 사용하기 + 한 줄로 입출력

from typing import MutableSequence

def qSort(a: MutableSequence, left: int, right: int) -> None:
    if left >= right: # 재귀 종료 조건 
        return
    
    pl = left
    pr = right
    x = a[(left+right)//2] # Pivot 설정 

    while pl <= pr:
        while a[pl] < x: pl += 1
        while a[pr] > x: pr -= 1
        if pl <= pr:
            a[pl], a[pr] = a[pr], a[pl] # pl pr Swap
            pl += 1
            pr -= 1
    if left < pr: qSort(a, left, pr) # 왼쪽 부분 정렬 
    if pl < right: qSort(a, pl, right) # 오른쪽 부분 정렬 

if __name__ == '__main__':
    num = int(input()) # 입력할 숫자 

    arr = list(map(int, input().split())) # 숫자 배열 한 줄로 입력 받기 

    qSort(arr, 0, num-1) # Quick Sort 실행 

    print("정렬 완료", ' '.join(map(str, arr))) # 숫자 배열 한 줄로 출력

정렬 결과

4
3 2 4 6
정렬 완료 2 3 4 6

3번 방법 파이썬 컴프리헨션과 배열 이용하기1

qSort 부분 

def qSort(a: MutableSequence) -> None:
    # len(a) 가 1 이하인 경우 정렬 완료로 간주 
    if len(a) <= 1:
        return a
    # Pivot 을 맨 앞으로 선언 
    pivot = a[0]

    # Pivot 을 제외한 a 에서 pivot 와 비교하여 작은 수는 less 에 넣기
    less_than_pivot = [x for x in a[1:] if x <= pivot]
    # Pivot 을 제외한 a 에서 pivot 과 비교하여 큰 수는 greater 에 넣기 
    greater_than_pivot = [x for x in a[1:] if x > pivot]

    # 정렬한 less 와 greater, pivot 을 하나로 묶어서 return 
    # less 와 greater 가 각각 정렬이 끝날 때까지 재귀 실행 
    return qSort(less_than_pivot) + [pivot] + qSort(greater_than_pivot)

 

Main

if __name__ == '__main__':
    # 공백으로 구분하여 문자열 입력 받기 
    num_list = list(map(int, input().split()))

    sorted_list = qSort(num_list)
    print(f" 정렬 완료 : {sorted_list}")

 

전체 코드

# Quick Search

from typing import MutableSequence

def qSort(a: MutableSequence) -> None:
    # len(a) 가 1 이하인 경우 정렬 완료로 간주 
    if len(a) <= 1:
        return a
    # Pivot 을 맨 앞으로 선언 
    pivot = a[0]

    # Pivot 을 제외한 a 에서 pivot 와 비교하여 작은 수는 less 에 넣기
    less_than_pivot = [x for x in a[1:] if x <= pivot]
    # Pivot 을 제외한 a 에서 pivot 과 비교하여 큰 수는 greater 에 넣기 
    greater_than_pivot = [x for x in a[1:] if x > pivot]

    # 정렬한 less 와 greater, pivot 을 하나로 묶어서 return 
    # less 와 greater 가 각각 정렬이 끝날 때까지 재귀 실행 
    return qSort(less_than_pivot) + [pivot] + qSort(greater_than_pivot)

if __name__ == '__main__':
    # 공백으로 구분하여 문자열 입력 받기 
    num_list = list(map(int, input().split()))

    sorted_list = qSort(num_list)
    print(f" 정렬 완료 : {sorted_list}")

 

 

4번 방법 파이썬 컴프리헨션과 배열 이용하기2

def quick_sort(arr):
    if len(arr) <= 1:  # 배열의 길이가 1 이하인 경우 종료
        return arr
    pivot = arr[len(arr) // 2]  # 피벗 선택 (중간 값)
    left = [x for x in arr if x < pivot]  # 피벗보다 작은 값들
    middle = [x for x in arr if x == pivot]  # 피벗과 같은 값들
    right = [x for x in arr if x > pivot]  # 피벗보다 큰 값들
    return quick_sort(left) + middle + quick_sort(right)  # 재귀적으로 호출하여 병합

 

반응형