Algorithm/μ•Œκ³ λ¦¬μ¦˜ 곡뢀

[μ•Œκ³ λ¦¬μ¦˜] μ •λ ¬ - 선택 μ •λ ¬, μ‚½μž… μ •λ ¬, 퀡 μ •λ ¬, κ³„μˆ˜ μ •λ ¬

meeeeejin 2021. 7. 10. 13:17

 

μ •λ ¬(Sorting)μ΄λž€ 데이터λ₯Ό νŠΉμ •ν•œ 기쀀에 λ”°λΌμ„œ μˆœμ„œλŒ€λ‘œ λ‚˜μ—΄ν•˜λŠ” 것을 λ§ν•œλ‹€.

 

μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ 데이터λ₯Ό μ •λ ¬ν•˜λ©΄ 이진 탐색(Binary Search)이 κ°€λŠ₯해진닀. λ˜ν•œ ν”„λ‘œκ·Έλž¨μ—μ„œ 데이터λ₯Ό 가곡할 λ•Œ μ–΄λ–€ μ‹μœΌλ‘œλ“  μ •λ ¬ν•΄μ„œ μ‚¬μš©ν•˜λŠ” κ²½μš°κ°€ 많기 λ•Œλ¬Έμ— μ •λ ¬ μ•Œκ³ λ¦¬μ¦˜μ€ ν”„λ‘œκ·Έλž¨ μž‘μ„± μ‹œ κ°€μž₯ 많이 μ‚¬μš©λ˜λŠ” μ•Œκ³ λ¦¬μ¦˜ 쀑 ν•˜λ‚˜μ΄λ‹€. 

 

 

선택 μ •λ ¬(Selection Sort)

πŸ’‘ 아이디어

데이터가 λ¬΄μž‘μœ„λ‘œ μ—¬λŸ¬ 개 μžˆμ„ λ•Œ, κ·Έμ€‘μ—μ„œ κ°€μž₯ μž‘μ€ 데이터λ₯Ό 선택해 맨 μ•žμ— μžˆλŠ” 데이터와 λ°”κΎΈκ³ , κ·Έλ‹€μŒ μž‘μ€ 데이터λ₯Ό 선택해 μ•žμ—μ„œ 두 번째 데이터와 λ°”κΎΈλŠ” 과정을 λ°˜λ³΅ν•΄λ³΄μž

=> 맀번 κ°€μž₯ μž‘μ€ 것을 μ„ νƒν•œλ‹€

좜처: μœ„ν‚€λ°±κ³Ό -  선택 μ •λ ¬

 

πŸ’‘ μ†ŒμŠ€μ½”λ“œ

def sel_sort(array):
  for i in range(len(array)):
    min_index = i # κ°€μž₯ μž‘μ€ μ›μ†Œμ˜ 인덱슀
    for j in range(i + 1, len(array)):
      if array[j] < array[min_index]:
        min_index = j
    array[i], array[min_index] = array[min_index], array[i] # swap

  return array

# μ‹œκ°„λ³΅μž‘λ„: O(N^2)

 

 

 

 

μ‚½μž… μ •λ ¬(Insertion Sort)

πŸ’‘ 아이디어

데이터λ₯Ό ν•˜λ‚˜μ”© ν™•μΈν•˜λ©°, 각 데이터λ₯Ό μ μ ˆν•œ μœ„μΉ˜μ— μ‚½μž…ν•΄λ³΄μž

좜처: μœ„ν‚€λ°±κ³Ό - μ‚½μž… μ •λ ¬

 

πŸ’‘ μ†ŒμŠ€μ½”λ“œ

def ins_sort(array):
  for i in range(1, len(array)):
    for j in range(i, 0, -1):
      if array[j] < array[j - 1]: # ν•œ μΉΈμ”© μ™Όμͺ½μœΌλ‘œ 이동
        array[j], array[j - 1] = array[j - 1], array[j]
      else: # μžκΈ°λ³΄λ‹€ μž‘μ€ 데이터λ₯Ό λ§Œλ‚˜λ©΄ κ·Έ μœ„μΉ˜μ—μ„œ 멈좀
        break

  return array

# μ‹œκ°„λ³΅μž‘λ„: O(N^2)

μ‚½μž… μ •λ ¬μ˜ 경우 μ •λ ¬λœ 리슀트λ₯Ό 인자둜 μ£Όμ—ˆμ„ λ•Œ O(N)에 μž‘λ™ν•œλ‹€. μ΄μ–΄μ„œ λ‚˜μ˜¬ 퀡 μ •λ ¬κ³Ό λΉ„κ΅ν–ˆμ„ λ•Œ, λ³΄ν†΅μ˜ 경우 μ‚½μž… 정렬이 더 λΉ„νš¨μœ¨μ μ΄μ§€λ§Œ 정렬이 거의 λ˜μ–΄ μžˆλŠ” μƒν™©μ—μ„œλŠ” 더 κ°•λ ₯ν•˜λ‹€λŠ” 것을 κΌ­ κΈ°μ–΅ν•˜κ³  잘 ν™œμš©ν•˜μž!!!😎

 

 

 

 

