[DS] 정렬 (Sort)

2022. 12. 21. 17:52·Data structure


1. 선택 정렬 (Selection Sort)

for (last : n-1 --> 1) 내려가면서 반복
       A[0~last] 중 가장 큰 수 A[k]를 찾는다.
       A[k]와 A[last]를 교환한다.



# 선택 정렬(selectionSort)
def selectionSort(A):
    for last in range(len(A)-1, 0, -1):
        max = 0; index = -12345
        for k in range(last+1):
            if A[k] > max:
                max = A[k]
                index = k
        A[index], A[last] = A[last], A[index]



2. 버블 정렬 (Bubble Sort)

for (last : n-1 --> 1) 내려가면서 반복한다.
       for (i : 0 --> last-1) 올라가면서 반복한다.
              if (A[i] > A[i+1] )
                     A[i] <--> A[i+1]




버블 정렬 (Bubble Sort)



# 버블 정렬(bubbleSort)
def bubbleSort(A):
    for last in range(len(A)-1, 0, -1):
        for k in range(last):
            if A[k] > A[k+1]:
                A[k], A[k+1] =  A[k+1], A[k]




3. 삽입 정렬 (Insertion Sort)

for (i : 1 --> n-1) 올라가면서 반복
       newItem = A[i]
       j = i - 1
       # 이 지점에서 A[0 ~ i-1]은 이미 정렬된 상태
       while (0 <= j and newItem < A[j])
              A[i] 값을 j+1 자리에 넣는다.
              j 값을 1 줄인다.
       j+1 자리에 newItem 값을 넣는다.


# j가 -1이 되는 경우는 newItem이 가장 작은 값인 경우
# newItem이 들어갈 자리를 만드려면 A[j] 값이 들어가는 자리가 오른쪽으로 한 칸씩 밀려야 한다.



 

# 삽입 정렬(insertionSort)
def insertionSort(A):
    for i in range(1, len(A)):
        newItem = A[i]
        j = i - 1
        # 이 지점에서 A[0~i-1]은 이미 정렬된 상태다
        while 0 <= j and newItem < A[j]:
        # 여기서 j가 음수가 될 수 있으므로, 0 <= j 조건이 있어야 한다(j는 인덱스 번호이다)
        # j가 -1이 되는 경우는 newItem이 가장 작은 값인 경우이다 -> 이 경우 j+1(0)에 newItem을 넣으면 됨
            A[j+1] = A[j]
            j -= 1
        A[j+1] = newItem



4. 병합 정렬 (Merge Sort)

if p < r:
인자로 A, p, r을 받는 정렬의 경우 이 조건을 반드시 넣어 주어야 오류가 발생하지 않음



병합 알고리즘 (A, p, q, r)에서 A[p ~ q]와 A[q+1 ~ r]은 이미 정렬되어 있는 상태이다.



# 병합 정렬(mergeSort)
def mergeSort(A,p,r):
    if p < r:  # 인자로 A,p,r을 받는 정렬의 경우, 이 조건을 반드시 넣어 주어야 오류가 발생하지 않음!!
        q = (p + r) // 2
        mergeSort(A, p, q)
        mergeSort(A, q+1, r)
        merge(A, p, q, r)
def merge(A, p, q, r):
    i = p; j = q+1; t = 0; temp = [0 for _ in range(len(A))]
    while i <= q and j <= r:
        if A[i] <= A[j]:
            temp[t] = A[i]; i += 1; t += 1
        else:
            temp[t] = A[j]; j += 1; t += 1
    while i <= q:  # 왼쪽 부분만 남은 경우
        temp[t] = A[i]; i += 1; t += 1
    while j <= r:  # 오른쪽 부분만 남은 경우
        temp[t] = A[j]; j += 1; t += 1
    i = p; t = 0
    while i <= r:
        A[i] = temp[t]; i += 1; t += 1




5. 퀵 정렬 (Quick Sort)

