[4주차] 알고리즘 5~7

이철민·2023년 2월 20일

[근삿값]

  • 근삿값: 특정값(참값)에 가장 가까운 값을 근삿값이라고 한다.
import random

nums = random.sample(range(0,50), 20)
print(f'nums: {nums}')

inputNum = int(input('input number: '))
print(f'inputNum: {inputNum}')

nearNum = 0
minNum = 50     # 가장 큰 숫자와 가장 작은 숫자의 차이 (데이터가 많을때는 최댓값을 구해야함)

for n in nums:
    absNum = abs(n - inputNum)
    # print(f'absNum: {absNum}')

    if absNum < minNum:
        minNum = absNum
        nearNum = n

print(f'nearNum: {nearNum}')
  • 근삿값 실습)

모듈: near

def getNearNum(an):    # an을 평균 점수로 받는다.

    baseScores = [95, 85, 75, 65, 55]
    nearNum = 0
    minNum = 100

    for n in baseScores:
        absNum = abs(n - an)
        if absNum < minNum:
            minNum = absNum
            nearNum = n

    if nearNum == 95:
        return 'A'
    elif nearNum == 85:
        return 'B'
    elif nearNum == 75:
        return 'C'
    elif nearNum == 65:
        return 'D'
    elif nearNum <= 55:
        return 'F'
실행파일) 

import near

scores = []

kor = int(input('국어 점수 입력: '))
scores.append(kor)

eng = int(input('영어 점수 입력: '))
scores.append(eng)

math = int(input('수학 점수 입력: '))
scores.append(math)

sci = int(input('과학 점수 입력: '))
scores.append(sci)

his = int(input('국사 점수 입력: '))
scores.append(his)

totalScore = sum(scores)
print(f'totalScore: {totalScore}')

avgScore = totalScore / len(scores)
print(f'avgScore: {avgScore}')

grade = near.getNearNum(avgScore)
print(f'grade: {grade}')

[평균]

  • 평균: 여러 수나 양의 중간값을 갖는 수
import random

nums = random.sample(range(0,100),10)
print(f'nums: {nums}')

total = 0
for n in nums:
    total += n

average = total / len(nums)
print(f'average: {average}')
예제 1) 50 이상 90 이하 수들의 평균 (조건: 0부터 100까지의 수 30개 중에서)

import random
nums = random.sample(range(0,100),30)
print(f'nums: {nums}')

total = 0
targetNums = []
for n in nums:
    if n >= 50 and n <= 90:
        total += n
        targetNums.append(n)

average = total / len(targetNums)
print(f'targetNums: {targetNums}')
print(f'average: {round(average, 2)}')
예제 2) 정수들의 평균 구하기
nums = [4, 5.12, 0, 5, 7.34, 9.1, 9, 3, 3.159, 1, 11, 12.789]
print(f'nums: {nums}')

targetNums = []
total = 0
for n in nums:
    if n - int(n) == 0:
        total += n
        targetNums.append(n)

average = total / len(targetNums)

print(f'targetNums: {targetNums}')
print(f'average: {round(average,2)}')
  • 평균 실습)
모듈: near

class Top5Players:

    def __init__(self, cs, ns):  # current score, new score
        self.currentScores = cs
        self.newScore = ns

    def setAlignScore(self):

        nearIdx = 0
        nearScore = 0
        minNum = 10.0

        for i, s in enumerate(self.currentScores):
            absNum = abs(self.newScore - s)

            if absNum < minNum:
                minNum = absNum
                nearIdx = i
                nearScore = s

        if self.newScore > self.currentScores[nearIdx]:
            for i in range(len(self.currentScores)-1, nearIdx, -1):
                self.currentScores[i] = self.currentScores[i-1]

            self.currentScores[nearIdx] = self.newScore

        else:
            for i in range(len(self.currentScores) - 1, nearIdx+1, -1):
                self.currentScores[i] = self.currentScores[i - 1]

            self.currentScores[nearIdx] = self.newScore

    def getFinalTop5Scores(self):
        return self.currentScores
실행파일)

import near