퀡 μ •λ ¬(Quick Sort)

πŸ’‘ 아이디어

κΈ°μ€€ 데이터λ₯Ό μ„€μ •ν•˜κ³  κ·Έ 기쀀보닀 큰 데이터와 μž‘μ€ λ°μ΄ν„°μ˜ μœ„μΉ˜λ₯Ό λ°”κΏ”λ³΄μž!

 

 

πŸ’‘ λΆ„ν•  κ³Όμ •

퀡 정렬은 κΈ°μ€€(pivot)을 μ„€μ •ν•œ λ‹€μŒ 큰 μˆ˜μ™€ μž‘μ€ 수λ₯Ό κ΅ν™˜ν•œ ν›„, 리슀트λ₯Ό 반으둜 λ‚˜λˆ„λŠ” λ°©μ‹μœΌλ‘œ λ™μž‘ν•œλ‹€.

피벗을 μ„€μ •ν•˜λŠ” λ°©λ²•μ—λŠ” μ—¬λŸ¬ 가지 방식이 μžˆμ§€λ§Œ, μ—¬κΈ°μ„œλŠ” λŒ€ν‘œμ μΈ λΆ„ν•  방식인 ν˜Έμ–΄ λΆ„ν• (Hoare Partition) λ°©μ‹μœΌλ‘œ 피벗을 μ •ν•˜κ² λ‹€. ν˜Έμ–΄ λΆ„ν•  λ°©μ‹μ—μ„œλŠ” '리슀트의 첫 번째 데이터'λ₯Ό ν”Όλ²—μœΌλ‘œ μ •ν•œλ‹€. 

 

피벗을 μ„€μ •ν•œ λ’€μ—λŠ” μ™Όμͺ½μ—μ„œλΆ€ν„° 피벗보닀 큰 데이터λ₯Ό μ°Ύκ³ , 였λ₯Έμͺ½μ—μ„œλΆ€ν„° 피벗보닀 μž‘μ€ 데이터λ₯Ό μ°ΎλŠ”λ‹€. κ·Έλ‹€μŒ 큰 데이터와 μž‘μ€ λ°μ΄ν„°μ˜ μœ„μΉ˜λ₯Ό μ„œλ‘œ λ°”κΎΌλ‹€. 이 과정을 μ™Όμͺ½μ—μ„œ μΆœλ°œν•œ 포인터와 였λ₯Έμͺ½μ—μ„œ μΆœλ°œν•œ 포인터가 μ—‡κ°ˆλ¦΄ λ•ŒκΉŒμ§€ λ°˜λ³΅ν•œλ‹€. 

 

두 포인터가 μ—‡κ°ˆλ¦° μ‹œμ μ—μ„œ, μž‘μ€ 데이터와 ν”Όλ²—μ˜ μœ„μΉ˜λ₯Ό μ„œλ‘œ λ°”κΎΌλ‹€. κ·Έλ ‡κ²Œ 되면 ν”Όλ²—μ˜ μ™Όμͺ½μ—λŠ” 피벗보닀 μž‘μ€ λ°μ΄ν„°λ§Œ, ν”Όλ²—μ˜ 였λ₯Έμͺ½μ—λŠ” 피벗보닀 큰 λ°μ΄ν„°λ§Œ μ‘΄μž¬ν•˜κ²Œ λœλ‹€. 이 과정을 λΆ„ν• (Divide) λ˜λŠ” νŒŒν‹°μ…˜(Partition)이라고 ν•œλ‹€. 

 

피벗에 따라 λΆ„ν• λœ μƒνƒœμ—μ„œ μ™Όμͺ½ λ¦¬μŠ€νŠΈμ™€ 였λ₯Έμͺ½ 리슀트λ₯Ό κ°œλ³„μ μœΌλ‘œ μ •λ ¬μ‹œν‚€λŠ” 과정을 λ°˜λ³΅ν•˜λ‹€ 보면 전체 λ¦¬μŠ€νŠΈμ— λŒ€ν•˜μ—¬ 정렬이 μ΄λ€„μ§€κ²Œ λœλ‹€. 

 

좜처: https://gmlwjd9405.github.io/2018/05/10/algorithm-quick-sort.html

 

 