if p < r:
인자로 A, p, r을 받는 정렬의 경우 이 조건을 반드시 넣어 주어야 오류가 발생하지 않음

기준보다 작은 수는 왼쪽에 나머지는 오른쪽에 오도록 배치하고 각각을 독립적으로 정렬한다.

 

1구역 : 15보다 작은 원소들 (i는 1구역의 끝)
2구역 : 15보다 크거나 같은 원소들
3구역 : 아직 정해지지 않은 원소들 (j는 3구역의 시작)
4구역 : 15 자신

for 루프가 한 바퀴 돌 때마다 3구역이 한 칸씩 줄어든다. (j가 1 증가)
for 루프가 한 바퀴 돌 때마다 1구역 또는 2구역 중 하나가 한 칸 늘어난다.
1구역이 늘어날 때는 i와 j가 동시에 1 증가한다.
2구역이 늘어날 때는 j만 1 증가한다. for 루프가 한 바퀴 돌 때마다 자동으로 j는 1 증가하므로, 2구역을 늘리기 위해서는 아무 일도 할 필요가 없다.



j만 증가할 경우 : 2구역 (가만히 있으면 2구역에 추가됨)
i와 j 모두 증가할 경우 : 1구역 (i와 j의 자리를 바꾸어 주어야 함)



# 퀵 정렬 1(Quick Sort 1)
def quickSort(A, p, r):  # 인자로 A,p,r을 받는 정렬의 경우, 이 조건을 반드시 넣어 주어야 오류가 발생하지 않음!!
    if p < r:
        q = partition(A, p, r)
        quickSort(A, p, q-1)
        quickSort(A, q+1, r)
def partition(A, p, r):
    x = A[r]
    i = p - 1
    for j in range(p, r):
        if A[j] < x:  # 1구역에 추가되어야 하는 경우, j는 3구역의 첫번째 원소를 가리키는 인덱스
           i += 1
           A[i], A[j] = A[j], A[i]
    A[i+1], A[r] = A[r], A[i+1]
    return i + 1

 

 

다른 방법 1

 

# 퀵 정렬 2(Quick Sort 2)
def quickSort(a, p, r):
    if p < r:
        left = p + 1
        right = r
        while (left <= right):
            while left <= r and a[left] <= a[p]: left += 1
            while right > p and a[p] <= a[right]: right -= 1
            if (left > right): a[right], a[p] = a[p], a[right]
            else: a[left], a[right] = a[right], a[left]
    quickSort(a, p, right-1)
    quickSort(a, right+1, r)

 

 

 

다른 방법 2

# 퀵 정렬 3(Quick Sort 3)
def quickSort(a):
	if len(a) <= 1: return a
	head = a[0]; tail = a[1:]
	left = [x for x in tail if x <= head]
	right = [x for x in tail if x > head]
	return quickSort(left) + [head] + quickSort(right)



6. 힙 정렬 (Heap Sort)



# 힙 정렬(heapSort)
def heapSort(A):
    buildHeap(A)
    for last in range(len(A)-1, 0, -1):
        A[0], A[last] = A[last], A[0]
        percolateDown(A, 0, last-1)
def percolateDown(A, i, end):
    left = 2 * i + 1
    right = 2 * i + 2
    if left <= end:
        child = left
        if right <= end and A[left] < A[right]:
            child = right
        if A[i] < A[child]:
            A[i], A[child] = A[child], A[i]
            percolateDown(A, child, end)

