자료구조의 스택, 큐, 환형 큐, 힙, 트리, 그래프에 대해 알아보고 C++에서 직접 사용해보자.
#include<stack>
// 선언
stack<int> stack;
// 데이터 추가
stack.push(element);
// top 데이터 삭제
stack.pop();
// 스택 사이즈 반환
stack.size();
// 비어있는지 체크
stack.empty();
// stack1과 stack2 두 스택의 내용을 바꿈
swap(stack1,stack2);
#include <queue>
// 선언
queue<int> q;
// 데이터 추가
queue.push(element);
// front data 삭제
queue.pop();
// 제일 최상위 데이터 반환
queue.front();
// 마지막 데이터번환
queue.back();
// 사이즈 반환
queue.size();
// 비어있는지 확인
queue.empty();
// 두 큐의 내용 바꾸기
swap(queue1, queue2);
#include<iostream>
using namespace std;
class myQueue{
private:
int arr[10] = {0};
int front = 0, rear = 0;
public:
void push(){
if(((rear + 1) % 10) == front){
cout << "Queue is Full" << endl;
} else {
cout << "데이터를 입력하세요: ";
int data;
cin >> data;
rear = (rear + 1) % 10;
arr[rear] = data;
}
}
void pop(){
if(front == rear){
cout << "Queue is Empty" << endl;
return;
}
front = (front + 1) % 10;
}
void print(){
if(front == rear){
cout << "Queue is Empty" << endl;
return;
}
for(int i = (front + 1)%10; i != (rear + 1)% 10; i = (i+1)% 10){
cout << i << " : " << arr[i] << endl;
}
}
};
int main() {
int num;
myQueue q;
while (1) {
cout << "번호를 입력해주세요 1. push / 2. pop / 3. print / 4. 종료" << endl;
cin >> num;
switch (num) {
case 1:
q.push();
break;
case 2:
q.pop();
break;
case 3:
q.print();
break;
case 4:
return 0;
default :
cout << "잘못된 입력입니다." << endl;
}
}
return 0;
}
정리를 해보자면 이렇다 일차원 배열로 생각했을 대 [1,2,3,4,5,6,7,8,9,10] 이 있다고 해보자 만약 저 배열이 원형으로 배치 되어 있다면 10 다음은 1일 것이고 1의 인덱스는
{(10의 인덱스 + 1)% 배열의 크기}
일 것이다.
그렇다면 1은 front, 10은 rear라고하고 위에 코드에서 다시생각하면 이해하기 슆다.
힙은 이진 트리 자료구조이다.
index 0은 최상단 노드
i 번째 노드의 자식 노드는 i 2 + 1번째 노드와 i 2 + 2번째 노드가 된다.
i 번째 노드의 부모 노드는 (i-1)/2 번째 노드가 된다.
부모노드는 항상 자식 노드보다 작거나 같다./크거나 같다.
이러한 구조는 Min Heap이라고 부른다.
부모가 자식보다 항상 큰 규칙을 가지면 Max Heap이 된다.
이러한 규칙을 유지하며 원소의 추가/제거 과정을 거치면 루트 노드에 있는 원소 값은 Min Heap에서는 최소값이, Max Heap에서는 최대값이 된다.
원소의 추가/제거 과정이 O(logN)의 복잡도
조회 O(1)으로 효율적인 구조
Heap 자료구조를 응용한 대표적인 사례가 Priority queue(우선순위 큐)이다.
push/pop이 가능한 자료로 꼭 Heap으로 구현할 필요는 없지만 Heap으로 구현하는 것이 시간복잡도 면에서 큰효율을 낸다.
왜 효율을 내는지는 아래의 Reference를 참조하라
// 큐와 우선순위 큐의 비교
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> qu;
qu.push(1);
qu.push(9);
qu.push(5);
int sz = qu.size();
for(int i=0;i<sz;i++){
cout << qu.front() << ',';
qu.pop();
}cout << '\n';
priority_queue<int> p_qu_l;
p_qu_l.push(1);
p_qu_l.push(9);
p_qu_l.push(5);
sz = p_qu_l.size();
for(int i=0;i<sz;i++){
cout << p_qu_l.top() << ',';
p_qu_l.pop();
}cout << '\n';
priority_queue<int, vector<int>, greater<int>> p_qu_g;
p_qu_g.push(1);
p_qu_g.push(9);
p_qu_g.push(5);
sz = p_qu_g.size();
for(int i=0;i<sz;i++){
cout << p_qu_g.top() << ',';
p_qu_g.pop();
}cout << '\n';
return 0;
}
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
int data;
Node* left;
Node* right;
// Val is the key or the value that has to be added to the data part
Node(int val)
{
data = val;
// Left and right child for node will be initialized to null
left = NULL;
right = NULL;
}
};
int main()
{
//create root
Node* root = new Node(1);
/* following is the tree after above statement
1
/ \
NULL NULL
*/
root->left = new Node(2);
root->right = new Node(3);
/* 2 and 3 become left and right children of 1
1
/ \
2 3
/ \ / \
NULL NULL NULL NULL
*/
root->left->left = new Node(4);
/* 4 becomes left child of 2
1
/ \
2 3
/ \ / \
4 NULL NULL NULL
/ \
NULL NULL
*/
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
// 인접 리스트 : 실제 연결된 애들만 넣어줌.
void CreateGraph_AdjacencyList()
{
struct Vertex
{
int data;
};
vector<Vertex> v(6); // 정점 6개 생성.
// 0 1 2
// [vector<int>][vector<int>][vector<int>]...
vector<vector<int>> adjacent; // 2차원 배열.
adjacent.resize(6);
adjacent[0] = { 1, 3 }; // 0번 정점은 1, 3번 정점과 연결되어 있음.
adjacent[1] = { 0, 2, 3 }; // 1번 정점은 0, 2, 3번 정점과 연결되어 있음.
adjacent[3] = { 4 }; // 3번 정점은 4번 정점과 연결되어 있음.
adjacent[4] = { 5 }; // 4번 정점은 5번 정점과 연결되어 있음.
// Q) 0번->3번 연결되어 있나요?
bool connected = false;
// 정점이 가지고 있는 값들을 하나씩 조사.
int size = adjacent[0].size();
for (int i = 0; i < size; i++)
{
int vertex = adjacent[0][i];
if (vertex == 3)
connected = true;
}
}
// 인접 행렬 : 메모리 소모 심하지만, 빠른 접근 가능.
void CreateGraph_AdjacencyMatrix()
{
struct Vertex
{
int data;
};
vector<Vertex> v(6);
// 연결된 목록을 행렬로 관리
// [X][O][X][O][X][X] 0 -> 1, 3
// [O][X][O][O][X][X] 1 -> 0, 2, 3
// [X][X][X][X][X][X] 2 -> x
// [X][X][X][X][O][X] 3 -> 4
// [X][X][X][X][X][X] 4 -> x
// [X][X][X][X][O][X] 5 -> 4
vector<bool> v(6, false);
vector<vector<bool>> adjacent(6, vector<bool>(6, false));
adjacent[0][1] = true;
adjacent[0][3] = true;
adjacent[1][0] = true;
adjacent[1][2] = true;
adjacent[1][3] = true;
adjacent[3][4] = true;
adjacent[5][4] = true;
// Q) 0번 -> 3번 연결되어 있나요?
// 정점을 인덱스로 사용하여 바로 접근 가능.
bool connected = adjacent[0][3];
// 가중치 그래프를 인접 행렬로 만들기. (정점간 연결되어 있지 않은 경우 = -1)
// 값을 가중치로 사용하면 됨.
vector<vector<int>> adjacent2 =
{
{ -1, 15, -1, 35, -1, -1},
{ 15, -1, 5, 10, -1, -1},
{ -1, 5, -1, -1, -1, -1},
{ 35, 10, -1, -1, 5, -1},
{ -1, -1, -1, 5, -1, 5},
{ -1, -1, -1, -1, 5, -1},
};
}