ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [이코테 # 정렬1] 정렬 소스코드, 선택/삽입/퀵/계수 정렬, sorted()와 sort()의 차이
    Programming 기초/Coding Test 2023. 6. 9. 02:21

    * 선택 정렬

    array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]
    
    for i in range(len(array)):
        min_index = i # 가장 작은 원소의 인덱스
        for j in range(i + 1, len(array)):
            if array[min_index] > array[j]:
                min_index = j
        array[i], array[min_index] = array[min_index], array[i] # 스와프
    
    print(array)

     

    * 삽입 정렬

    • 시간 복잡도: 최악의 경우는O(n^2)이지만 보통 어느정도 정렬된 상태에서 삽입 정렬을 쓰기 때문에 최선의 경우에는 O(n)으로 퀵 정렬 알고리즘보다 더 강력하다.
    array = [7, 5, 9, 0, 3, 1, 6, 2, 4, 8]
    
    for i in range(1, len(array)):
        for j in range(i, 0, -1): # 인덱스 i부터 1까지 1씩 감소하며 반복하는 문법
            if array[j] < array[j - 1]: # 한 칸씩 왼쪽으로 이동
                array[j], array[j - 1] = array[j - 1], array[j]
            else: # 자기보다 작은 데이터를 만나면 그 위치에서 멈춤
                break
    
    print(array)

     

    * 퀵 정렬

    • 시간 복잡도 : O(NlogN) (밑이 2다.) 최악의 경우 O(n^2)이다.
    • 이전 포스팅에서와 아래 퀵 정렬(Hoare Partition 방식)의 정렬 방식이 약간 다르다(https://operationcoding.tistory.com/60)
    # 퀵 정렬 정석 버전
    array = [5, 7, 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 += 1
            # 피벗보다 작은 데이터를 찾을 때까지 반복
            while(right > start and array[right] >= array[pivot]):
                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(array, 0, len(array) - 1)
    print(array)
    # 퀵 정렬 짧은 버전 - 정석버전보다 시간효율이 약간 떨어진다.
    array = [5, 7, 9, 0, 3, 1, 6, 2, 4, 8]
    
    def quick_sort(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] # 분할된 오른쪽 부분
        # 리스트 컴프리헨션 -> tail의 원소 중의 피벗 보다 작거나큰(혹은 큰) 요소를 차례대로 x에 대입 
        
        # 분할 이후 왼쪽 부분과 오른쪽 부분에서 각각 정렬을 수행하고, 전체 리스트를 반환
        return quick_sort(left_side) + [pivot] + quick_sort(right_side)
    
    print(quick_sort(array))

     

    * 계수 정렬(count sort)

    • 특정한 조건이 부합할 때만 사용할 수 있음 : '데이터의 크기 범위가 제한(일반적으로 ~1,000,000)되어 정수 형태로 표현할 수 있을 때'
    • 시간 복잡도 : O(N+K)
    • 이전 포스팅 참고 : https://operationcoding.tistory.com/61
    # 모든 원소의 값이 0보다 크거나 같다고 가정
    array = [7, 5, 9, 0, 3, 1, 6, 2, 9, 1, 4, 8, 0, 5, 2]
    # 모든 범위를 포함하는 리스트 선언 (모든 값은 0으로 초기화)
    count = [0] * (max(array) + 1)
    
    for i in range(len(array)):
        count[array[i]] += 1 # 각 데이터에 해당하는 인덱스의 값 증가
    
    for i in range(len(count)): # 리스트에 기록된 정렬 정보 확인
        for j in range(count[i]):
            print(i, end=' ') # 띄어쓰기를 구분으로 등장한 횟수만큼 인덱스 출력

     

    * sorted() 와 sort()

    • sorted()파이썬 기본 정렬 라이브러리이다. ex) sorted(arr), 리스트나 딕셔너리 자료형을 매개변수로 입력받는다.(리턴값이 리스트다.)
    • sort()리스트 객체의 내장 함수이다. ex) arr.sort(). 별도의 정렬된 리스트가 반환되지 않고 내부 원소가 바로 정렬됨.(리턴값이 없다. None)
    • sorted()와 sort() 둘 다, key 매개변수를 입력으로 받을 수 있다. key 값으로 하나의 함수(lambda함수를 많이 사용한다.)가 들어가야 하며, 이는 정렬기준이된다.
    •  시간 복잡도 O(nlogn)
    • key옵션을 주면 기준값에 대해서만 정렬되고 나머지 값들은 본래 순서대로 보장된다. (정렬 안정성 참고)
    # 정렬 라이브러리에서 key를 활용한 소스코드
    array = [('바나나', 2), ('사과', 5), ('당근', 3)]
    
    def setting(data):
        return data[1]
    
    result = sorted(array, key=setting)
    print(result)
    
    # 람다함수를 활용
    array = [("바나나", 2), ("사과", 5), ("당근", 3)]
    result = sorted(array, key=lambda data: data[1])
    print(result)

    기준이 여러개 일 때 key에 lambda함수 작성 예시

    a = [(1, 99, 10000), (2, 98, 10002), (3, 97, 105), (4, 96, 105), (5, 95, 100)]
    a.sort(key=lambda a: (a[2], a[0]))	# 기준이 여러 개일 때 
    print(a)
    --------------------------------------
    [(5, 95, 100), (3, 97, 105), (4, 96, 105), (1, 99, 10000), (2, 98, 10002)]
    < 정렬에서 key 매개변수에 대한 고찰 >
    의문.
    lambda 함수는 data[1]을 출력한다. data[1]은 array[1]을 뜻한다고 생각했고, 그래서  ("바나나",2)가 반환되어야 한다고 생각했다. 하지만 위 코드의 결과는 각 리스트 요소의 두 번째 요소를 반환한다.  

    의문 해결.
    sort 함수의 설명서를 찾아봤다.

    "list.sort()와 sorted()는 모두 비교하기 전에 각 리스트 요소에 대해 호출할 함수(또는 다른 콜러블)를 지정하는 key 매개 변수를 가지고 있습니다."

    즉, data[1]은 array[1]을 의미하는 것이 아닌 data변수에 리스트의 각 요소인 array[0] ~ array[2]이 입력되는 것으로, data[1]은 array[0][1], array[1][1], array[2][1]를 의미한다.

     

     

    * 소스코드 출처 

    '이것이 코딩테스트다 ' 깃허브

    https://github.com/ndb796/python-for-coding-test

     

    GitHub - ndb796/python-for-coding-test: [한빛미디어] "이것이 취업을 위한 코딩 테스트다 with 파이썬" 전체

    [한빛미디어] "이것이 취업을 위한 코딩 테스트다 with 파이썬" 전체 소스코드 저장소입니다. - GitHub - ndb796/python-for-coding-test: [한빛미디어] "이것이 취업을 위한 코딩 테스트다 with 파이썬" 전체 소

    github.com

     

    댓글

Designed by Tistory.