def buildHeap(A):
    for i in range((len(A)-2)//2, -1, -1):
        percolateDown(A, i, len(A)-1)



7. 셸 정렬 (Shell Sort)

셸 정렬은 마지막 삽입 정렬을 하기 전에 각 원소가 있어야 할 자리에서 멀리 떨어져 있을 가능성을 현저히 줄이는 작업을 통해 삽입 정렬의 효율성을 높인다.

갭 수열 H = {h0, h1, ..., 1}
for (h : h0, h1, ..., 1) h칸 떨어진 원소들 끼리 삽입 정렬
       A[0, h, 2h, ... ]을 정렬
       A[1, 1+h, 1+2h, ... ]을 정렬
                     ...
       A[h-1, 2h-1, ... ]을 정렬


# 간격을 h로 하는 삽입 정렬 알고리즘 !






# 셸 정렬(shellSort)
def shellSort(A):
    H = gapSequence(A)
    for h in H:
        for k in range(h):
            stepInsertionSort(A, k, h)
            # for 루프를 마지막으로 수행할 때 stepInsertionSort(A,0,1)이 호출되는데, 이는 삽입정렬과 동일하다.
def gapSequence(A):
    H = [1]; gap = 1
    while gap < len(A) / 5:
        gap = 3 * gap + 1
        H.append(gap)
    H.reverse()
    return H
def stepInsertionSort(A, k, h):  # A[k, k+h, k+2h ...]를 정렬
    for i in range(k+h, len(A), h):
        newItem = A[i]
        j = i - h
        while j >= 0 and A[j] > newItem:
            A[j+h] = A[j]
            j -= h
        A[j+h] = newItem



8. 계수 정렬 (Counting Sort)


 

# 계수 정렬(countingSort)
def countingSort(A):
    k = max(A)
    C = [0 for _ in range(k+1)]  # C[0, 1, 2 ... k-1]; C[0]->0, C[1]->1 ... C[k]->k    
    B = [0 for _ in range(len(A))]
    for i in range(len(A)):  # A의 원소별 등장 횟수를 카운터에 기록
        C[A[i]] += 1
    for j in range(1, k+1):  # C(카운터)를 수선
        C[j] = C[j] + C[j-1]
    for i in range(len(A)):  # B를 채우기
        B[C[A[i]]-1] = A[i]
        C[A[i]] -= 1
    return B



9. 기수 정렬 (Radix Sort)

 

# 기수 정렬(radixSort)
def radixSort(A):
    buckets = [[] for _ in range(10)]
    k = max(A)
    numberDigits = math.ceil(math.log10(k))
    for i in range(numberDigits):
        for x in A:
            y = (x // 10**i) % 10
            buckets[y].append(x)
        A.clear()
        for j in range(10):
            A.extend(buckets[j])
            buckets[j].clear()



10. 버킷 정렬 (Bucket Sort)

정렬하고자 하는 원소들이 균등 분포할 때를 가정한 정렬 알고리즘
균등분포 : 데이터가 전 영역에 걸쳐 고루 존재하는 분포

A[0 ... 14] 각각에 15를 곱하여 정수부만 취함

* 균등 분포이기만 하면 [a, b] 사이의 값들을 [0, 1] 범위의 실수 값으로 매핑할 수 있기 때문에 정렬할 원소들이 반드시 [0, 1] 사이의 값일 필요는 없다.

# 버킷 정렬(bucketSort)
def bucketSort(A):
    n = len(A)
    buckets = [[] for _ in range(n)]
    for i in range(n):
        buckets[math.floor(n*A[i])].append(A[i])
    A.clear()
    for i in range(n):
        insertionSort(buckets[i])
        A.extend(buckets[i])

 

'Data structure' 카테고리의 다른 글
  • [DS] Red-Black Tree
  • [DS] 그래프
  • [DS] 해시 테이블 (Hash Table)
  • [DS] 힙 (Heap) - Priority Queue ☑️
vysryoo
vysryoo
  • vysryoo
    vysryoo
    vysryoo
  • 전체
    오늘
    어제
    • 분류 전체보기 (129)
      • Python (20)
      • Data structure (12)
      • Algorithm (14)
      • Operating system (18)
      • Programming language theory (12)
      • Computer architecture (6)
      • Softeware engineering (8)
      • Multicore (2)
      • Data Base (3)
      • Problem solving (24)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
vysryoo
[DS] 정렬 (Sort)
상단으로

티스토리툴바