Array
Linked List
결론
Stack
Queue
두개의 스택으로 큐 구현(파이썬)
stack1 = []
stack2 = []
next_pop = 1 # 다음번에 pop할 stack
next_push = 1 # 다음번에 push할 stack
def push(num):
global next_push
if next_push == 1:
stack1.append(num)
next_push = 2
else:
stack2.append(num)
next_push = 1
def pop():
global next_pop
if next_pop == 1:
s1 = stack1
s2 = stack2
else:
s1 = stack2
s2 = stack1
if len(s1) == 0:
return -1
size = len(s1) - 1
while len(s1) > 1:
s2.append(s1.pop())
res = s1.pop()
while len(s1) < size:
s1.append(s2.pop())
if next_pop == 1:
next_pop = 2
else:
next_pop = 1
return res
turn = 1
while True:
command = input().split()
if command[0] == 'push':
num = int(command[1])
push(num)
elif command[0] == 'pop':
print(pop())
루트 노드를 중심으로 두개의 서브 트리, 나눠진 두 서브 트리도 모두 이진 트리여야 한다.
포화(full) 이진 트리 : 모든 level이 꽉 찬 트리
완전(complete) 이진 트리 : 왼쪽에서 오른쪽으로 순서대로 차곡차곡 채워진 이진 트리
순회 : 항상 부모 노드를 기준으로 생각한다.
우선순위 큐를 위해 만들어졌다.
우선순위 큐
삽입 O(log N), 삭제 O(log N)
배열 기반 완전 이진 트리
최댓값, 최솟값을 찾아내는 데에 유용하다
index 1부터 사용한다. i번째 노드에 대해 왼쪽 자식은 i*2, 오른쪽 자식은 i*2 + 1
최대힙은 각 노드의 값이 자식 노드의 값보다 크거나 같은 완전 이진 트리, 최소힙은 반대
최대힙에서 최댓값을 찾는 시간복잡도는 O(1)
중복된 값을 허용한다
최대 힙 삽입 구현
heapSize를 1증가, 마지막 노드에 x삽입
for i = heapSize to i = 2 do
if i번째 노드가 부모 노드(index i//2인 노드)보다 크다
then 두 값을 교환한다.
else for문을 중단한다
endif
endfor
heap이 비어있으면 -1을 return
root = heap[1] # 루트 노드 값을 저장
heap[1] 에 마지막 노드를 삽입하고, heapSize 1감소
i = 1
while i번째 노드의 자식 노드가 존재
if i번째 노드 값이 자식 노드들 값보다 큼
then while문 중단
if 왼쪽 child 노드가 i번째 노드보다 큼
then 왼쪽 child 노드와 i번째 노드 swap하고 i = 왼쪽 child 노드의 인덱스로 변경
else 오른쪽 child 노드와 i번째 노드 swap하고 i = 오른쪽 child 노드의 인덱스로 변경
endwhile
원래 루트 노드 값이었던 root을 return
이진 탐색 + 연결 리스트
이진 트리의 일종, 각 노드의 왼쪽 서브트리에는 해당 노드의 값보다 작은 값들만, 오른쪽 서브트리에는 해당 노드보다 큰 값의 노드들로만 이루어진다.
중위 순회 방식 이용
탐색 시간 복잡도는 평균적으로 O(logN)이지만 최악의 경우 편향 트리가 되어 O(N)
중복이 없어야 되는 이유? 검색을 목적으로 하기 때문, 노드가 많을 수록 검색 속도가 저하된다. 노드에 count 변수를 추가하는 것이 효율적
구현하기(파이썬)
class Node:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
class BST:
def __init__(self, root):
self.root = root
# 노드 삽입
def insert(self, value):
self.current_node = self.root
while True:
if value < self.current_node.value:
if self.current_node.left == None:
self.current_node.left = Node(value)
break
else:
self.current_node = self.current_node.left
else:
if self.current_node.right == None:
self.current_node.right = Node(value)
break
else:
self.current_node = self.current_node.right
# 노드 탐색
def search(self, value):
self.current_node = self.root
while self.current_node:
if self.current_node == value:
return True
elif self.current_node < value:
self.current_node = self.current_node.right
else:
self.current_node = self.current_node.left
return False
노드 삭제는 귀찮아서 설명으로 대체
None
으로 변경)# target_node(삭제하려는 노드가) 자식 노드를 두개 가질 경우 target_node를 제거하는 코드
target_node = 삭제하려는 노드
change_node = 삭제하려는 노드의 right child
change_node_parent = target_node
# right child 중 가장 왼쪽의 노드를 찾아주기
while change_node의 왼쪽 child가 존재
change_node를 왼쪽 child로 바꾸고
change_node_parent를 change_node로 바꿔준다
if change_node에 오른쪽 child가 존재
then change_node_parent에 오른쪽 child를 넣어주기
else change_node_parent의 왼쪽 child를 제거
target_node의 자리에 change_node를 넣어주기
Undirected Graph에서 각 정점에 연결된 edge의 개수를 degree라고 한다.
spanning tree
: 그래프 G의 모든 정점이 cycle 없이 연결된 형태
그래프 G의 spanning tree 중 edge의 가중치 합이 최소인 spanning tree를 지칭한다
크루스칼 알고리즘 : weight가 가장 작은 edge부터 차례대로 추가하는 것. spanning tree 조건을 만족시키기 위하여 cycle이 생기지 않는 경우에만 edge를 추가하고, 모든 정점이 연결되면 탐색을 끝낸다.
Union-Find Disjoint set(서로소인 집합들로 나눠진 원소들에 대한 자료구조)를 표현할 때 사용하는 알고리즘이다. 두 집합을 합치는
union
, x가 속한 집합의 대표값을 반환하는find
로 구성된다.
Prim 알고리즘 : 하나의 vertex로 이루어진 초기 그래프 A를 구성한다. 선택한 간선의 정점으로부터 가장 낮은 가중치를 갖는 정점을 선택하고, 모든 정점이 선택될때까지 반복한다.
minWeight[]
: 트리와 이 정점을 연결하는 간선의 최소 가중치. 트리에 정점을 추가할때마다 인접한 간선을 순회하면서 갱신한다.
# 해당 정점이 트리에 포함되어있는지를 저장할 배열
added를 정점개수 * [False]로 정의
# 트리에 인접한 간선 중 해당 점점에 닿는 최소 간선의 정보
minWeight = 정점개수 * INF
minWeight[0] = 0
for (i = 0) to 정점개수-1 do
트리에 포함되지 않은 정점들 중 minWeight가 가장 작은 정점(u)을 찾는다.
새로운 정점 u를 트리에 추가한다
u와 연결된 간선들에 대하여 minWeight를 갱신한다.