CS/자료구조

Chapter 9: Heaps, Priority Queues, and Graphs

arsenic-dev 2025. 12. 14. 14:53

경희대학교 박제만 교수님의 자료구조 수업을 기반으로 정리한 글입니다.

Heap

A heap is a binary tree that satisfies these special SHAPE and ORDER properties:

  • Shape: Heaps' shape must be a complete binary tree. (위쪽, 왼쪽부터 채움)
  • Order: Parents value > Child values (MAX heap)

▶ Heap Example

  • Largest (Smallest) Value in a Heap -> root

 

BST와 Heap은 비슷한 듯 다르니, 구분할 수 있어야 한다.

  • Heap: 부모 >= 자식
  • BST: 왼쪽 서브트리 <  노드 < 오른쪽 서브트리

 

※ MAX heap <-> MIN heap

 

▶ Array Representation of Heaps

  • complete binary tree -> array! (minimized empty space)
  • 위에서 아래로, 왼쪽에서 오른쪽으로 번호를 붙임

 

array이기에 linked structure로 구현한 것에 비해 확장성이 떨어진다.

 

Heap Operations

Insert a New Node

▶ Logical Level - insertItem(65)

  • 1. Insert the new element in the next bottome leftmost place -> shape 만족
  • 2. Fix the heap property by calling ReheapUp -> order 만
    • If heap property is violated (chile> parent) -> Swap nodes

 

▶ reheapUp() - Implementation Level

  • root: root의 idx
  • boottom_id: 현재 비교하는 값의 idx

 

Why Do We Need a Heap?

  • find max (or min) in root -> O(1)
  • e.g., priority queue

 

※ 메모리 공간 heap 과는 아무런 상관이 없다. (just 이름만 같음)

 

※ priority_dequeue()

template<class ItemType>
bool QueueType<ItemType>::priority_dequeue(ItemType& ret) { // 원형큐의 경우 에러 발생 시 -> % maxQueue 했는지 확인
    if(isEmpty()){
        cout << "[ERROR] Queue is Empty. Dequeue Failed." << endl;
        return false;
    }
    
    int i = front;
    int min_index = (front + 1) % maxQueue; // front는 reserved_space이기에 + 1 해야 첫 번째 값임
    do {
        i = (i + 1) % maxQueue;
        if (data[min_index].priority > data[i].priority) {
            min_index = i;
        }
    } while (i != rear);

    ret = data[min_index];

    i = min_index;
    while (i != rear) {
        data[i] = data[(i + 1) % maxQueue];
        i = (i + 1) % maxQueue;
    }

    rear = (rear - 1 + maxQueue) % maxQueue; // 음수될 위험 방지
    
    return true;
}

 

Priority Queue

A priority queue is an ADT with the property that only the highest-priority element can be accessed at any time.

  • e.g., CPU task queue
    • For tasks that require immediate processing (important interrupts) we can assign higher priorities.

 

▶ Priority Queue using a Array

  • time complexity to find a task with the highest priority: O(N)

 

Can we make it better?

 

Yes, use Heap!

 

▶ Priority Queue using a Heap

  • time complexity to find a task with the highest priority: O(1)

 

Get (remove) a Largest Value 

▶ Logical Level

  • 1. Copy the bottom rightmost item to the root 
  • 2. Delete the bottom rightmost node
  • 3. Fix the heap property by calling ReheapDown
    • Swap nodes if child > parent
    • Compare with the lager child node (MAX heap)

 

▶ reheapDown() - Implementation Level

 

▶ PQType Definition

▶ HeapType Definition

  • items:  힙이 아이템을 보관하는 array
  • num_items: 아이템의 개수

▶ Constructor

▶ destructor & clear()

▶ enqueue() 

▶ dequeue()

 

Big-O comparison

 

BST는 높이가 랜덤하지만, heap은 완전 이진 트리로 높이가 log N 으로 고정이기에 위와 같은 결과가 나오는 것이다.

  • heap의 enqueue는 reheapUp, dequeue는 reheapDown임

 

