늦은 프로그래밍 이야기

정렬 본문

내일배움캠프/자료구조 알고리즘

정렬

한정규 2022. 11. 10. 22:11

정렬

버블정렬

특징

 - 리스트의 두가지 자료를 비교하여 둘중 작은 것을 왼쪽에 둔다.

 - 한 바퀴를 실행하면 가장 큰 데이터가 가장 오른쪽으로 가게 된다.

 - 두 바퀴를 실행하면 두번째로 큰 데이터가 오른쪽에서 두번째로 가게 된다.

 - 모든 바퀴 수를 실행하면 데이터가 순서에 맞게 정렬되게 된다.

 - 따라서, 오른쪽부터 정렬이 된다.

출처 : https://www.google.com/url?sa=i&url=https%3A%2F%2Fgfycat.com%2Fko%2Fexaltedinconsequentialdwarfrabbit&psig=AOvVaw3VaULnsbKIQS9rzYXoze1R&ust=1602902999761000&source=images&cd=vfe&ved=0CAIQjRxqFwoTCKCE3JKNuOwCFQAAAAAdAAAAABA9

구현

input = [4, 6, 2, 9, 1]

def bubble_sort(array):
    n = len(array)
    for i in range(n - 1):             # 이중반복문을 통해 아래와 같이 배열의 인덱스를 반복한다.
        for j in range(n - i - 1):     # 맨마지막 인덱스를 제외하고 반복, 마지막 인덱스를 하나씩 줄여감.
            if array[j] > array[j + 1]: # 인덱스 j와 오른쪽 인덱스인 j+1을 비교 왼쪽이 크다면,
                array[j], array[j + 1] = array[j + 1], array[j] # 오른쪽으로 옮겨준다.
    return
    
bubble_sort(input)
print(input)

 

 - a, b = b, a 로 변수의 위치를 변경할 수 있다.

 - 이중 반복문 구조 (n = 5)

i j
0 5 - 0 - 1 = 4, 따라서 0, 1, 2, 3
1 5 - 1 - 1 = 3, 따라서 0, 1, 2
2 5 - 2 - 1 = 2, 따라서 0, 1
3 5 - 3 - 1 = 1, 따라서 0

 - 이중 반복문을 사용하므로 O(N^2)의 시간복잡도를 가진다.


선택 정렬

특징

 - 선택해서 정렬한다.

 - 배열을 탐색한 후 가장 작은 데이터를 맨 왼쪽의 데이터와 자리를 바꾼다.

 - 맞춘 데이터를 제외하고 다시 배열을 탐색 후 가장 작은 데이터를 왼쪽 두번째 데이터와 자리를 바꾼다.

 - 따라서, 왼쪽부터 정렬이 된다.

출처 : https://www.google.com/url?sa=i&url=https%3A%2F%2Fko.wikipedia.org%2Fwiki%2F%25EC%2584%25A0%25ED%2583%259D_%25EC%25A0%2595%25EB%25A0%25AC&psig=AOvVaw36PdJGACq2UZUa3djaaffs&ust=1602902740553000&source=images&cd=vfe&ved=0CAIQjRxqFwoTCMDgm5aMuOwCFQAAAAAdAAAAABAD

구현

input = [4, 6, 2, 9, 1]

def selection_sort(array):
    n = len(array)

    for i in range(n - 1):       # 배열의 모든 인덱스를 반복
        min_index = i            # 왼쪽의 인덱스가 변수에 담긴다.
        for j in range(n - i):   # 아래와 같이 반복
            if array[i + j] < array[min_index]: # 반복된 배열의 원소를 하나하나 비교.
                min_index = i + j               # i 위치에 가장 작은 수가 온다.
        array[i], array[min_index] = array[min_index], array[i]

    return
    
selection_sort(input)
print(input)

 - 이중 반복문 구조 (n = 5)

i j i + j
0 5 - 0 = 5, 따라서 0, 1, 2, 3, 4 0, 1, 2, 3, 4
1 5 - 1 = 4, 따라서 0, 1, 2, 3 1, 2, 3, 4
2 5 - 2 = 3, 따라서 0, 1, 2 2, 3, 4
3 5 - 3 = 2, 따라서 0, 1 3, 4
4 5 - 4 = 1, 따라서 0 4

 - 이중 반복문을 사용하므로 O(N^2)의 시간복잡도.


삽입 정렬

특징

 - 올바른 위치에 삽입한다.

 - 왼쪽부터 인덱스 하나씩 늘려가며 정렬한다.

 - “기존 왼쪽에 있는 데이터”와 “오른쪽의 데이터”를 비교하여 왼쪽으로 정렬한다.

 - 0번 인덱스의 데이터는 정렬되어 있다.

 - 1번 인덱스를 0번 인덱스와 비교하여 0, 1번을 정렬한다.

 - 2번 인덱스를 1, 0번 인덱스와 비교하여 0, 1, 2번을 정렬한다.

 - 3번 인덱스를 2, 1, 0번 인덱스와 비교하여 0, 1, 2, 3번을 정렬한다.

 - 끝까지 반복한다.

 - 비교할때는 버블정렬의 방식을 사용한다. (왼쪽으로)

 - 따라서, 왼쪽부터 정렬이 된다.

 

