728x90

스택(Stack)과 힙(Heap)은 프로그래밍에서 중요한 메모리 구조임

이들은 데이터를 저장하고 관리하는 데 사용되며, 주로 컴퓨터 프로그램의 실행 중에 데이터를 저장하는 데 쓰임

여기에서는 이 두 가지 구조의 기본적인 개념과 차이점에 대해 설명할 예정

스택(Stack)

스택은 후입선출(LIFO, Last In, First Out)의 구조를 가진 메모리 영역

이는 마치 접시를 쌓는 것처럼, 마지막에 들어온 데이터가 먼저 처리되는 구조

  • 특징
    • 구조: 스택은 선형 자료구조로, 데이터가 일렬로 쌓여있는 형태로, 맨 위에 있는 요소에만 접근 가능
    • 연산: 스택에는 데이터를 스택에 추가하는 "push"와, 스택에서 데이터를 꺼내는 "pop"이라는 두 가지 연산이 존재
    • 메모리 할당방식: 정적 메모리 할당을 사용하여 크기가 컴파일 시에 결정됨
    • 용도: 함수 호출 시에 지역 변수, 매개변수, 반환 주소 등을 저장하는 데 사용되며, 재귀 알고리즘의 실행 흐름을 관리하는 데에도 사용
  • 장점
    • 빠른 접근 속도: 메모리에 연속적으로 저장되어 있으므로, 데이터에 빠르게 접근 가능
    • 간편한 관리: 후입선출구조로인해 데이터의 추가와 삭제가 간단하며 메모리 관리에 용이
    • 스택프레임: 함수 호출 시에 지역변수와 매개변수를 저장하는 스택 프레임을 통해 함수의 호출과 반환을 효율적으로 관리 가능
  • 단점
    • 크기 제한: 스택의 크기는 컴파일 시에 결정되므로 런타임 시에 동적으로 조정이 불가 → 정적으로 할당된 메모리의 한계로 인해 스택오버플로우가 발생 가능
    • 임시저장만 가능: 스택은 임시데이터를 저장하는 데 사용되므로, 장기적인 데이터 보관에는 적합하지 않음
# 파이썬 리스트를 이용한 스택 구현 예시
class Stack:
    def __init__(self):
        self.stack = []

    def push(self, item):
        self.stack.append(item)

    def pop(self):
        if self.is_empty():
            return None
        return self.stack.pop()

    def peek(self):
        if self.is_empty():
            return None
        return self.stack[-1]

    def is_empty(self):
        return len(self.stack) == 0

# 스택 테스트
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)

# 스택은 무조건 가장 나중에 삽입한 값부터 반환함
print("스택의 맨 위 항목:", stack.peek())  # 출력: 3
print("스택에서 팝된 항목:", stack.pop())  # 출력: 3
print("스택의 맨 위 항목:", stack.peek())  # 출력: 2

 

힙 (Heap)

힙은 메모리의 동적 할당 영역으로 데이터의 저장 및 관리를 위해 사용됨

힙은 데이터를 임의의 순서로 저장하며 메모리가 동적으로 할당되고 해제됨

맨 위의 요소에만 접근 가능한 스택과는 달리, 힙은 임의의 요소에 접근이 가능함

  • 특징
    • 구조: 힙은 트리 형태의 자료구조로, 노드들이 부모-자식 관계로 연결되며, 각 노드는 일반적으로 특정한 데이터를 저장
    • 연산: 힙은 데이터를 삽입하는 "insert" 연산과, 삭제하는 "delete" 연산이 존재
    • 메모리 할당방식: 동적 메모리 할당을 사용하여 런타임 중에 크기가 결정됨
    • 용도: 동적으로 크기가 변하는 데이터 구조를 관리하는 데 사용되며, 주로 동적으로 할당된 객체나 배열, 그래프 등을 저장하기 위해 활용
  • 장점
    • 동적 할당: 힙은 런타임 중에 메모리를 동적으로 할당하므로, 유연한 데이터 구조를 생성 가능하며 크기제한이 없음
    • 오랜 기간 데이터 보존 가능: 힙은 데이터의 수명이 프로그램의 실행 시간 동안 지속되므로, 장기적인 데이터 보존이 가능함
  • 단점
    • 메모리 누수: 메모리 해제를 제대로 처리하지 않으면 메모리 누수가 발생할 수 있음
    • 접근 시간: 힙은 트리 구조로 데이터에 접근하는 데에 추가적인 시간이 소요될 수 있음
    • 효율성: 동적할당 및 해제 작업은 상대적으로 오버헤드가 크므로, 스택에 비해 느릴 수 있음
