참고: 부스트코스 CS50 모두를 위한 컴퓨터과학
에드위드 파이썬으로 배우는 알고리즘 기초
알고리즘
1. 알고리즘 표기법
- 빅O와 빅Ω
- 빅O
- 알고리즘 실행 시간의 상한
- 최악의 경우! (즉, 자료가 맨 마지막 경우에 발견되거나, 리스트 안에 없는 경우)
- O는 "on the order of"의 약자 → "~만큼의 정도로 커지는"
- 알고리즘별 일반적인 빅O
- O(n²) - 버블 정렬, 선택 정렬, 삽입 정렬(정렬이 하나도 안 된 경우)
- O(n log n)
- O(n) - 선형 검색
- O(log n) - 이진 검색
- O(1)
- 빅Ω
- 알고리즘 실행 시간의 하한
- 운이 좋은 경우!
- 알고리즘별 일반적인 빅Ω
- Ω(n²) - 버블 정렬, 선택 정렬
- Ω(n log n)
- Ω(n) - 배열 안에 존재하는 값의 개수 세기, 버블정렬(이미 정렬된 경우), 삽입정렬(정렬이 좀 된 경우)
- Ω(log n)
- Ω(1) - 선형 검색, 이진 검색
- 빅O와 빅Ω의 비교
- 최악의 경우일때 더 나은 알고리즘, 즉 상한선이 낮은 알고리즘이 좋음 (평균적으로, 일반적으로 계산했을 때의 경우가 더 중요하단 것. 안전빵 개념.)
- 빅O
2. 알고리즘 설계 종류
- Brute-force (단순무식): 선형검색 같은 거
- 백트래킹
- 분기한정정
- divide-conquer (분할, 정복): +필요하면 통합까지! 탑다운 방식, 작은 입력 사례를 각각 정복하는데 작은 입력 사례가 충분히 작지 않으면 재귀 호출
- greedy(탐욕법): 가장 비효율적인 분할정복 알고리즘
- dynamic programming(동적계획): 바텀업 개념
3. 검색 알고리즘
- 검색 알고리즘이란?
- 주어진 "배열" 속에서 특정 값을 찾는 방법
- 배열은 자료형의 여러 값들이 메모리상에 모여 있는 구조
- 컴퓨터는 이 값들에 접근할 때 배열의 인덱스 하나하나를 접근
- 배열이 정렬되어 있는지 여부가 중요해짐!
- 선형 검색linear serach
- 선형 검색의 특징
- 배열의 인덱스를 처음부터 끝까지 하나씩 증가시키면서 방문하여 그 값이 속하는지를 검사
- 원하는 원소가 발견될 때까지 처음부터 마지막 자료까지 차례대로 검색
- 정확하지만 아주 효율적이지 못한 방법
- 자료가 정렬되어 있지 않거나 그 어떤 정보도 없어 하나씩 찾아야 하는 경우에 유용
- 효율적인 검색을 위해서는 "정렬"이 그래서 중요함 → but 정렬은 시간이 오래 걸리고 공간을 더 차지 → 여러번 검색해야 하는 경우, 더 큰 리스트를 검색해야 하는 경우를 위해서는 필요할 수 있음
- 검색을 위해 구조체를 정의하면 편리할 수 있음
- 슈도코드
For i from 0 to n–1 If i'th element is 50 Return true Return false
- 선형 검색의 특징
3. 정렬 알고리즘
- 정렬 알고리즘이란?
- 말 그대로 정렬을 위함
- 정렬해서 더 쉽게 검색하기 위함임!
- 버블 정렬 (bubble sort)
- 두 개의 인접한 자료 값을 비교하면서 위치를 교환하는 방식으로 정렬
- 단 두 개의 요소만 정렬해주는 좁은 범위의 정렬
- 단 하나의 요소를 정렬하기 위해 너무 많이 교환하는 낭비가 발생할 수 있음
- 버블 정렬시 교환이 하나도 이루어지지 않는다면 이미 정렬되어 있다는 의미 → 교환이 일어나지 않을때까지만 루프가 발생하게 수정한다면 버블 정렬의 하한은 Ω(n)이 됨
- 슈도코드
Repeat n–1 times For i from 0 to n–2 If i'th and i+1'th elements out of order Swap them
- 상한 시간: O(n²)
- 하한 시간: Ω(n²)
- 선택 정렬 (selection sort)
- 배열 안의 자료 중 가장 작은 수(혹은 가장 큰 수)를 찾아 첫 번째 위치(혹은 가장 마지막 위치)의 수와 교환
- 교환 횟수를 최소화하는 반면 각 자료를 비교하는 횟수는 증가
- 슈도코드
For i from 0 ton–1 Find smallest item between i'th item and last item Swap smallest item with i'th item
- 상한 시간: O(n²)
- 하한 시간: Ω(n²)
- 삽입 정렬 (insertion sort)
- 정렬되지 않은 부분의 자료가 정렬된 부분의 자리로 삽입되는 형태의 정렬 방법
- 1번째 원소부터 0번째 원소와 비교하여 정렬하기 시작 → 다음 단계가 진행되며 기존의 자료들의 위치가 바뀔 수 있음
- 자료의 양이 적을 때 성능이 우수하며 자료 대부분이 이미 정렬이 되어있는 경우 효율적
- 이미 정렬된 자료에 새로운 자료를 삽입해야 하는 경우가 발생하면, 정렬된 자료들이 자리를 이동해야 하므로 안정성이 낮음
- 생각해보니 내가 일상 생활에서 많이 쓰는 정렬!
- 슈도 코드
- 상한 시간: O(n²)
- 하한 시간: Ω(n)
- 병합 정렬 (merge sort)
- 원소가 한 개가 될 때까지 계속해서 반으로 나누다가 다시 합쳐나가며 정렬을 하는 방식
- 버블, 선택 정렬보다 빠름 but 이미 정렬되어 있다면 버블 정렬(O(n))보다는 느림
- 상한 시간: O(n log n) → 숫자를 반으로 나누는 데
- 하한 시간: Ω(n log n) → 나눈 부분을 다시 정렬하여 병합할 때
- 퀵 정렬 (quick sort)
- 대표적인 분할정복 알고리즘
- 내부정렬(in-place) 방식 (추가적인 temp 리스트가 필요하지 않음)
- 병합 정렬과 다른 점은 병합 정렬은 반으로 자르는 기준이 N/2라면, 퀵 정렬은 기준원소(pivot)을 정해서 그걸 기준으로 좌우 분할함 (바로 이 부분이 효율성과 성능을 향상시켜줌)
- 이때, 피봇을 정하는 것이 중요함!
- 정렬이 많이 되어 있는 함수일수록 성능이 떨어짐..! → 랜덤할 수록 성능이 나아지기 때문에, 피봇을 정할때 아무거나 랜덤으로 찍는게 좋음
재귀함수 recursive function
- 자기 자신을 호출하는 함수
- 재귀 종료 조건이 존재하여, 종료 조건까지 함수 호출을 반복함
- 함수 안에 그 함수를 또 써주면 됨 (무한 루프를 조심)
- 반복문을 재귀 함수로 바꾸어 표현할 수 있음 (재귀 개념은 fractal을 떠올리게 함!)
- 재귀 함수의 구조
- 멈추어야 하는 조건은 1회 이상 하드코딩 해주어야 함 → 안 그런 경우 무한히 재귀 함수를 호출하며 스택 오버플로우 현상이 일어날 것!
(스택 오버플로우: 재귀함수처럼 자기 자신을 계속 호출하는 함수를 쓰다 보면, 점점 메모리 영역이 위로 늘어나며 힙 영역을 침범) - 마지막 완성 전 한 스텝 뒤를 재귀 함수로 호출
- 그리고 완성을 위한 마지막 스텝에서 해주어야 할 과정을 수행문으로 작성하면 됨
- 멈추어야 하는 조건은 1회 이상 하드코딩 해주어야 함 → 안 그런 경우 무한히 재귀 함수를 호출하며 스택 오버플로우 현상이 일어날 것!
'자료구조&알고리즘' 카테고리의 다른 글
컴퓨터 과학, 자료구조, 알고리즘 with C언어 (0) | 2022.11.27 |
---|---|
크래프톤정글 2주차; 힙, 힙 정렬, 우선순위 큐 (0) | 2022.11.14 |
크래프톤정글 2주차; 중위 표기식과 후위 표기식, 스택으로 계산기 구현 (1) | 2022.11.09 |
크래프톤정글 2주차; 자료구조 中 스택, 큐, 우선순위 큐 (0) | 2022.11.06 |
크래프톤정글 2주차; 이분탐색, 분할정복 (0) | 2022.11.06 |