본문 바로가기

CS STUDY/알고리즘

(10)
DFS & BFS DFS(Depth-First Search) 개념 루트노드에서 시작해 다음 분기로 넘어가기 전 해당 분기를 완벽하게 탐색 스택 or 재귀함수로 구현 특징 장점 최단 경로 빠르게 찾을 수 있다. 단점 경로가 매우 길 경우 많은 기억 공간 필요 비연결 그래프일 경우, 모든 그래프 탐색 후 실패 BFS(Breadth First Search) 개념 루트 노드에서 시작해 인접한 노드를 먼저 탐색하는 방식으로 시작 정점으로부터 가까운 정점을 먼저 방문하고 멀리 떨어진 정점을 나중에 방문 큐를 이용해 구현 특징 장점 적은 메모리 사용 찾으려는 노드가 깊은 단계에 있는 경우 BFS보다 빠름 단점 경로가 존재하지 않아도 끝날 때까지 탐색 최단 경로 찾기 힘듬
이분 탐색(Binary Search) 이분 탐색 개념 정렬되어 있는 리스트에서 탐색 범위를 절반씩 좁혀가며 데이터 탐색 배열 내부의 데이터가 정렬되어 있어야만 사용 가능 과정 데이터를 오름차순으로 정렬 자료의 중간값(mid)가 찾고자 하는 값(target)인지 비교 mid 값이 target과 다르다면 대소관계를 비교해 탐색 범위를 좁히고, target과 mid 값이 같을 때까지 아래 조건에 따라 2, 3번 반복 target이 mid보다 작으면 end를 mid 왼쪽 값으로 바꿈 target이 mid보다 크면 start를 mid 오른쪽 값으로 바꿈 코드 def binary_search(target, data): data.sort() start = 0 # 맨 처음 위치 end = len(data) - 1 # 맨 마지막 위치 while start ..
계수정렬(Counting Sort) 계수정렬(Counting Sort) 개념 각 숫자가 몇 개 있는지 개수를 세어 저장한 후에 정렬 기수정렬과 마찬가지로 비교를 하지 않는 알고리즘 양수만 가능, 값의 범위가 제한적 과정 1. 정렬되지 않은 배열의 수들이 각각 몇 번 나왔는지 count 배열에 기록 # 정렬을 수행할 배열 arr = [4, 7, 9, 1, 3, 5, 2, 3, 4] count = [0] * (max(arr) + 1) for num in arr: count[num] += 1 print(count) # [0, 1, 1, 2, 2, 1, 0, 1, 0, 1] 2. count 배열을 앞에서 순회하여 자신이 정렬된 배열에서 몇 번째에 나와야 하는지 기록하기 위해 누적합으로 갱신 for i in range(1, len(count)): ..
기수정렬(Radix Sort) 기수정렬(Radix Sort) 개념 자릿수를 기준으로 정렬하는 알고리즘 비교를 하지 않는 알고리즘 양수만 가능 과정 특징 Least Significant Digit(LSD) 안정정렬 추가적인 메모리 공간 필요 정렬 대상의 모든 길이가 동일해야 효율적 시간 복잡도 O(dN) => N은 데이터의 개수, d는 데이터들의 최대 자리 수 Q. 왜 주로 낮은 자리 수부터 정렬? A. LSD의 경우 10000와 1을 비교할 때, Digit의 갯수만큼 확인 but MSD의 경우 중간에 정렬이 완료되면 더 살펴볼 필요가 없음 LSD의 코드 구현이 MSD에 비해 간결
힙 정렬(Heap Sort) 힙 정렬(Heap Sort) 개념 완전 이진 트리를 기본으로 하는 힙(Heap) 자료구조를 기반으로 한 정렬 방식 최대 힙 트리나 최소 힙 트리를 구성해 정렬 내림차순 정렬을 위해서는 최대 힙 구성, 오름차순 정렬 위해서는 최소 힙 구성 과정 최대 값을 하나씩 뽑아내면서 정렬 코드 # Max Heapify 함수: 특정 인덱스의 노드를 최대 힙 형태로 유지하는 함수 def max_heapify(arr, n, i): largest = i # 부모 노드의 인덱스로 초기화 left = 2 * i + 1 # 왼쪽 자식 노드의 인덱스 right = 2 * i + 2 # 오른쪽 자식 노드의 인덱스 # 왼쪽 자식 노드가 부모 노드보다 크면 largest 값을 갱신 if left < n and arr[largest] <..
병합 정렬(Merge Sort) 병합 정렬(Merge Sort) 개념 분할 정복 알고리즘 주어진 배열을 원소가 하나 밖에 남지 않을 때까지 계속 둘로 쪼갠 후 다시 크기 순으로 재배열 안정 정렬 코드 def merge_sort(arr): if len(arr)
퀵 정렬(Quick Sort) 퀵 정렬(Quick Sort) 개념 불안정 정렬 분할 정복 알고리즘 중 하나로 매우 빠른 속도로 수행 문제를 작은 2개의 문제로 분리 순환 호출을 이용해 구현 리스트 안에 있는 하나의 원소를 pivot으로 설정 pivot을 기준으로 작은 원소들은 모두 왼쪽으로, 큰 요소들은 모두 오른쪽으로 이동 pivot을 제외한 왼쪽 원소들과 오른쪽 원소들을 다시 정렬(순환 호출) 더 이상 분할이 불가능할 때까지 재귀적으로 과정을 반복 과정 pivot을 선택한다. left는 오른쪽으로 가면서 pivot보다 큰 수를 찾는다. right는 왼쪽으로 가면서 pivot보다 작은 수를 찾는다 left와 right을 교환한다. left와 right이 교차하면 pivot과 right을 교환한다. pivot을 기준으로 왼쪽, 오른쪽..
삽입정렬(Insertion Sort) 삽입정렬(Insertion Sort) 개념 자료 배열의 모든 요소를 앞에서부터 차례로 이미 정렬된 배열 부분과 비교해서 자신의 위치를 찾아 삽입 코드 def insertion_sort(arr): for end in range(1, len(arr)): for i in range(end, 0, -1): if arr[i - 1] > arr[i]: arr[i - 1], arr[i] = arr[i], arr[i - 1] 특징 장점 안정한 정렬 데이터가 이미 정렬되어 있는 경우에 효율적 버블 정렬, 선택 정렬에 비해 상대적으로 빠름 in-place sorting 알고리즘 단점 여전히 비교적 많은 레코드들의 이동을 포함 시간 복잡도 최선(Best) 이동 없이 1번의 비교만 행해짐 => O(N) 최악(Worst) 입력..