# 파이썬 heapq 모듈을 이용한 힙 구현 예시
import heapq

heap = []
heapq.heappush(heap, 5)
heapq.heappush(heap, 2)
heapq.heappush(heap, 7)

# 마지막 삽입한 값이 아닌 값 반환 가능 (heapq.heappop 함수는 힙에서 가장 작은 값을 삭제하고 반환)
print("힙에서 팝된 최소 항목:", heapq.heappop(heap))  # 출력: 2
print("힙에서 팝된 최소 항목:", heapq.heappop(heap))  # 출력: 5

 

728x90
728x90

명령형 프로그래밍

프로그램이 어떻게 작업을 수행할지를 명시적으로 정의하는 방식

상태와 상태를 변경하는 명령어들의 연속으로 구성됨

프로그램이 어떤 작업을 수행해야 하느지 단계별로 기술하며, 컴퓨터에게 명령을 내리는 개념

# 리스트에서 짝수를 찾아 제곱한 후 새로운 리스트에 저장하는 명령형 코드
numbers = [1, 2, 3, 4, 5]
squared_evens = []

for num in numbers:
    if num % 2 == 0:
        squared_evens.append(num ** 2)

print(squared_evens)
  • 장점
    • 직관성, 가독성 : 일반적으로 작업이 어떻게 수행되는지 명확히 보여줌
    • 효율적인 메모리 사용 : 상태를 직접 조작하므로 메모리 효율적 사용에 유리
    • 직접적인 제어 : 작업의 세부사항에 대한 직접적인 제어를 제공하므로 세밀한 최적화가 가능
  • 단점
    • 복잡성 : 코드가 상태를 직접 조작하면서 복잡성이 증가할 수 있음
    • 변수 상태 관리 : 변수상태를 올바르게 관리하지 않으면 버그가 발생할 수 있음
    • 유지보수 어려움 : 코드가 어떻게 동작할지 이해하기 어려울 수 있어 유지보수가 불리

선언형 프로그래밍

프로그램이 무엇을 수행할지를 명시적으로 정의하는 방식

어떤 작업을 어떻게 수행할지를 명시하지 않고, 목표를 기술하는 방식

더 추상화되고 선언적인 방식으로 문제를 해결하며, 내부적으로 시스템이 어떻게 동작하는지를 숨김

함수형 프로그래밍은 선언형 프로그래밍의 대표적인 예시

# 리스트에서 짝수를 찾아 제곱한 후 새로운 리스트에 저장하는 선언형 코드 (리스트 컴프리헨션 사용)
numbers = [1, 2, 3, 4, 5]
squared_evens = [num ** 2 for num in numbers if num % 2 == 0]

print(squared_evens)
  • 장점
    • 간결성 : 코드가 더 짧고 간결하며, 목적에 집중할 수 있음
    • 추상화와 모듈화 : 작업을 높은 수준에서 추상화하고 모듈화하므로 코드를 이해하고 재사용하기 쉬움
    • 병렬처리 용이 : 함수형 프로그래밍의 특징인 불변성과 순수 함수는 병렬처리를 쉽게 만들어줌
  • 단점
    • 초기 학습이 어려움
    • 최적화 어려움 : 목표를 선언하는 것은 좋지만 내부 동작을알기 어려워 최적화가 어려울 수 있음
    • 메모리 사용량 증가 가능성 : 함수형 프로그래밍에서 불변성을 유지하려면 새로운 데이터 구조를 계속 생성해야하므로 메모리 사용량이 증가할 수 있음
728x90

'Computer Science' 카테고리의 다른 글

지역 심벌과 전역 심벌  (0) 2024.07.24
링커란?  (0) 2024.07.17
컴파일 언어와 인터프리터 언어 비교  (0) 2024.07.10
Brute force(브루트 포스)란?  (0) 2024.07.09
스택(stack)과 힙(Heap)  (0) 2024.03.27

+ Recent posts