Cute Running Puppy

알고리즘

알고리즘(5)

jwjin 2025. 1. 22. 16:24
728x90

- 나누어 풀어보기

  • 선택 정렬(Selection sort) : 가장 작은 숫자가 적힌 카드를 찾아 맨 왼쪽에 놓고, 나머지 카드 중에서 가장 작은 숫자를 찾아 맨 왼쪽 카드 다음에 놓고, 이를 반복하여 모든 카드를 정렬한다. 
  • 버블 정렬(Bubble sort) : 첫 번째 숫자와 두 번째 숫자를, 두 번째 숫자와 세 번째 숫자를, 세 번째 숫자와 네 번째 숫자를 ,... 이런 식으로 (마지막-1)번째 자료와 마지막 자료를 비교하여 교환하면서 자료를 정렬한다.
  • 힙 정렬(Heap sort) : 정렬해야 할 n개의 요소들로 최대 힙(완전 이진 트리 형태)을 만들고 한 번에 하나씩 요소를 힙에서 꺼내서 배열의 뒤부터 저장한다. 삭제되는 요소들(최댓값부터 삭제)은 값이 감소되는 순서로 정렬되게 된다.

 

  • 퀵 정렬(Quick sort) : 맨 왼쪽 숫자를 피벗으로 삼는다. 피벗과 각 숫자를 비교하여 피벗보다 작거나 같은 숫자들을 왼쪽으로 큰 숫자들은 오른쪽으로 나누고, 피벗을 그 사이로 옮긴다. 피벗보다 작거나 같은 부분을 동일한 방법으로 정렬한다. 피벗보다 큰 부분을 동일한 방법으로 정렬한다.
# 퀵 정렬 함수 정의
def quick_sort(arr):
    # 재귀 종료 조건: 배열의 길이가 1 이하이면 이미 정렬된 상태
    if len(arr) <= 1:
        return arr
    
    # 피벗 선택 (여기서는 리스트의 첫 번째 요소를 피벗으로 선택)
    pivot = arr[0]
    
    # 피벗을 기준으로 작은 값과 큰 값으로 나누기
    less = [x for x in arr[1:] if x <= pivot]  # 피벗 이하
    greater = [x for x in arr[1:] if x > pivot]  # 피벗 초과

    # 재귀적으로 정렬 후 병합
    return quick_sort(less) + [pivot] + quick_sort(greater)

# 테스트용 리스트
arr = [7, 2, 1, 6, 8, 5, 3, 4]

# 퀵 정렬 실행
sorted_arr = quick_sort(arr)
print(sorted_arr)

[1, 2, 3, 4, 5, 6, 7, 8] => 코드 실행 결과

 

- 합병 정렬(Merge Sort)

합병 정렬은 크기가 n인 입력을 n/2크기 2개로 분할하고, 각각에 대해 같은 방법으로 합병 정렬을 수행한 후, 2개의 각각 정렬된 부분을 합병

합병(Merge) 2개의 각각 정렬된 리스트를 합치어 정렬하는 것

분할 정복(Divide-and-Conquer) 알고리즘 : 입력을 분할하여 분할된 입력 각각에 대한 문제(부분 문제)를 같은 방법으로 해결한 후 취합하여 문제를 해결하는 알고리즘

  1. 현재 입력 크기가 1이면 return
  2. 현재 입력을 으로 나눈다.
  3. 앞부분을 동일한 방법으로 정렬
  4. 뒷부분을 동일한 방법으로 정렬
  5. 정렬된 앞부분과 뒷부분을 합병
# 합병 정렬 함수 정의
def merge_sort(arr):
    # 재귀 종료 조건: 배열의 길이가 1 이하이면 이미 정렬된 상태
    if len(arr) <= 1:
        return arr

    # 배열을 두 부분으로 나누기
    mid = len(arr) // 2
    left = arr[:mid]
    right = arr[mid:]

    # 재귀적으로 두 부분을 정렬
    left_sorted = merge_sort(left)
    right_sorted = merge_sort(right)

    # 두 정렬된 부분을 병합
    return merge(left_sorted, right_sorted)

# 두 정렬된 리스트를 병합하는 함수
def merge(left, right):
    sorted_list = []
    i = j = 0

    # 두 리스트를 비교하며 정렬된 결과 생성
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            sorted_list.append(left[i])
            i += 1
        else:
            sorted_list.append(right[j])
            j += 1

    # 남은 요소를 추가
    sorted_list.extend(left[i:])
    sorted_list.extend(right[j:])
    return sorted_list

# 테스트용 리스트
arr = [7, 2, 1, 6, 8, 5, 3, 4]

# 합병 정렬 실행
sorted_arr = merge_sort(arr)
print(sorted_arr)

[1, 2, 3, 4, 5, 6, 7, 8] => 코드 실행 결과

- 어떤 입력에 대해서도 T(n) = O(nlogn) 시간 보장

- [단점] => 합병을 위해 입력 크기의 보조 메모리가 필요

 

- K 번째 작은 수 찾기

  1. 피벗을 랜덤하게 선택
  2. 피벗과 각 숫자를 비교하여 피벗보다 작은 숫자들을 왼쪽으로, 큰 숫자들을 오른쪽으로 나누고, 피벗을 그 사이에 둠
  3. K번째 작은 숫자가 피벗이면 탐색 성공
  4. K번째 작은 숫자가 피벗보다 작은 부분에 있으면, 작은 부분에서 동일한 방법으로 탐색
  5. 피벗보다 큰 부분에 있으면, K를 수정하여 큰 부분에서 동일한 방법으로 탐색

평균 경우 수행 시간 : O(n)

728x90

'알고리즘' 카테고리의 다른 글

알고리즘(7)  (0) 2025.01.24
알고리즘(6)  (0) 2025.01.23
알고리즘(4)  (0) 2025.01.22
알고리즘(3)  (0) 2024.10.13
알고리즘(2)  (0) 2024.10.06