[자료구조] 12.고급정렬
12장 고급 정렬
큐(Queue)는 선입선출(FIFO, First-In-First-Out) 구조를 가지고 있습니다. 즉, 먼저 들어온 데이터가 먼저 나가게 되는 자료구조입니다. 이러한 특성 때문에, 큐는 많은 분야에서 활용됩니다.
큐는 자체적으로 하나의 추상 자료형(Abstract Data Type)으로 정의됩니다. 추상 자료형은 데이터와 그 데이터에 대한 연산을 결합한 자료형으로, 구현 방법에 따라서 리스트, 배열, 집합 등 다양한 형태로 구현될 수 있습니다.
선형 큐(Linear Queue)는 배열을 이용하여 구현된 큐입니다. 선형 큐에서는 큐의 front와 rear를 각각 배열의 인덱스로 나타내고, 데이터가 들어올 때마다 rear 인덱스를 증가시키고, 데이터가 나갈 때마다 front 인덱스를 증가시킵니다. 선형 큐는 간단하고 구현하기 쉽기 때문에 많이 사용되지만, 몇 가지 문제점이 있습니다.
선형 큐에서는 배열의 크기를 미리 정해야 합니다. 큐의 크기를 초과하면, 새로운 데이터를 삽입할 수 없게 됩니다.
선형 큐에서는 rear 인덱스가 배열의 끝에 도달하면, 새로운 데이터를 삽입할 수 없게 됩니다. 하지만, front 인덱스가 배열의 처음에 위치해 있을 때, 큐의 앞부분에 빈 공간이 있어도 이를 활용할 수 없습니다. 이러한 경우에는, 큐의 크기가 크더라도 실제로 저장 가능한 데이터의 수가 제한됩니다.
선형 큐에서는 front와 rear 인덱스를 이용하여 큐의 빈 공간과 꽉 찬 상태를 구분합니다. 하지만, front와 rear 인덱스가 같은 경우, 큐가 비어있는지 꽉 찬 상태인지 구분할 수 없습니다.
위와 같은 문제점을 해결하기 위해, 원형 큐(Circular Queue)와 연결 큐(Linked Queue)가 개발되었습니다. 여기서는 원형 큐에 대해 다루겠습니다.
원형 큐(Circular Queue)는 배열을 이용하여 구현된 큐의 한 종류로, 큐의 처음과 끝이 연결된 형태로 구현됩니다. 따라서, rear 인덱스가 배열의 끝에 도달하면, 다시 배열의 처음으로 돌아가서 데이터를 삽입할 수 있습니다. 이를 통해, 큐의 크기를 미리 정해놓지 않아도 되고, 빈 공간을 활용할 수 있습니다.
원형 큐에서는 front와 rear 인덱스를 이용하여 큐의 빈 공간과 꽉 찬 상태를 구분합니다. front와 rear 인덱스가 같은 경우, 큐가 비어있는지 꽉 찬 상태인지 구분할 수 없습니다. 따라서, 큐가 비어있는지 구분하기 위해서는, front와 rear 인덱스를 같은 값으로 설정하지 않고, front 인덱스와 rear 인덱스 사이에 최소한 한 개의 빈 공간을 유지해야 합니다.
원형 큐에서는 삽입 연산과 삭제 연산을 수행할 때, front와 rear 인덱스를 적절하게 조절해주어야 합니다. 데이터를 삽입할 때는, rear 인덱스를 증가시키고, 데이터를 삭제할 때는, front 인덱스를 증가시킵니다.
원형 큐는 선형 큐에 비해 데이터를 더 효율적으로 활용할 수 있으며, 큐의 크기를 동적으로 조절할 수 있는 장점이 있습니다. 하지만, front와 rear 인덱스를 적절하게 조절해주어야 하기 때문에 구현이 복잡해질 수 있습니다.
덱(Deque, Double-Ended Queue)은 양쪽 끝에서 삽입과 삭제가 모두 가능한 자료구조입니다. 따라서, 덱은 큐와 스택의 특성을 모두 가지고 있습니다. 덱은 선형 구조를 가지고 있으며, 데이터를 한쪽에서 삽입하고, 다른 한쪽에서 삭제할 수 있습니다.
덱의 가장 큰 단점은 데이터를 삽입하거나 삭제할 때, 덱의 양쪽 모두에서 이를 수행할 수 있기 때문에, 덱에 데이터가 충분히 많은 경우에는 데이터를 찾아내는 것이 어려울 수 있다는 점입니다. 이를 해결하기 위해서는 이중 연결 리스트(Double-Linked List)를 이용하여 덱을 구현할 수 있습니다.
이중 연결 리스트는 각 노드가 이전 노드와 다음 노드를 모두 가리키는 구조로, 덱의 양쪽 끝을 가리키는 front와 rear 포인터를 이용하여 덱을 구현합니다. 이를 통해, 덱의 양쪽에서 삽입과 삭제를 수행할 때도, 해당 위치를 빠르게 찾아내어 삽입과 삭제를 수행할 수 있습니다.
하지만, 이중 연결 리스트를 이용하여 덱을 구현하는 경우에는 추가적인 메모리 공간이 필요하고, 덱의 구현이 복잡해지기 때문에, 사용하는 상황에 따라 적합한 자료구조를 선택해야 합니다.
우선순위 큐(Priority Queue)는 큐(Queue)의 일종으로, 각각의 요소(Element)가 우선순위를 가지고 있어, 우선순위가 높은 요소가 먼저 처리되는 자료구조입니다. 즉, 큐의 요소가 정렬되어 있는 상태로 삽입되고, 가장 우선순위가 높은 요소가 먼저 삭제됩니다.
우선순위 큐는 다음과 같은 기본 연산을 가지고 있습니다.
우선순위 큐는 여러 분야에서 활용되며, 힙(Heap) 자료구조를 이용하여 구현됩니다. 힙은 이진 트리(Binary Tree)의 일종으로, 부모 노드의 우선순위가 항상 자식 노드의 우선순위보다 높은 구조를 가지고 있습니다.
우선순위 큐는 다익스트라 알고리즘(Dijkstra Algorithm), 허프만 코딩(Huffman Coding), 우선순위 스케줄링(Priority Scheduling) 등에서 사용됩니다.
MAX_QSIZE = 10
class CircularQueue:
def __init__(self):
self.front = 0
self.rear = 0
self.items = [None] * MAX_QSIZE
def isEmpty(self): return self.front == self.rear
def isFull(self):
return self.front == (self.rear+1)%MAX_QSIZE
def clear(self):
self.front = self.rear
def enqueue(self, item):
if not self.isFull():
self.rear = (self.rear+1)%MAX_QSIZE
return self.items[self.rear] = item
def dequeue(self):
if not self.isEmpty():
self.front = (self.front+1)%MAX_QSIZE
return self.items[self.front]
def peek(self):
if not self.isEmpty():
return self.items[(self.front + 1)%MAX_QSIZE]
def size(self):
return (self.rear - self.front + MAX_QSIZE) % MAX_QSIZE
def display(self):
out = []
if self.front < self.rear:
out = self.items[self.front+1:self.rear+1]
else:
out = self.items[self.front+1:MAX_QSIZE] + self.items[0:self.rear+1]
print(out)
class CircularDeque(CircularQueue):
def __init__(self):
# front, rear, items와 같은 멤버 변수는 추가로 선언하지 않음
super().__init__()
# 기존 메소드 재활용
def addRear(self, item):
self.enqueue(item)
def deleteFront(self):
return self.dequeue()
def getFront(self):
return self.peek()
# 추가 구현 메소드
def addFront(self, item):
if not self.isFull():
self.front = (self.front - 1 + MAX_QSIZE) % MAX_QSIZE
self.items[self.front] = item
def deleteRear(self):
if not self.isEmpty():
item = self.items[self.rear]
self.rear = (self.rear - 1 + MAX_QSIZE) % MAX_QSIZE
return item
def getRear(self):
return self.items[self.rear]
# python list를 이용한 구현
class PriorityQueue:
def __init__(self):
self.items = []
def isEmpty(self):
return len(self.items) == 0
def size(self):
return len(self.items)
def clear(self):
self.items = []
def enque(self, item):
self.items.append(item)
def findMaxIndex(self):
if self.isEmpty():
return None
else:
highest = 0
for i in range(1, self.size()):
if self.items[i] > self.items[highest]:
highest = i
return highest
def dequeue(self):
highest = self.findMaxIndex()
if highest is not None:
return self.items.pop(highest)
def peek(self):
highest = self.findMaxIndex()
if highest is not None:
return self.items[highest]
파이썬에서는 상속을 이용하여 새로운 클래스를 만들 수 있습니다. 상속은 기존 클래스의 모든 속성을 새로운 클래스에게 상속받아 사용할 수 있는 방법입니다. 이를 통해, 코드의 중복을 줄일 수 있고, 기존 클래스의 기능을 유지하면서 새로운 기능을 추가할 수 있습니다.
상속을 이용하여 새로운 클래스를 만들 때는 다음과 같은 형식을 따릅니다.
class NewClass(BaseClass):
def __init__(self, arg1, arg2, ...):
#super() 함수는 부모 클래스(BaseClass)의 메서드를 호출하기 위한 함수입니다.
super().__init__(arg1, arg2, ...)
# 새로운 클래스에서 추가적으로 정의할 속성과 메서드들을 작성합니다.
super().__init__()
함수를 호출하면, BaseClass
의 __init__()
메서드를 먼저 실행한 후, 새로운 클래스(NewClass
)에서 추가적으로 정의한 속성과 메서드들을 실행합니다.
예를 들어, 기존 클래스인 Person
클래스에서 이름(name)과 나이(age) 속성을 가지고, say_hello()
메서드를 정의한 후, 상속을 이용하여 새로운 클래스인 Student
클래스를 만드는 경우, 다음과 같은 코드를 작성할 수 있습니다.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hello(self):
print("Hello, my name is", self.name, "and I am", self.age, "years old.")
class Student(Person):
def __init__(self, name, age, grade):
super().__init__(name, age)
self.grade = grade
def say_hello(self):
super().say_hello()
print("I am a student in grade", self.grade)
이제 Student
클래스의 객체를 생성하여 say_hello()
메서드를 실행하면, 다음과 같은 결과를 얻을 수 있습니다.
s = Student("Alice", 20, 3)
s.say_hello() # "Hello, my name is Alice and I am 20 years old."
# "I am a student in grade 3"
우선순위 큐를 이용한 전략적 미로 탐색 방법은 A* 알고리즘이라고도 불리며, 지정된 출발점에서 목표지점까지의 최단경로를 탐색하는 알고리즘입니다. 이 알고리즘은 다음과 같은 방식으로 작동합니다.
이 알고리즘에서는 현재 위치에서 목표지점까지의 예상 비용을 계산하는 휴리스틱 함수(Heuristic Function)를 사용하여, 비용을 계산합니다. 이 휴리스틱 함수는 현재 위치에서 목표지점까지 직선거리 등의 예상 비용을 계산합니다.
예를 들어, 10x10 크기의 미로에서 출발점(0, 0)에서 목표지점(9, 9)까지의 최단 경로를 탐색하는 경우, 다음과 같은 코드를 작성할 수 있습니다.
from queue import PriorityQueue
def heuristic(node, goal):
# 현재 위치('node')에서 목표지점('goal')까지의 직선거리를 계산합니다.
dx = abs(node[0] - goal[0])
dy = abs(node[1] - goal[1])
return dx + dy
def astar(maze, start, goal):
# 최소 비용으로 이동할 수 있는 경로를 탐색
frontier = PriorityQueue()
frontier.put(start, 0)
# 현재 노드의 이전 노드를 저장하는 딕셔너리
came_from = {}
cost_so_far = {}
came_from[start] = None
cost_so_far[start] = 0
while not frontier.empty():
current = frontier.get()
if current == goal:
break
for next_node in neighbors(maze, current):
new_cost = cost_so_far[current] + cost(maze, current, next_node)
if next_node not in cost_so_far or new_cost < cost_so_far[next_node]:
cost_so_far[next_node] = new_cost
priority = new_cost + heuristic(next_node, goal)
frontier.put(next_node, priority)
came_from[next_node] = current
return came_from, cost_so_far
astar()
함수는 frontier
에서 비용이 가장 적게 드는 위치(current
)를 꺼내어 방문합니다. 그리고 해당 위치에서 이동 가능한 모든 위치를 계산하고, 이동 가능한 위치를 frontier
에 넣습니다. 이때, cost_so_far
딕셔너리를 이용하여 각 위치까지의 비용을 계산합니다.
이후, frontier
에서 다시 비용이 가장 적게 드는 위치를 꺼내어 방문합니다. 이 과정을 반복하여 목표지점에 도착하면 탐색을 종료합니다.
위의 코드에서 neighbors()
함수와 cost()
함수는 각각 현재 위치에서 이동 가능한 위치와 현재 위치와 이동 가능한 위치까지의 비용을 계산하는 함수입니다. 이 함수들은 각각 미로의 구조에 따라 다르게 작성될 수 있습니다.
이처럼 우선순위 큐를 이용한 전략적 미로 탐색 방법은 A* 알고리즘을 이용하여 최단 경로를 탐색하는 것이 가능합니다.
12장 고급 정렬
Dijkstra 최단 경로 알고리즘
8장 트리
Abstract
선택 정렬 알고리즘
연결된 구조
큐에 대한 정의
스택의 개념과 동작 원리
1. 리스트 & 집합 & 배열
1. 파이썬 이란?
1. 교과서 정리
1. 자료구조와 알고리즘
논문 정리 논문 요약
[우분투] 파이썬 가상환경 만들고 사용하기
[우분투] 파이썬 가상환경 만들고 사용하기 - venv 사용하여 가상환경 생성
1. 개념
활동내용
활동내용
활동내용
- hhttps://dacon.io/competitions/official/236050/overview/description
활동내용
외국계 기업의 정확한 뜻
활동내용
1. 다항함수(Polynomial Function)
활동내용
출처: https://gaussian37.github.io/ml-sklearn-saving-model/
1. 경사도벡터(Gradient Vector)
[참고] - https://blog.est.ai/2020/03/%EB%94%A5%EB%9F%AC%EB%8B%9D-%EB%AA%A8%EB%8D%B8-%EC%95%95%EC%B6%95-%EB%B0%A9%EB%B2%95%EB%A1%A0%EA%B3%BC-bert-%EC%95%95%E...
- https://aihub.or.kr/aihubdata/data/view.do?currMenu=115&topMenu=100&aihubDataSe=realm&dataSetSn=631
머신러닝 스터디 팀4 활동 보고서
1. 영유아 행동인식을 통한 발달평가 XXX - https://aihub.or.kr/aihubdata/data/view.do?currMenu=115&topMenu=100&aihubDataSe=realm&dataSetSn=631
https://www.itworld.co.kr/insight/109825 [ITWorld - 머신러닝 라이브러리, 텐서플로우의 이해] https://tensorflow.blog/%EC%BC%80%EB%9D%BC%EC%8A%A4-%EB%94%A5%EB%9F%AC%EB%8B...
http://matrix.skku.ac.kr/math4ai-intro/W13/
랜덤(random) 모듈
1팀. 주식시세 차익 알림
차원축소와 매니폴드 학습
인공지능 기초 2022-2 Project Proposer
추천 알고리즘의 기본 협업 필터링(Collaborative Filtering) • Memory Based Approach User-based Filtering I...
자소서 지원동기 효과적인 작성법
분명히 로컬에서 삭제한 파일인데 원격에 반영되지 않는 경우가 있다. git status로 했을 때 삭제 됐다고 뜨는데 add를 해도 안먹고 commit을 해도 반영이 안되는 것이다…
1. 결정 트리
[공통] 마크다운 markdown 작성법
Git 설치 & 환경설정
첫 블로그 생성입니다. 앞으로 잘 부탁드려요.