# docer compose 버전version:"3.7"# docker service 생성services:# nginx container 생성nginx:# nginx image 불러오기image:nginx:1.19.5# nginx가 속할 networknetworks:-network# voluems 정의volumes:# 내가 올린 nginx.conf를 nginx폴더의 nginx.conf와 연결-/home/django_course/nginx.conf:/etc/nginx/nginx.conf# volumes에 저장할 파일들의 경로-static-volume:/data/static-media-volume:/data/media# nginx가 사용할 portsports:-80:80# django container 생성# container name은 nginx.conf에서 hostname과 동일하게 작성django_container_gunicorn:# 위에서 만든 image 불러오기image:django_test_image:5# 장고가 속할 네트워크networks:-network# volumes에 저장할 파일들의 경로volumes:-static-volume:/home/django-pinterest/staticfiles-media-volume:/home/django-pinterest/media# 위에서 저장한 django secrets에서 가져올 파일secrets:-MYSQL_PASSWORD-DJANGO_SECRET_KEY# mariadb container 생성# container name은 djago settings의 host명과 동일하게 작성mariadb:# 사용할 이미지image:mariadb:10.5# 사용할 네트워크networks:-network# volumes에 저장할 db 데이터volumes:-maria-database:/var/lib/mysql# 위에서 저장한 django secrets에서 가져올 파일secrets:-MYSQL_PASSWORD-MYSQL_ROOT_PASSWORD# maria db의 환경변수# docker secrets에서 패스워드 가져오기environment:MYSQL_DATABASE:djangoMYSQL_USER:djangoMYSQL_PASSWORD_FILE:/run/secrets/MYSQL_PASSWORDMYSQL_ROOT_PASSWORD_FILE:/run/secrets/MYSQL_ROOT_PASSWORD# 사용할 네트워크networks:network:# 사용할 volumevolumes:static-volume:media-volume:maria-database:# 사용할 secretssecrets:DJANGO_SECRET_KEY:external:trueMYSQL_PASSWORD:external:trueMYSQL_ROOT_PASSWORD:external:true
#행(row)이 3개인 2차원 리스트로 인접 리스트 표현graph =[[] for _ in range(3)]
#노드 0에 연결된 노드 정보 저장 (노드,거리)graph[0].append((1,7))
graph[0].append((2,5))
#노드 1에 연결된 노드 정보 저장 (노드,거리)graph[1].append((0,7))
#노드 2에 연결된 노드 정보 저장 (노드,거리)graph[2].append((0,5))
DFS 알고리즘
특정한 경로로 탐색하다가 특정한 상황에서 최대한 깊숙이 들어가서 노드를 방문한 후 다시 돌아가 다른 경로로 탐색하는 알고리즘
동작 과정
탐색 시작 노드를 스택에 삽입하고 방문 처리
스택의 최상단 노드에 방문하지 않은 인접 노드가 있으면 그 인접 노드를 스택에 넣고 방문 처리한다. 방문하지 않은 인접 노드가 없으면 스택에서 최상단 노드를 꺼낸다.
1,2번의 과정을 더 이상 수행할 수 없을 때까지 반복
예시
노드 1을 시작 노드로 설정하여 DFS를 이용해 탐색 진행인접한 노드 중에서 방문하지 않은 노드가 여러 개 있으면 번호가 낮은 순서부터 처리
1.시작 노드인 1을 스택에 삽입하고 방문 처리 2.노드 1에 인접 노드 2,3,8이 있다. 이 중 가장 작은 노드인 2를 스택 삽입 3.노드 2의 인접 노드 7 스택 삽입 4.노드 7의 인접 노드 8,6 중 작은 노드인 6 스택 삽입 5.노드 6의 인접 노드가 없으므로 스택에서 노드 6을 꺼냄 6.노드 7에서 방문하지 않은 인접 노드 8을 스택에 삽입 7.노드 8의 인접 노드가 없으므로 노드 8을 스택에서 꺼냄 8.노드 7의 인접 노드가 없으므로 노드 7을 스택에서 꺼냄 9.위와 동일 노드 2 꺼냄 10.노드 1의 인접 노드 3을 스택에 삽입 11.노드 3의 인접 노드 4,5 중 작은 4를 스택에 삽입 12.노드 4의 인접노드가 없으므로 노드 4를 스택에서 꺼냄 13.노드 3의 인접 노드 5를 스택에 삽입 14. 남아 있는 노드에 방문하지 않은 인접 노드가 없다. 따라서 모든 노드를 차래대로 꺼낸다.
결과 : 노드의 탐색 순서(스택에 들어간 순서)
1 -> 2 -> 7 -> 6 -> 8 -> 3 -> 4 -> 5
구현
#DFS 메서드 정의defdfs(graph, v, visited):# 현재 노드를 방문 처리
visited[v] = Trueprint(v end=' ')
# 현재 노드와 연결된 다른 노드를 재귀적으로 방문for i in graph[v]:
ifnot visited[i]:
dfs(graph, i, visited)
# 각 노드가 연결된 정보를 리스트 자료형으로 표현(2차원 리스트)
graph = [
[],
[2,3,8],
[1,7],
[1,4,5],
[3,5],
[3,4],
[7],
[2,6,8],
[1,7]
]
# 각 노드가 방문된 정보를 리스트 자료형으로 표현 (1차원 리스트)
visited = [False] * 9# 정의된 DFS 함수 호출
dfs(graph, 1, visited)
# 결과# 1 2 7 6 8 3 4 5
BFS Breadth First Search
너비 우선 탐색
가까운 노드부터 탐색하는 알고리즘
인접한 노드를 반복적으로 큐에 넣도록 알고리즘을 작성하면 자연스럽게 먼저 들어온 것이 먼저 나가게 되어 가까운 노드부터 탐색을 진행하게 된다.
동작과정
탐색 시작 노드를 큐에 삽입하고 방문 처리
큐에서 노드를 꺼내 해당 노드의 인접 노드 중에서 방문하지 않은 노드를 모두 큐에 삽입하고 방문 처리
1,2의 과정을 반복
예시
시작 노드인 1을 큐에 삽입하고 방문처리
큐에서 노드 1을 꺼내고 방문하지 않은 인접 노드 2, 3, 8을 모두 큐에 삽입하고 방문 처리
큐에서 노드 2를 꺼내고 방문하지 않은 인접 노드 7을 큐에 삽입하고 방문 처리
큐에서 노드 3을 꺼내고 방문하지 않은 인접 노드 4, 5를 모두 큐에 삽입하고 방문 처리
큐에서 노드 8을 꺼내고 방문하지 않은 인접 노드가 없으므로 무시
큐에서 노드 7을 꺼내고 방문하지 않은 인접 노드 6을 큐에 삽입하고 방문 처리
남아 있는 노드에 방문하지 않은 인접 노드가 없으므로 모든 노드를 차례대로 꺼냄
결과 : 노드의 탐색 순서(큐에 들어간 순서)
1 -> 2 -> 3 -> 8 -> 7 -> 4 -> 5 -> 6
구현
from collections import deque
# BFS 메서드 정의defbfs(graph, start, visited):# 큐 구현을 위해 deque 라이브러리 사용
queue = deque([start])
# 현재 노드를 방문 처리
visited[start] = True# 큐가 빌 때까지 반복while queue:
# 큐에서 하나의 원소를 뽑아 출력
v = queue.popleft()
print(v, end=' ')
# 해당 원소와 연결된, 아직 방문하지 않은 원소들을 큐에 삽입for i in graph[v]:
ifnot visited[i]:
queue.append(i)
visited[i] = True# 각 노드가 연결된 정보를 리스트 자료형으로 표현 (2차원 리스트)
graph = [
[],
[2,3,8],
[1,7],
[1,4,5],
[3,5],
[3,4],
[7],
[2,6,8],
[1,7]
]
# 각 ㄴ드가 방문된 정보를 리스트 자료형으로 표현 (1차원 리스트)
visited = [False] * 9# 정의된 BFS 함수 호출
bfs(graph, 1, visited)
# 결과# 1 2 3 8 7 4 5 6
#스택 선언
stack = []
#스택에 5 추가
stack.append(5)
#스택에 가장 최근에 추가된 항목 삭제
stack.pop()
큐 Queue
선입선출 구조
대기 줄에 비유
먼저 온 사람이 먼저 들어가고 나중에 온 사람이 나중에 들어감
라이브러리 사용하기
collections 의 deque
from collections import deque
예제
from collections import deque
#Queue 구현을 위해 deque 라이브러리 사용 queue = deque() #삽입 queue.append(5) #삭제 (먼저 삽입된 자료부터 삭제) queue.popleft()
#먼저 삽입된 순서대로 출력 print(queue) #다음 출력을 위해 역순으로 바꾸기 queue.reverse() #나중에 들어온 원소부터 출력 print(queue) #리스트 자료형으로 변환 list(queue)
<br/><br/>
# 재귀함수
> 자기자신을 다시 호출하는 함수
### 예시
```Python
defrecursive_function():print('재귀함수를 호출합니다.')
recursive_function()
recursive_function()
주의사항
재귀 함수가 언제 끝날지 종료 조건을 꼭 명시
참고
재귀 함수는 내부적으로 스택 자료 구조와 동일
팩토리얼을 통한 반복문과 재귀함수 비교
# 반복문deffactorial_iterative(n):
result = 1# 1부터 n까지의 수를 차례대로 곱하기for i inrange(1, n+1):
result *= i
return result
# 재귀적으로 구현deffactorial_recursive(n):# n이 1 이하인 경우 1을 반환if n <= 1:
return1# n! = n * (n-1)!를 그대로 코드로 작성return n * factorial_recursive(n-1)