정열이 되어 있다는 가정하에 순차적으로 탐색하지 않고, 중간을 탐색해서 어디에 있는지 판단하는 방식
분할 정복 알고리즘과 이진 탐색
분할 정복 알고리즘 : Divide(문제를 하나 또는 둘 이상으로 분할), Conquer(나눠진 문제가 충분히 작고, 해결가능하면 해결하고 그렇지 않으면 다시 분할함)
이진 탐색:
Divide : 리스트를 두 개의 서브 리스트로 나눔
Conquer :
검색할 숫자 > 중간값 -> 뒷부분의 서브 리스트에서 검색할 숫자를 찾음
검색할 숫자 < 중간값 -> 앞부분의 서브 리스트에서 검색할 숫자를 찾음
이진 탐색도 분할 정복 알고리즘에 해당하므로, 전형적으로 재귀함수를 활용하여 구현할 수 있음
알고리즘 고안
데이터가 일단, 정렬되어 있는 상태
데이터 리스트와, 검색할 데이터를 인자로 받아 해당 함수를 구현
알고리즘 구현
def binary_search(data, search):
if len(data) == 1 and search == data[0]: # 최종적으로 1개의 데이터인 경우 비교 데이터와 비교
return True
if len(data) == 1 and search != data[0]:
return False
if len(data) == 0:
return False
medium = len(data) // 2 # 몫을 구하면 중간 인덱스를 구할 수 있음
if search == data[medium]:
return True
else:
if search > data[medium]:
return binary_search(data[medium:], search)
else:
return binary_search(data[:medium], search)
# TEST
import random
data_list = random.sample(range(100), 10)
data_list.sort() # 정렬이 필요 하므로, list 내장 함수 sort()를 사용
# [10, 11, 18, 36, 42, 65, 68, 69, 71, 89]
binary_search(data_list, 66)
# [10, 11, 18, 36, 42, 65, 68, 69, 71, 89]
# [68, 69, 71, 89]
# [68, 69]
# [68]
# False
이진 탐색의 시간 복잡도
한번 처리하는 과정(1턴)에서, 전체의 데이터가 1/2씩 줄어 들고 데이터가 1개가 될 때 까지 이를 반복
1턴에 1번 밖에 처리 안함(안에 반복문은 없음)
데이터의 개수가 1이 될때 까지 반복 이니까, 턴의 개수는 log n 번
n _ (1/2) _ (1/2) _ (1/2) _ ... = 1
n * (1/2)^k = 1 (1일 될 때까지 k 번 반복)
n = 2^k
log n = k
O(log n)
Sequential Search (순차 탐색)
탐색은 여러 데이터 중에서 원하는 데이터를 찾아내는 것을 의미
데이터가 담겨있는 리스트를 앞에서 부터 하나씩 비교해서 원하는 데이터를 찾는 방법
프로그래밍 연습
임의 리스트 존재시 원하는 데이터의 위치를 return 하는 순차탐색 알고리즘 작성하기
from random import *
rand_data_list = list()
for num in range(10):
rand_data_list.append(randint(1, 100)) # 1 ~ 100 의 int를 10회 수행
print(rand_data_list)
# [71, 63, 75, 33, 6, 37, 81, 79, 3, 29] 중복된 숫자도 가능함
def sequential(data_list, search_data):
for i in range(len(data_list)):
if data_list[i] == search_data:
return i
return -1
# TEST
sequential(rand_data_list, 37) # 5
sequential(rand_data_list, 3) # -1
순차 탐색의 시간 복잡도
최악의 경우 list 길이가 n일 때, n번 비교해야함
O(n)
그래프(Graph) 이해
그래프는 실제 세계의 현상이나 사물을 정점(Vertex) 또는 노드(Nord) 와 간선(Edge)로 표현하기 위해 사용
예제) 집에서 회사로 가는 경로를 그래프로 표현
용어
노드 (Node): 위치를 말함, 정점(Vertex)라고도 함
간선 (Edge): 위치 간의 관계를 표시한 선으로 노드를 연결한 선이라고 보면 됨 (link or branch라고도 함)
인접 정점 (Adjacent Vertex): 간선으로 직접 연결된 정점(또는 노드), 인접노드
참고 용어
무방향 그래프: 간선이 방향이 없는 경우
방향 그래프: 간선이 방향이 있는 경우
정점의 차수 (Degree): 무방향 그래프에서 하나의 정점에 인접한 정점의 수 (특정 노드에 무방향으로 연결된 노드의 수)
진입 차수(In-Degree): 방향 그래프에서 외부에서 오는 간선의 수(자기 노드에서 몇개의 간선을 받느냐)
진출 차수(Out-Degree): 방향 그래프에서 외부로 향하는 간선의 수(자기 노드에서 몇개의 간선을 보내냐)
경로 길이 (Path Length): 경로를 구성하기 위해 사용된 간선의 수
단순 경로 (Simple Path): 처음 정점과 끝 정점을 제외하고 중복된 정점이 없는 경로(경로 중에 중복된 정점을 가진 경로를 제외한 것, 즉, Start, End가 동일한 경우를 제외하고 중복된 정점을 가지지 않은 경로)
사이클 (Cycle): 단순 경로의 시작 정점과 종료 정점이 동일한 경우
단순 경로는 사이클 일 수 있다, 사이클은 단순 경로이다.
그래프의 종류
무방향 그래프 (Undirected Graph)
간선에 방향이 없는 그래프
간선을 통해, 노드는 양방향으로 갈 수 있음
보통 노드 A, B가 연결 되어 있을 경우, (A, B), (B, A) 로 표기
방향 그래프 (Directed Graph)
간선에 방향이 있는 그래프
간선을 통해, 노드는 지정된 방향으로만 갈 수 있음
보통 노드 A, B가 연결 되어 있을 경우,
A -> B: <A, B> 로 표기
B -> A: <B, A> 로 표기
순서가 있음을 주의 하자
가중치 그래프 (Weighted Graph) 또는 네트워크(Network)
간선에 비용 또는 가중치가 할당된 그래프
그림에서는 간선 위에 숫자를 적어 표현
거리가 될수도 있고, 그런 간선간의 차이를 표현할 수 있음
연결 그래프 (Connected Graph)와 비연결 그래프 (Disconnected Graph)
연결 그래프
일단 무방향 그래프 이어야 함
무방향 그래프에 있는 모든 노드에 대해 항상 경로가 존재하는 경우
모든 노드가 어느 하나라도 연결 되어 있어 접근이 가능한 경우를 말함, 하나에 모두 연결(완전 그래프)이 아님
비연결 그래프
무방향 그래프에서 특정 노드에 대해 경로가 존재하지 않는 경우
사이클(Cycle)과 비순환 그래프(Acyclic Graph)
사이클
단순 경로의 시작 노드와 종료 노드가 동일한 경우
비순환 그래프
사이클이 없는 그래프
완전 그래프 (Complete Graph)
그래프의 모든 노드가 서로 연결되어 있는 그래프
각각의 노드가 모든 노드로 바로 연결 되어 있음
그래프와 트리의 차이
트리는 그래프 중에 속한 특별한 종류임
그래프 ⊃ 트리
항목\종류
그래프
트리
정의
노드와 노드를 연결하는 간선으로 표현되는 자료구조
그래프의 한종류, 방향성이 있는 비순환 그래프
방향성
O (방향, 무방향 모두 가능)
O (방향 그래프만 가능)
사이클
O (순환, 비순환 모두 가능)
X (비순환만 가능)
루트 노드
X (루트 노드를 정의하고 있지 않지만, 스스로 추가는 가능)
O (루트 노드를 정의하고 있음)
부모/자식 관계
X (부모자식 정의하고 있지 않지만, 스스로 추가는 가능)
O (부모 자식 관계 존재)
BFS (Breadth-First Search, 너비 우선 탐색)
BFS 와 DFS
대표적인 그래프 탐색 알고리즘
너비 우선 탐색(Breadth First Search, BFS): 정점들과 같은 레벨에 있는 노드들(형제 노드들)을 먼저 탐색하는 방식
깊이 우선방식(Depth First Search, DFS): 정점의 자식들을 먼저 탐색하는 방식
둘다, 약간 트리같은 사이클이 없는 그래프에서 탐색
BFS/DFS 방식 이해를 위한 예제
BFS : 한 단계씩 내려가면서, 해당 노드와 같은 레벨있는 노드 먼저 순회
가로 방향의 지그재그
DFS : 한 노드의 자식을 타고 끝까지 순회한 후, 다시 돌아와서 다른 형제들의 자식을 타고 내려가며 순회
세로 방향의 지그재그
Python으로 그래프를 표현하는 방법
파이썬에서 제공하는 딕셔너리와 리스트 자료구조 활용하여 그래프 표현
딕셔너리의 key - values 구조 item을 노드로 활용하여, key는 해당 DATA를 표현하고 values는 해당 노드에 연결된 노드를 가르키게 함