그리고 Sorted list의 경우는 array/linked structure, 오름차순/내림차순, 이렇게 4가지 경우의 수가 나올 수 있다.  

  • enqueue: 모두 O(N)
  • dequeue
    • array: 오름차순의 경우 O(1), 내림차순의 경우 O(N)
    • linked structure: 오름차순의 경우 O(N), 내림차순의 경우 O(1)

 

이때, enqueue는 특정 item의 위치를 찾아 삽입하는 것이지만, dequeue는 맨 앞(max)의 값을 찾을 필요 없이 제거하니 주의한다.

또한, array의 경우 제거하거나 삽입할 때 한 칸씩 앞으로 당기거나 뒤로 미는 행위를 해야되니 주의해야 한다.

 

linked structure로 heap 구현 -> 시간복잡도 및 코드 알아야 함!!

 

Graph

▶ Graph

 

A data structure that consists of a set of nodes (vertices) and a set of edges that relate the nodes to each other.

THe set of edges describes relationships among the vertices.

 

Formal Definition

A graph G is defined as floolows:

  • G = (V, E)
    • V(G): 한 개 이상의 유한한 개수의 노드 집합 
    • E(G): a sef of edges (pairs of veritces)

 

▶ Undirected Graph

  • the edges in a graph have no direction

 

▶ Directed Graph

  • the edges in a graph have direction

 

Directed Graph에서 E(G)를 정의할 때는 vertices의 순서가 중요하니 주의하여야 한다.

  • 출발 -> 도착 

 

▶ Tree

 

Trees are special cases of graphs. 

  • Acyclic structure: 자기로부터 시작해서 다른 점을 돌아 자기 자신에게 돌아오는 것이 불가능

 

Terms

  • Adjacent nodes: 인접한 노드 (edge로 연결된 노드)
  • Path: 특정 노드로부터 다른 특정한 노드까지 이동할 때 지나가는 노드들의 순서
  • Complete graph: a graph in which every vertex is directly connected to every other vertex

 

▶ Complete Directed Graph

  • 모든 노드들끼리 직접적으로 연결되어 있어야 함

 

What is the number of edges in a complete directed graph with N vertices?

  • N * (N-1)
  • nP2: 시작 정점 N가지 * 도착 정점은 자기 자신을 뺀 N-1가지

-> 공간 복잡도: O(N^2)

 

※ Big-O는 Upper Bound의 개념으로, 가장 최악의 상황을 감안했을 때의 estimate를 표현해준다. 그리고 이를 시간에 적용하면 시간 복잡도 혹은 메모리를 얼마나 사용하는지를 나타내기 위해 메모리에 적용하면 공간(space) 복잡도가 되는 것이다. 즉, "Big-O = 시간 복잡도"는 아니니 주의하여야 한다.

 

▶ Complete Undirected Graph

  • 모든 노드들끼리 직접적으로 연결되어 있어야 함

 

What is the number of edges in a complete undirected graph with N vertices?

  • N * (N-1) / 2
  • nC2

-> 공간 복잡도: O(N^2)

 

▶ Weighted Graph

  • each edge carries a value

 

graph는 네트워크나 인공지능을 나타내어 분석하는 데에 효과적인 자료구조이다.

 

▶ Adjacency Matrix

  • 0: edge 존재 X

 

We can use two matrices to represent a graph (컴퓨터가 이해하기 쉽게 나타냄)

  • A 1D array: to represent vertices
  • A 2D array (adjacency matrix):  to represent the edges

 

▶ Adjacency List

 

We can also use a linked list (and on array) to represent a graph

  • A 1D array: to represent vertices
  • A linked list (adjacency list):  to represent the edges

 

▶ Adjacency Matrix vs. List

  • E: edge
  • V: vertex

 

▶ GraphType Definition

  • mark: DFS, BFS 할 때 방문 여부를 담는 배열 -> 방문하면 true, 아직 방문 안 했으면 false