scores = [8.9, 7.6, 8.2, 9.1, 8.8, 8.1, 7.9, 9.4, 7.2, 8.7]
top5PlayerScores = [9.12, 8.95, 8.12, 7.90, 7.88]
print(f'top5PlaerScores: {top5PlayerScores}')

total = 0; average = 0
for n in scores:
    total += n

average = round(total / len(scores), 2)

print(f'total: {total}')
print(f'average: {average}')

tp = near.Top5Players(top5PlayerScores, average)
tp.setAlignScore()
top5PlayerScores = tp.getFinalTop5Scores()
print(f'top5PlayerScores: {top5PlayerScores}')

[재귀 알고리즘]

  • 재귀 알고리즘: 나 자신을 다시 호출하는 것을 재귀라고 한다.
def recursion(num):

    if num > 0:    # 재귀 함수는 무한반복을 피하기 위해 조건이 붙는다.
        print('*' * num)
        return recursion(num-1)
    else:
        return 1

recursion(10)
# 10!을 구해보자.

def factorial(num):
    if num > 0:
        return num * factorial(num-1)
    else:
        return 1

print(f'facotrial(10): {factorial(10)}')
  • 재귀 알고리즘 실습)
    • 재귀 알고리즘을 이용한 최대공약수 계산 (유클리드 호제법)

유클리드 호제법: 두 자연수 n1, n2에 대하여 (n1 > n2) n1을 n2로 나눈 나머지를 r이라 할때, n1과 n2의 최대 공약수는 n2와 r의 최대공약수와 같다.

# 재귀 함수 이용 X
def gcd(n1,n2):

    maxNum = 0
    for i in range(1,(n1+1)):
        if n1 % i == 0 and n2 % i == 0:
            maxNum = i

    return maxNum

print(f'gcd: {gcd(82,32)}')
print(f'gcd: {gcd(96,40)}')
# 재귀 함수 이용 (유클리드 호제법)
def gcd(n1,n2):

    if n1 % n2 == 0:
        return n2
    else:
        return gcd(n2, n1 % n2)

print(f'gcd: {gcd(82,32)}')
print(f'gcd: {gcd(96,40)}')

[하노이의 탑]

  • 하노이의 탑
  • 하노이의 탑 실습)
          # 원판 개수, 출발 기둥, 도착 기둥, 경유 기둥
def moveDisc(discCnt, fromBar, toBar, viaBar):
    if discCnt == 1:
        print(f'{discCnt}disc를 {fromBar}에서 {toBar}(으)로 이동!')

    else:
        # (discCnt-1)개들을 경유 기둥으로 이동
        moveDisc(discCnt-1, fromBar, viaBar, toBar)    # 여기서는 최종 목적지가 경유지!

        # discCnt를 목적 기둥으로 이동
        print(f'{discCnt}disc를 {fromBar}에서 {toBar}(으)로 이동!')

        # (discCnt-1)개들을 도착 기둥으로 이동
        moveDisc(discCnt-1, viaBar, toBar, fromBar)

moveDisc(3, 1, 3, 2)
# 과정 설명

(3, 1, 3, 2) 2, 1, 2, 3    -> 3 디스크를 1에서 3으로 이동 (4)

(2, 1, 2, 3) 1, 1, 3, 2    -> 2 디스크를 1에서 2로 이동 (2)

(1, 1, 3, 2)               -> 1 디스크를 1에서 3으로 이동! (1)


(2, 1, 2, 3)  1, 3, 2, 1

(1, 3, 2, 1)               -> 1 디스크를  3에서 2로 이동 (3)

(3, 1, 3, 2)  --- 이런 과정을 반복 (재귀)

[병합정렬]

  • 병합정렬: 자료구조를 분할하고 각각의 분할된 자료구조를 정렬한 후 다시 병합하여 정렬한다. (재귀 알고리즘 활용)