πŸ’‘ μ†ŒμŠ€μ½”λ“œ

def quickSort(array):
  if len(array) <= 1:
    return array

  pivot = array[0]
  tail = array[1:]

  leftSide = [x for x in tail if x <= pivot]
  rightSide = [x for x in tail if x > pivot]

  return quickSort(leftSide) + [pivot] + quickSort(rightSide)

# 평균 μ‹œκ°„λ³΅μž‘λ„: O(NlogN)
# μ΅œμ•…μ˜ 경우: O(N^2)

퀡 μ •λ ¬μ—μ„œ μ΅œμ„ μ˜ κ²½μš°λŠ” 피벗값이 μ •ν™•νžˆ 리슀트λ₯Ό μ ˆλ°˜μ”© λ‚˜λˆ„λŠ” 것을 λ°˜λ³΅ν•  κ²½μš°μ΄λ‹€. 이 경우 μ‹œκ°„ λ³΅μž‘λ„λŠ” O(NlogN)이 λœλ‹€. 

퀡 μ •λ ¬μ—μ„œ μ΅œμ•…μ˜ κ²½μš°λŠ” 이미 μ •λ ¬λœ 리슀트λ₯Ό μž…λ ₯으둜 μ£Όμ—ˆμ„ λ•Œμ΄λ‹€. 이 경우 μ‹œκ°„ λ³΅μž‘λ„λŠ” O(N^2)이 λœλ‹€. 

 

 

 

 

κ³„μˆ˜ μ •λ ¬(Count Sort)

πŸ’‘ κ³„μˆ˜ μ •λ ¬μ΄λž€?

κ³„μˆ˜ 정렬은 λ°μ΄ν„°μ˜ κ°œμˆ˜κ°€ N, 데이터 쀑 μ΅œλŒ“κ°’μ΄ K일 λ•Œ μˆ˜ν–‰ μ‹œκ°„ O(N + K)λ₯Ό 보μž₯ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€. 

 

ν•˜μ§€λ§Œ μ–Έμ œλ‚˜ μ“°κΈ° μ ν•©ν•œ 것은 μ•„λ‹ˆκ³ , λ°μ΄ν„°μ˜ 크기 λ²”μœ„κ°€ μ œν•œλ˜μ–΄ μ •μˆ˜ ν˜•νƒœλ‘œ ν‘œν˜„ν•  수 μžˆμ„ λ•Œλ§Œ μ‚¬μš©ν•  수 μžˆλ‹€. 일반적으둜 λ°μ΄ν„°μ˜ maxκ°’κ³Ό minκ°’μ˜ 차이가 1,000,000을 λ„˜μ§€ μ•Šμ„ λ•Œ 효과적으둜 μ‚¬μš©ν•  수 μžˆλ‹€. μ™œλƒν•˜λ©΄ κ³„μˆ˜ 정렬을 μˆ˜ν–‰ν•˜λ €λ©΄ λͺ¨λ“  λ²”μœ„λ₯Ό 담을 수 μžˆλŠ” 크기의 λ¦¬μŠ€νŠΈκ°€ ν•„μš”ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. 

 

κ³„μˆ˜ μ •λ ¬μ˜ μˆ˜ν–‰ 과정은 λ‹€μŒκ³Ό κ°™λ‹€. 

  1. λ°μ΄ν„°μ˜ (min, max) λ²”μœ„λ₯Ό ν¬ν•¨ν•˜λŠ” ν•˜λ‚˜μ˜ 리슀트λ₯Ό 생성함
  2. 데이터λ₯Ό ν•˜λ‚˜μ”© ν™•μΈν•˜λ©° λ°μ΄ν„°μ˜ κ°’κ³Ό λ™μΌν•œ 인덱슀의 값을 1μ”© μ¦κ°€μ‹œν‚΄
  3. 리슀트의 첫 번째 데이터뢀터 κ·Έ κ°’λ§ŒνΌ 인덱슀λ₯Ό 좜λ ₯

 

좜처: https://www.programiz.com/dsa/counting-sort

 

 

πŸ’‘ μ†ŒμŠ€μ½”λ“œ

def countSort(array):
  count = [0] * (max(array) + 1)

  for x in array:
    count[x] += 1

  result = []
  for i in range(len(count)):
    for j in range(count[i]):
      result.append(i)

  return result

# μ‹œκ°„λ³΅μž‘λ„: O(N + K)

 

 

 

 

참고자료: 이것이 취업을 μœ„ν•œ μ½”λ”© ν…ŒμŠ€νŠΈλ‹€ with Python(λ‚˜λ™λΉˆ μ €, ν•œλΉ›λ―Έλ””μ–΄)

 

 

 

 

728x90