
class Stack:
def __init__(self, capacity = 10):
self.capacity = capacity
self.items = [None] * capacity
self.top = -1
def is_empty(self):
return self.top == -1
def is_full(self):
return self.top == self.capacity - 1
def get_size(self):
return self.top + 1
def peek(self):
if self.is_empty():
raise IndexError("Stack is empty")
return self.items[self.top]
def push(self, item):
if self.is_full():
raise IndexError("Stack is full")
self.top += 1
self.items[self.top] = item
def pop(self):
if self.is_empty():
raise IndexError("Stack is empty")
itme = self.items[self.top]
self.items[self.top] = None
self.top -= 1
return item
파이썬에서는 list의 append()와 pop(), len()을 활용하여 쉽게 스택을 이용할 수 있다.
stack = []
# push
stack.append('a')
stack.append('b')
stack.append('c') # stack = ['a', 'b', 'c']
# pop
stack.pop() # c 출력, stack = ['a', 'b']
# peek
stack[len(stack)] # b 출력, stack = ['a', 'b']

class Queue:
def __init__(self, capacity = 10):
self.capacity = capacity
self.items = [None] * capacity
self.front = -1
self.reer = -1
def is_empty(self):
return self.front == self.rear
def is_full(self):
return self.rear == self.capacity - 1
def peek(self):
if self.is_empty():
raise IndexError("Queue is empty")
return self.items[self.front + 1]
def get_size(self):
return self.rear - self.front
def enqueue(self, item):
if self.is_full():
raise IndexError("Queue is full")
self.rear += 1
self.items[self.rear] = item
def dequeue(self):
if self.is_empty():
raise IndexError("Queue is empty")
self.front += 1
item = self.items[self.front]
self.items[self.front] = None
return item
여기서 문제점이 있음
잘못된 포화 상태 인식
삽입과 삭제를 반복하다 보면 리스트의 앞부분이 None임에도 불구하고 포화상태로 인식할 수 있다.

이를 위해 항상 앞쪽을 채우도록 하려면 한번의 삭제마다 n번의 이동이 필요하다. -> 매우 비효율적
이를 해결하기 위해 원형 큐를 사용할 수 있다.

class CircleQueue:
def __init__(self, capacity = 10):
self.capacity = capacity + 1
self.items = [None] * self.capacity
self.front = 0
self.rear = 0
def is_empty(self):
return self.front == self.rear
def is_full(self):
return (self.rear + 1) % self.capacity == self.front
def peek(self):
if self.is_empty():
raise IndexError("Queue is empty")
return self.itmes[(self.front + 1) % self.capacity]
def get_size(self):
return (self.rear - self.front + self.capacity) % self.capacity
def enqueue(self, item):
if self.is_full():
raise IndexError("Queue is full")
self.rear = (self.rear + 1) % capacity
self.items[self.rear] = item
def dequeue(self):
if self.is_empty():
raise IndexError("Queue is empty")
self.front = (self.front + 1) % self.capacity
item = self.items[self.front]
self.items[self.front] = None
return item
파이썬에서 deque라는 라이브러리로 쉽게 사용가능하다.
기존의 리스트에서 중간에 특정 값을 삭제하면 뒤의 모든 값을 앞으로 이동시켜야 하는 문제가 있다. 이렇게 하면 한 번의 삭제에 n번의 연산이 필요한 겂이다. 이를 해결하기 위해 연결 리스트를 사용할 수 있다.

연결 리스트에서 하나의 원소를 표현하는 구성 요소
구성요소

class Node:
def __init__(self, data):
self.data = data
self.next = None
class SinglyLinkedList:
def __init__(self):
self.head = None
def is_empty(self):
return self.head is None
def insert(self, data, position):
new_node = Node(data)
if position == 0:
new_node.next = self.head
self.head = new_node
else:
current = self.head
for _ in range(position - 1):
if current is None:
print("범위를 벗어난 삽입입니다.")
return
current = current.next
new_node.next = current.next
current.next = new_node
def append(self, data):
new_node = Node(data)
if self.is_empty():
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
def delete(self, position):
if self.is_empty():
print("싱글 링크드 리스트가 비었습니다.")
return
if position == 0:
deleted_data = self.head.data
self.head = self.head.next
else:
current = self.head
for _ in range(position - 1):
if current is None or current.next is None:
print("범위를 벗어났습니다.")
return
current = current.next
deleted_node = current.next
deleted_data = deleted_node.data
current.next = current.next.next
return deleted_data
def search(self, data):
current = self.head
position = 0
while current:
if current.data == data:
return position
current = current.next
position += 1
return -1
def __str__(self):
result = []
current = self.head
while current:
result.append(current.data)
current = current.next
return str(result)
장점
- 필요한 만큼만 메모리를 사용
단점
- 특정 요소에 접근하려면 순차적으로 탐색 (O(n))
- 역방향 탐색 불가
역방향 탐색이 가능하도록 링크 필드를 두 개, 데이터 필드 한 개로 구성