▶ Constructor 

  • edge: 더블 포인터 (int 포인터를 가리키는 포인터) -> 2차원 배열
    • edges는 int가 아닌 int*들의 배열 -> edges[i]가 i번째 행을 가리키는 포인터 (adjacency matrix)
    • 행 할당: edges = new int* [maxVertices];
    • 열 할당: for문 -> edges[i] = new int[maxVertices];

▶ Destructor

▶ addVertex()

  • 새 정점을 vertices의 맨 끝에 넣음
  • 새 정점과 "기존 정점들" 사이 간선 초기화

▶ addEdge()

▶ getVertexIndex()

▶ getWeight()

  • edges 이차원 배열이 adjacency matrix임

 

Graph Searching

  • 두 노드를 연결하는 path를 찾는 것을 의미
  • Methods: Depth-First-Search (DFS) or Breadth-First-Search (BFS)

 

Depth-First Searching (DFS)

What is the idae behind DFS?

  • Visit all in a branch to its deepest point before moving up
  • Travel as far as you can down a path

 

DFS can be implemented efficiently using a stack.

 

 

Depth-first Searching (DFS)

▶ DFS uses STACK

  • 1. Pop from Stack
  • 2. Visit the popped coordinate (node)
  • 3. Push the adjacent coordinates (nodes)
  • 4. Repeat 1-3

-> 경로가 있구나! 판단

 

만약 경로가 없을 경우엔, end를 pop 하지 못했는데 어느 순간 스택이 비어버리게 된다.

-> 경로가 없구나! 판단

 

Why STACK?

⭐ 스택의 원리가 직전의 상태를 기억해 주는 역할을 하기 때문이다.

 

▶ DepthFirstSearch()

  • 초기화
  • DFS
    • pop the node
    • endVertex에 도달하면 return true
    • eddVertex에 도달하지 못했으면 push adjacents

▶ getAdjacents()

 

⭐ 경로의 합을 구하는 것과, 최단 경로 (weight) 구하는 것과, 경로 출력하는 함수도 만들어 볼 것!

 

Breadth-First Searching (BFS)

What is the idae behind BFS?

  • Visit all nodes on one level before going to the next level
  • Look at all possible paths at the same depth before you go at a deeper level

 

BFS can be implemented efficiently using a queue.

 

 

Breadth-First Searching (BFS)

▶ BFS uses QUEUE

  • 1. Dequeue from Queue
  • 2. Visit the dequeued coordinate (node)
  • 3. Enqueue the adjacent coordinates (nodes)
  • 4. Repeat 1-3

-> 경로가 있구나! 판단

 

만약 경로가 없을 경우엔, end를 dequeue 하지 못했는데 어느 순간 큐가 비어버리게 된다.

-> 경로가 없구나! 판단

 

Why QUEUE?

⭐ 찾아낸 경로가 효율적일 가능성이 BFS보다 높지만, 경로를 찾아내는 과정 자체는 비효율적이다. (DFS와 반대!)

 

▶ breadthFirstSearch()

 

⭐ 경로의 합을 구하는 것 해보기!!! (int 반환)

 

 

DFS, BFS 장단점 고민해볼 것!!

 

Shortest Path Problem

특정한 정점을 출발해서 다른 정점들로 갈 수 있는 최단 경로들의 값을 구해주는 방식

 

 

 

 


참고자료

https://arsenic-dev.tistory.com/68

 

Programming Exercise: Lab #3

경희대학교 박제만 교수님의 자료구조 수업을 기반으로 정리한 글입니다.Exercise #1ProblemsImplement rotateFirstItem() in Circular Queue with Reserved space.This function "ROTATES" the first item of the queue.▶ Both are OKAY (in

arsenic-dev.tistory.com

 

 

'CS > 자료구조' 카테고리의 다른 글

Programming Exercise: Lab #7  (1) 2025.06.08
Chapter 8: Tree  (2) 2025.06.08
Programming Exercise: Lab #6  (3) 2025.06.02
Chapter 7: Recursion  (0) 2025.06.02
Programming Exercise: Lab #5  (0) 2025.05.20