Notice
Recent Posts
Recent Comments
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 월미도
- 자료구조
- JPA
- Spring Data JPA
- aws
- Spring Boot
- 쿠버네티스
- 카프카
- 클라우드
- Elasticsearch
- 스프링
- Spring
- 백준
- 인천여행
- 스프링 부트
- 오일러프로젝트
- 스프링부트
- springboot
- 프로그래밍문제
- Kafka
- Docker
- 알고리즘
- DFS
- 백트래킹
- VPC
- 클라우드 컴퓨팅
- gcp
- 로드밸런서
- Apache Kafka
- 코드업
Archives
- Today
- Total
GW LABS
C++로 구현하는 자료구조 (8) - Heap 본문
이번 포스팅에서는 힙 자료구조를 알아보려고 한다. 힙은 우선순위 큐로도 활용할 수 있으며, 정렬에도 사용할 수 있다. 힙에 대한 이해도가 낮아서 geeksforgeeks의 구현 예제를 많이 참고했다. 어떤 자료구조인지 함께 알아보자!
1. Heap
힙은 완전이진트리(complete binary tree)를 기본으로 한 트리형 자료구조이다. 최댓값과 최소값을 빠르게 찾아내기 위해 고안되었으며, 종류에 따라 다음과 같은 속성을 지닌다.
- 최소 힙이라면?
- 자식 노드의 값은 부모 노드의 값보다 크다.
- 최대 힙이라면?
- 자식 노드의 값은 부모 노드의 값보다 작다.
이런 속성을 만족하면 힙의 루트는 최대 혹은 최소값이 된다.
2. Heap 구현방법
처음 힙을 구현하려고 했을 때, 이번 포스팅에서 구현했던 이진탐색트리와 같은 방법으로 구현하려고 접근했었다. 그러나 그런 방법보다 동적배열을 사용하면 훨씬 간단하게 힙을 구현할 수 있다. 아래의 노트 특성을 기억하면 손쉽게 힙을 구현할 수 있다. 편의상 힙의 자료를 담는 배열을 Arr라고 하겠다.
- 힙의 루트는 Arr[0]이다.
- 힙의 각 i번째 노드들은 아래와 같은 성질을 만족한다.
- Arr[(i-1) / 2]은 i번째 노드의 부모 노드이다.
- Arr[(2*i) + 1]은 i번째 노드의 왼쪽 자식 노드이다.
- Arr[(2*i) + 2]은 i번째 노드의 오른쪽 자식 노드이다.
위에서 기술한 성질들을 이용하면 배열을 통해 힙을 구현할 수 있으며, 힙 정렬을 수행할 때에도 위의 성질을 이용하여 정렬을 수행할 수 있다.
3. 소스코드
#pragma once
#include <vector>
#include <algorithm>
#include <iostream>
/*
Reference:
https://www.geeksforgeeks.org/binary-heap/
*/
template <typename T>
class Heap {
private:
std::vector<T> heap;
// 주어진 인덱스의 부모 인덱스를 가져온다.
int _parent(int idx) {
return (idx - 1) / 2;
}
// 주어진 인덱스의 왼쪽 인덱스를 가져온다.
int _left(int idx) {
return (2 * idx + 1);
}
// 주어진 인덱스의 오른쪽 인덱스를 가져온다.
int _right(int idx) {
return (2 * idx + 2);
}
void _heapify(int idx) {
int l = this->_left(idx);
int r = this->_right(idx);
int largest = idx;
if (l < heap.size() && heap[l] > heap[idx]) {
largest = l;
}
if (r < heap.size() && heap[r] > heap[largest]) {
largest = r;
}
if (largest != idx) {
std::swap(heap[idx], heap[largest]);
this->_heapify(largest);
}
}
public:
Heap() {}
void insert(T data) {
heap.push_back(data);
int idx = heap.size() - 1;
// 부모 인덱스가 자식 인덱스보다 작다면 교환한다.
while (idx != 0 && heap[this->_parent(idx)] < heap[idx]) {
std::swap(heap[idx], heap[this->_parent(idx)]);
idx = this->_parent(idx);
}
}
void pop() {
if (heap.size() <= 0) {
std::cout << "힙에 요소가 없습니다." << std::endl;
return;
}
// 루트 요소를 맨 뒤로 보내고 heapify를 수행한다.
int root = heap[0];
heap[0] = heap[heap.size() - 1];
heap.pop_back();
this->_heapify(0);
return;
}
T top() {
return heap[0];
}
~Heap() {
delete heap;
}
};
#include <iostream>
#include "datastructure/Heap.h"
int main() {
Heap<int>* heap = new Heap<int>();
heap->insert(3);
heap->insert(1);
heap->insert(5);
heap->insert(2);
heap->insert(8);
std::cout << heap->top() << std::endl; // 8
heap->pop();
std::cout << heap->top() << std::endl; // 5
return 0;
}
'Algorithm & DataStructure' 카테고리의 다른 글
[Backjoon] 스타트와 링크 (0) | 2020.10.30 |
---|---|
C++로 구현하는 자료구조 (9) - Trie (0) | 2020.10.28 |
[Backjoon] 토마토 (0) | 2020.10.17 |
C++로 구현하는 자료구조 (7) - Queue (0) | 2020.10.13 |
C++로 구현하는 자료구조 (6) - Stack (0) | 2020.10.07 |
Comments