본문 바로가기
반응형

Computer Science/알고리즘21

다익스트라 알고리즘(Dijkstra Algorith) 이번에 배워볼 알고리즘은 그래프에서 최단 경로를 찾기 위한 알고리즘 중 하나인 다익스트라 알고리즘(Dijkstra Algorith)이다. 다익스트라 알고리즘은 한 정점에서 나머지 모든 정점으로 가는 최단 경로를 구할 수 있는 알고리즘이다. 단, 그래프 내에 음의 간선(경로)이 존재한다면 다익스트라 알고리즘을 적용할 수가 없다. 다익스트라 알고리즘은 다이나믹 프로그래밍, 그리디 알고리즘으로 분류된다. 이전에 구했던 최단 경로 정보를 이용하기 때문에 다이나믹 프로그래밍이라고 불리며, 가장 최단 경로인 간선을 선택하기 때문에 그리디 알고리즘이라고 불린다. ​ 다익스트라 알고리즘의 동작원리는 다음과 같다. 시작 정점을 선택한다. 시작 정점을 기준으로 다른 정점으로 가는 비용을 저장한다. 현재 방문하지 않는 정점.. 2021. 7. 3.
너비 우선 탐색(Breadth First Search) : BFS 이번에 배워볼 알고리즘은 너비 우선 탐색(Breadth First Search)이다. 줄여서 흔히 BFS라고 부른다. 깊이 우선 탐색은 깊이를 우선시하였다면 너비 우선 탐색은 너비를 우선시하는 탐색 방법이다. 또한, 노드에서 다른 노드로 가는 최단 경로를 구할 때 깊이 우선 탐색은 한 노드의 끝까지 탐색하기 때문에 최단 경로를 보장해 주지 않지만 너비 우선 탐색은 항상 같은 깊이 내에 있는 모든 노드들을 탐색하기 때문에 최단 경로를 보장해 준다는 장점이 있다. ​깊이 우선 탐색은 스택(Stack)을 이용하여 구현하였다면, 너비 우선 탐색은 큐(Queue)를 이용해서 구현한다. ​ 너비 우선 탐색의 원리는 다음과 같다. 큐에서 노드 하나를 꺼낸다. 큐에서 꺼낸 노드에 인접한 노드들 중 아직 방문하지 않은 .. 2021. 7. 2.
깊이 우선 탐색(Depth First Search) : DFS 그래프의 모든 정점들을 방문하는 방법은 크게 두 가지가 있다. 이번에 배워볼 알고리즘은 그중 하나인 깊이 우선 탐색(Depth First Search)이다. 줄여서 흔히 DFS라고 부른다. 이 알고리즘은 깊이 우선 탐색이란 말 그대로 깊이(Depth)를 우선순위로 두고 탐색을 하겠다는 의미이다. ​깊이 우선 탐색은 스택(Stack)을 이용해서 구현한다. 또한, 컴퓨터는 구조적으로 함수를 호출할 때 스택의 원리를 이용하기 때문에 스택을 선언하여 사용하지 않고 재귀적 함수 호출로 구현할 수도 있다. 필자는 재귀적인 구현이 훨씬 간단하고 직관적이기 때문에 보통 재귀적으로 구현을 많이 하는 편이다. 다만, 과도한 재귀 함수 호출은 스택에 함수가 계속 쌓이게 되면서 메모리에 많은 부담을 주기 때문에 이런 경우는 .. 2021. 7. 2.
Lower_bound & Upper_bound 이전에 배운 이분 탐색(Binary Search)은 리스트 내에 찾고자 하는 Key 값이 있을 때만 위치를 반환하고 만약 Key 값이 존재하지 않는다면 아무것도 반환을 하지 않았다. 또한, Key 값이 중복된 경우 정확히 우리가 원하는 Key의 위치를 얻을 수가 없었다. 따라서 Key 값이 존재하지 않더라도 Key에 가장 가까운 원소의 위치를 찾아야 하거나, 중복된 Key 값의 범위, 중복 값을 활용하는 등의 문제를 해결하기 위해선 이분 탐색은 한계가 있다. 이를 위해 이분 탐색을 응용한 두 개의 알고리즘이 존재한다. 당연한 말이지만 이분 탐색을 응용하는 알고리즘이기 때문에 리스트는 정렬이 되어있어야 한다. ​ 첫 번째는 Lower_bound라는 알고리즘이다. Lower_bound는 하한선이라는 뜻으로 .. 2021. 7. 2.
이분 탐색(Binary Search) 데이터가 담긴 리스트를 탐색하는 방법은 크게 순차 탐색(Linear Search)과 이분 탐색(Binary Search)이 존재한다. 예를 들어 { 8, 3, 1, 5, 4, 7, 9, 2, 6, 10}, 10개의 데이터가 담긴 리스트가 있다고 하자. 이 리스트에서 9의 위치를 찾기 위해서는 어떻게 해야 할까? 위 리스트처럼 정렬되지 않은 리스트에서 데이터를 탐색하기 위해서는 어쩔 수 없이 처음부터 끝까지 순차적으로 탐색을 진행하여 9의 위치를 찾는 방법밖에 없을 것이다. ​그렇다면 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}처럼 정렬된 리스트가 있다고 생각해 보자. 이 리스트에서도 9의 위치를 찾기 위해서는 어떻게 해야 할까? 단순하게는 앞서 언급한 방법처럼 처음부터 순차적으로 9의 인덱스.. 2021. 7. 2.
기수 정렬(Radix Sort) 이번에 배워볼 정렬 알고리즘은 기수 정렬(Radix Sort)이다. 지금까지 배워온 정렬들은 모두 데이터들을 비교하여 정렬하는 방식이었다. 기수 정렬은 이와는 다르게 데이터를 비교하지 않고 정렬하는 조금 특수한 정렬 알고리즘이다. 기수 정렬은 O(dn)의 시간 복잡도를 가질 정도로 매우 빠른 정렬 알고리즘이다. 여기서 d는 데이터의 자릿수이다. ​ 기수 정렬은 아쉽게도 추가적인 메모리를 필요로 하며, 정렬할 수 있는 데이터 타입이 제한된다는 단점이 있다. 기수 정렬을 사용하기 위해선 데이터의 값들이 동일한 길이를 가지는 숫자나 문자열로 구성되어 있어야 한다. ​그렇다면 0~99 사이의 숫자들로 이루어진 배열을 정렬하는 과정을 살펴보자. 간단하게 100개의 배열을 생성하여 각 인덱스에 저장하여 출력하는 방.. 2021. 7. 1.
힙 정렬(Heap Sort) 이번에 배워볼 정렬 알고리즘은 힙 정렬(Heap Sort)이다. 이전에 우선순위 큐를 공부할 때 힙 자료구조에 대해서 공부하였다. 힙 자료구조는 우선순위 큐를 완전 이진 트리로 구현하는 방법으로 삽입, 삭제 연산이 O(logN)이라는 빠른 시간에 가능하기 때문에 최대, 최소 등 자신이 원하는 조건에 맞는 데이터를 정렬을 유지한 상태로 빠르게 뽑아낼 수 있는 훌륭한 자료구조였다. 힙의 특성을 활용하여 원하는 기준의 원소부터 차례대로 추출하는 방법을 힙 정렬이라 한다. 예를들어 오름차순으로 데이터를 정렬하려고 한다면 최소 힙을 구현하고 원소들을 아무렇게나 차례대로 삽입한 다음, 루트 노드(최솟값)를 데이터 개수만큼 삭제를 통해 뽑아내서 나열하면 원소들이 오름차순으로 정렬된 것을 확인할 수 있다. ​ 힙 정렬.. 2021. 7. 1.
퀵 정렬(Quick Sort) 이번에 배워볼 정렬 알고리즘은 퀵 정렬(Quick Sort)이다. 퀵 정렬은 평균적으로 매우 빠른 수행 속도를 자랑하는 정렬 방법이다. 퀵 정렬도 앞서 배운 합병 정렬처럼 분할 정복(Divide and Conquer) 방법에 근거한다. 하지만 합병 정렬은 항상 리스트를 절반으로 균등하게 나누는 반면에, 퀵 정렬은 피벗(Pivot)이라는 것을 사용하여 비균등하게 분할한다. 피벗을 기준으로 좌측에는 크기가 작은 요소, 우측에는 크기가 큰 요소들을 옮기면서 분할한다. Mid를 기준으로 좌, 우측으로 분할하는 합병 정렬과 조금 차이가 있다. 피벗을 기준으로 분할된 상태에서 피벗을 제외한 좌측, 우측 요소들을 정렬하면 정렬된 리스트를 얻게 된다. 그럼 퀵 정렬은 분할된 상태에서 어떤 방법으로 리스트를 정렬할까? .. 2021. 7. 1.
합병 정렬(Merge Sort) 이번에 배워볼 정렬 알고리즘은 합병 정렬(Merge Sort)이다. 이전까지 배운 정렬들은 최악의 경우 시간 복잡도가 O(N^2)이지만, 합병 정렬은 이와 다르게 최선, 평균, 최악 모든 경우가 O(N logN)의 시간 복잡도를 가지는 빠른 정렬 알고리즘이다. 합병 정렬은 하나의 리스트를 두 개의 균등한 크기로 분할하고 분할된 부분 리스트를 정렬한 다음, 두 개의 정렬된 부분 리스트를 합하여 전체가 정렬된 리스트가 되게 하는 방법이다. 합병 정렬은 분할 정복(Divide and Conquer) 방법에 바탕을 두고 있다. 분할 정복 방법은 문제를 작은 2개의 문제로 분리하고 각각을 해결한 다음, 결과를 모아서 원래의 문제를 해결하는 전략이다. ​ 합병 정렬은 다음의 단계들로 이루어진다. 분할(Divide).. 2021. 7. 1.
반응형