def mSort(ns):

    if len(ns) < 2:
        return ns

    midIdx = len(ns) // 2            # 반으로 분할하기 위한 기준점
    leftNums = mSort(ns[0:midIdx])   # 한 번만 분할하는 것이 아니라 계속 분할해야 하기 때문에 재귀 알고리즘 사용
    rightNums = mSort(ns[midIdx:len(ns)])

    mergeNums = []                   # 병합된 후의 리스트
    leftIdx = 0; rightIdx = 0
    while leftIdx < len(leftNums) and rightIdx < len(rightNums):

        if leftNums[leftIdx] < rightNums[rightIdx]:
            mergeNums.append(leftNums[leftIdx])
            leftIdx += 1

        else:
            mergeNums.append(rightNums[rightIdx])
            rightIdx += 1

    mergeNums = mergeNums + leftNums[leftIdx:]
    mergeNums = mergeNums + rightNums[rightIdx:]

    return mergeNums

nums = [8, 1, 4, 3, 2, 5, 10, 6]
print(f'mSort(nums): {mSort(nums)}')
  • 병합정렬 실습)

모듈: sortMod

def mSort(ns, asc=True):

    if len(ns) < 2:
        return ns

    midIdx = len(ns) // 2
    leftNums = mSort(ns[0:midIdx], asc=asc)   # 내림차순을 만들때, 최초에는 asc = False가 들어와도,
    rightNums = mSort(ns[midIdx:], asc=asc)   # 재귀호출을 할때 asc = True가 되기 때문에 asc = asc 라는 옵션 필요

    mergeNums = []
    leftIdx = 0; rightIdx = 0
    while leftIdx < len(leftNums) and rightIdx < len(rightNums):

        if asc:
            if leftNums[leftIdx] < rightNums[rightIdx]:
                mergeNums.append(leftNums[leftIdx])
                leftIdx +=1
            else:
                mergeNums.append(rightNums[rightIdx])
                rightIdx += 1

        else:
            if leftNums[leftIdx] > rightNums[rightIdx]:
                mergeNums.append(leftNums[leftIdx])
                leftIdx +=1
            else:
                mergeNums.append(rightNums[rightIdx])
                rightIdx += 1

    mergeNums = mergeNums + leftNums[leftIdx:]
    mergeNums = mergeNums + rightNums[rightIdx:]
    return mergeNums
실행파일)

import random as rd
import sortMod as sm

rNums = rd.sample(range(1,101),10)
print(f'not sorted rNums: {rNums}')
print(f'sorted rNums ASC: {sm.mSort(rNums)}')
print(f'sorted rNums DSC: {sm.mSort(rNums, asc=False)}')

[퀵정렬]

  • 퀵정렬: 기준 값보다 작은 값과 큰 값으로 분리한 후 다시 합친다. (재귀 함수 사용)
def qSort(ns):

    if len(ns) < 2:
        return ns

    midIdx = len(ns) // 2
    midVal = ns[midIdx]       # 기준값

    smallNums = []; sameNums = []; bigNums = []

    for n in ns:
        if n < midVal:
            smallNums.append(n)
        elif n == midVal:
            sameNums.append(n)
        else:
            bigNums.append(n)

    return qSort(smallNums) + sameNums + qSort(bigNums)

nums = [8, 1, 4, 3, 2, 5, 2, 10, 6, 8]
print(f'qSort(nums): {qSort(nums)}')
  • 퀵정렬 실습)
모듈: sortMod

def qSort(ns, asc=True):

    if len(ns) < 2:
        return ns

    midIdx = len(ns) // 2
    midVal = ns[midIdx]

    smallNums = []; sameNums = []; bigNums = []

    for n in ns:

        if n < midVal:
            smallNums.append(n)
        elif n == midVal:
            sameNums.append(n)
        else:
            bigNums.append(n)

    if asc:
        return qSort(smallNums, asc=asc) + sameNums + qSort(bigNums, asc=asc)
    else:
        return qSort(bigNums, asc=asc) + sameNums + qSort(smallNums, asc=asc)
실행파일) 

import random as rd
import sortMod as sm

rNums = rd.sample(range(1,101),10)
print(f'not sorted rNums: {rNums}')
print(f'sorted rNums ASC: {sm.qSort(rNums)}')
print(f'sorted rNums DSC: {sm.qSort(rNums, asc=False)}')
profile
늘 온 마음을 다해 :)

0개의 댓글