구현

input = [4, 6, 2, 9, 1]

def insertion_sort(array):
    n = len(array)
    for i in range(1, n):     # 배열의 인덱스 1부터 n-1까지 반복
        for j in range(i):    # i가 1인 경우, j는 0
            if array[i - j - 1] > array[i - j]:  # i가 1인 경우, array[0]과 array[1] 중 왼쪽이 크면,
                array[i - j - 1], array[i - j] = array[i - j], array[i - j - 1] # 위치 변경
            else:
                break  # 왼쪽 데이터가 오른쪽 데이터보다 크지 않을 경우 멈추고 첫번째 반복문으로 돌아간다.
    return
    
insertion_sort(input)
print(input)

 - 이중 반복문 구조 (n = 5)

i j i - j
1 0 1
2 0, 1 2, 1
3 0, 1, 2 3, 2, 1
4 0, 1, 2, 3 4, 3, 2, 1

 - 이중 반복문을 사용하지만, break문을 사용하므로 최선의 경우에는 N 복잡도가 나올  있다.


병합 정렬

특징

 - 병합 : 배열의 앞부분, 뒷부분 두그룹으로 나누어 각각 정렬 후 합치며 새로운 배열에 정렬.

 - 분할 정복의 개념 적용

 - 분할 정복 : 문제를 작은 두개의 문제로 분리, 각각을 해결, 결과를 모아서 문제를 해결.

 - 배열을 두개로 끝까지 분리하면 길이가 1인 배열이 된다.

 - 길이가 1 배열을 2개씩 병합하며 새로운 배열에 정렬한다.

 

구현

 - 합치기

array_a = [1, 2, 3, 5]
array_b = [4, 6, 7, 8]

def merge(array1, array2):
    array_c = []                # 새로운 배열을 생성한다.
    array1_index = 0            # 배열1의 인덱스 변수를 설정
    array2_index = 0            # 배열2의 인덱스 변수를 설정
    while array1_index < len(array1) and array2_index < len(array2):  # 배열1과 배열2의 모든 인덱스의 데이터를 반복한다.
        if array1[array1_index] < array2[array2_index]:  # 배열1의 데이터가 작은 경우
            array_c.append(array1[array1_index])         # 새로운 배열에 배열1의 데이터를 담는다.
            array1_index += 1                            # 배열1의 인덱스를 다음으로 넘긴다.
        else:                                            # 배열2의 데이터가 작은 경우
            array_c.append(array2[array2_index])         # 새로운 배열에 배열2의 데이터를 담는다.
            array2_index += 1                            # 배열2의 인덱스를 다음으로 넘긴다.

    if array1_index == len(array1):                      # 배열1의 인덱스가 끝까지 간 경우
        while array2_index < len(array2):                # 배열2의 남은 인덱스의 데이터를 반복한다.
            array_c.append(array2[array2_index])         # 새로운 배열에 배열2의 데이터를 담는다.
            array2_index += 1

    if array2_index == len(array2):                      # 배열2의 인덱스가 끝까지 간 경우
        while array1_index < len(array1):                # 배열1의 남은 인덱스의 데이터를 반복한다.
            array_c.append(array2[array1_index])         # 새로운 배열에 배열1의 데이터를 담는다.
            array1_index += 1

    return array_c
    
print(merge(array_a, array_b))

 

 - 분할

array = [5, 3, 2, 1, 6, 8, 7, 4]

def merge_sort(array):
    if len(array) <= 1:        # 탈출조건으로 배열의 길이가 1보다 작거나 같을때
        return array           # 멈춤.
    mid = len(array) // 2                  # 배열의 중간 인덱스를 변수에 담는다.
    left_array = merge_sort(array[:mid])   # 배열의 처음부터 mid 인덱스까지 슬라이싱 하여 왼쪽 배열을 담는다.
    right_array = merge_sort(array[mid:])  # 배열의 mid 인덱스부터 끝까지 슬라이싱 하여 오른쪽 배열을 담는다.
                                           # 재귀함수를 사용하여 슬라이싱한 배열을 반복적으로 슬라이싱 한다.
    return merge(left_array, right_array)  # 합치기 함수를 실행하여 왼쪽과 오른쪽 배열을 순서에 맞게 정렬한다.
    

def merge(array1, array2):

print(merge_sort(array))

 - 병합 정렬의 시간복잡도는 O(NlogN)이다.


'내일배움캠프 > 자료구조 알고리즘' 카테고리의 다른 글

해쉬  (0) 2022.11.14
스택, 큐  (0) 2022.11.11
Array, Linked List  (0) 2022.11.10
최대값 찾기, 최빈값 찾기  (0) 2022.11.09
시간복잡도, 공간복잡도  (0) 2022.11.09
Comments