파이썬_알고리즘_006 최대값-하노이탑

이새롬·2023년 2월 19일
0

python

목록 보기
19/21
post-thumbnail

최대값

자료구조에서 가장 큰 값을 찾는다.
maxNum이라는 변수를 첫번째 데이터를 넣어 for문으로 계속 비교하며 찾기

코드쓰고

class MaxAlgorithm:

    def __init__(self, ns):
        self.nums = ns
        self.maxNum = 0

    def getMaxNum(self):
        self.maxNum = self.nums[0]

        for n in self.nums:
            if self.maxNum < n:
                self.maxNum = n

        return self.maxNum;

ma = MaxAlgorithm([-2, -4, 5, 7, 10, 0, 8, 20, -11])
maxNum = ma.getMaxNum()
print(f'maxNum: {maxNum}')

이 코드에서 변형된게 최소 값, 활용한게 최빈값이니
잘 알아두자!


최소값

자료구저에서 가장 작은 값을 찾는 것.
minNum이라는 변수를 첫번째 데이터를 넣어 for문으로 계속 비교하며 찾기

라진 점은
담는 변수가 miNum이라는 것
그리고 판별하는 등호가 최대값
if self.maxNum < n: 에서
if self.minNum > n: 이라는 것외엔 동일!


최빈값

빈도가 가장 잦은 데이터를 찾아보자!

최대값 maxNum만 할당하는 데서 enumerate를 이용해서 index와 값을 나눔.
그러면서 index도 변수로 담아서

  1. 최대값을 찾는다
  2. 최대값의 갯수만큼 0을 담은 indexes변수를 만든다
  3. indexes에 나온 숫자에 자리에 +1이 쌓이게끔 for을 돌린다.
for n in nums:
    indexes[n] = indexes[n] + 1
  1. 반대로 최대값을 만든 객체에 indexes를 보내 maxNum을 활용해 어떤 숫자인지 찾음
    자리수는 maxIdx(자리 값이 곧 숫자)를 호출,
    빈도수는 maxNum(쌓인 포인트만큼이 빈도수)을 호출

해서 최대값을 2번 호출하여 사용하기에 class를 만들어 활용한다.

class MaxAlgorithm:
    def __init__(self,ns):
        self.nums = ns
        self.maxNum = 0
        self.maxNumIdx = 0

    def setMaxIdxAndNum(self):
        self.maxNum = self.nums[0]
        self.maxNumIdx = 0

        for i, n in enumerate(self.nums):
            if self.maxNum < n :
                self.maxNum = n
              self.maxNumIdx = i

    def getMaxNum(self):
        return self.maxNum

    def getMaxNumIdx(self):
        return self.maxNumIdx

nums = [1, 3, 7, 6, 7, 7, 7, 12, 12, 17]

maxAlo = MaxAlgorithm(nums)
maxAlo.setMaxIdxAndNum()
maxNum = maxAlo.getMaxNum()
print(f'num의 최대값: {maxNum}')

indexes = [0 for i in range(maxNum+1)]

print(f'indexes : {indexes}')
print(f'indexes 길이 : {len(indexes)}')

for n in nums:
    indexes[n] = indexes[n] + 1
print(f'indexes : {indexes}')

ma =MaxAlgorithm(indexes)
ma.setMaxIdxAndNum()
maxNum = ma.getMaxNum()
maxIdx = ma.maxNumIdx

print(f'따라서 {maxIdx}의 빈도수가 {maxNum}으로 가장 높다')

결과 출력


근사값

가장 가까운 값을 찾자! (차이가 적은 숫자 찾기)
절대값이 작은 숫자

import random
nums = random.sample(range(0,50),5)
print(f'nums : {nums}')
inputNum = int(input('input number : '))
print(f'input number : {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} 근사값이다.')

결과 출력

차이를 구하고 그 차이가 가장 적은 걸 최소값으로 담아
최종 최소값의 자리번호인 n을 구함(근사값)


평균

너무 자주 예제에서 썼던 평균
전체합

for n in nums:
    nums += n

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

++) 실수는 if 조건 안에 n - int(n) != 0: 으로 끝


재귀

나 자신을 호출하자

1 .팩토리얼

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

print(f'factorial(10) : {factorial(10)}')
  1. 유클리드 호제법
    1) for문
def greatestCommonDevide(n1,n2):
    maxNum = 0
    for i in range(1,(n1+1)):
        if n1 % i == 0 and n2 % i == 0:
            maxNum = i

    return maxNum

2) 재귀함수

def gcd(n1, n2):

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

하노이의 탑 (재귀 활용)

게임으로 많이 하던 하노이탑....
유튜브로도 복습하는데
매개변수를 계속 바꿔가며 이동을 하는데 쉽지않아서 당분간 매일 봐야할듯...

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

    else:
        moveDisc(discCnt-1, fromBar, viaBar, toBar)              # (discNo-1)개들을 경유 기둥으로 이동
        print(f'{discCnt}disc: {fromBar}에서 {toBar}(으)로 이동!') # discNo를 도착 기둥으로 이동
        moveDisc(discCnt-1, viaBar, toBar, fromBar)              # (discNo-1)개들을 도착 기둥으로 이동

moveDisc(3, 1, 3, 2)

병합 정렬 (재귀활용 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(mSort(nums))

동작원리를 log를 찍어보면

💡 응용문제서는 내림차순+ 오름차순
매개변수 asc=True값을주고
재귀 호출될 시도 같은 값을 주기 위해
(인수, asc=asc)로 추가해줘야한다.
안그러면 한번 호출이면 기본값이 True로되어 숫자가 뒤섞임.


퀵정렬 (재귀 활용3)

기준보다 작은 값과 큰 값을 분리하다

1. 기준값 정함 (인덱스 가운데)
2. 그 다음 그 기준 기준으로 작냐 크냐 가름
3. 그 다음 왼쪽 그룹도 가운데 정해서 크고 작냐 거름 - 나뉠때 까지 반복 (재귀)

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)

사이에 로그를 보기 위해서

    print(f'smallNums: {smallNums} ')
    print(f'sameNums: {sameNums} ')
    print(f'bigNums: {bigNums} ')
    return qSort(smallNums) + sameNums + qSort(bigNums)

nums= [8, 1, 4, 3, 2, 5, 4, 10, 8, 6]

print(f'퀵정렬: {qSort(nums)}')

위에를 return 직전에 추가하여

출력 결과 보기


💬 코멘트

...개념강의가 금방 끝난 재귀가 이렇게 눈덩이처럼 돌아올 줄이야.
병합정렬, 퀵정렬은 설명도 이해가 갔고 코드도 그리 어렵지 않게 받아들여졌다.
하노이탑....진짜 코드 배우기 이전에 재밌게하던 놀이가 코드로 오니까
지금 유튜브를 보고 ..아 조콤 알겠는데?? 하면서도 코드 다시보면 도루묵이라
이게 공부가 연계가 되고 그게 심화가 되니까 그냥 아 좀 알겠다로 넘길수가 없다..
계속 들여다보면 또 전체적인게 안보일 수 있으니 매일 좀 보며 익숙해지는 수 밖에 없을 것..같다.....

0개의 댓글