'Push'에 해당되는 글 2건

  1. 2020.12.17 우선순위 큐
  2. 2020.12.09 스택

우선순위 큐의 필요성

- 우선순위 큐는 우선순위를 가진 데이터들을 저장하는 큐를 의미

- 데이터를 꺼낼 때 우선순위가 높은 데이터가 가장 먼저 나온다는 특징이 있어 많이 활용되고 있음

- 우선순위 큐는 운영체제의 작업 스케줄링, 정렬, 네트워크 관리 등의 다양한 기술에 적용되고 있음

 

우선순위 큐의 차이점

- 일반적인 형태의 큐는 선형적인 형태를 가지고 있지만 우선순위 큐는 트리 구조로 보는 것이 합리적

- 일반적으로 우선순위 큐는 최대 힙을 이용해 구현함

 

최대 힙

- 최대 힙은 부모 노드가 자식 노드보다 값이 큰 완전 이진트리를 의미

- 최대 힙의 루트 노드는 전체 트리에서 가장 큰 값을 가진다는 특징이 있음

- 항상 전체 트리가 최대 힙 구조를 유지하도록 자료구조를 만들 수 있음

- PUSH : 우선순위 큐에 데이터를 삽입

- POP : 우선순위 큐에서 데이터를 추출

 

우선순위 큐의 삽입

- 삽입할 원소는 완전 이진트리를 유지하는 형태로 순차적으로 삽입됨

- 삽입 이후에는 루트 노드까지 거슬러 올라가면서 최대 힙을 구성함 [상향식]

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 10000

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

typedef struct {
    int heap[MAX_SIZE];
    int count;
} priorityQueue;

void push(priorityQueue *pq, int data) {
    if (pq->count >= MAX_SIZE) return;
    pq->heap[pq->count] = data;
    int now = pq->count;
    int parent = (pq->count - 1) / 2;
    // 새 원소를 삽입한 이후에 상향식으로 힙을 구성
    while (now > 0 && pq->heap[now] > pq->heap[parent]) {
        swap(&pq->heap[now], &pq->heap[parent]);
        now = parent;
        parent = (parent - 1) / 2;
    }
    pq->count++;
}

 

우선순위 큐의 삭제

- 삭제할 때는 루트 노드를 삭제하고 가장 마지막 원소를 루트 노드의 위치로 옮겨줌

- 삭제 이후에는 리프 노드까지 내려가면서 최대 힙을 구성 [하향식]

 

* 우선순위 큐의 추출

int pop(priorityQueue *pq) {
    if (pq->count <= 0) return -9999;
    int res = pq->heap[0];
    pq->count--;
    pq->heap[0] = pq->heap[pq->count];
    int now = 0, leftChild = 1, rightChild = 2;
    int target = now;
    // 새 원소를 추출한 이후에 하향식으로 힙을 구성
    while (leftChild < pq->count) {
        if (pq->heap[target] < pq->heap[leftChild]) target = leftChild;
        if (pq->heap[target] < pq->heap[rightChild] && rightChild < pq->count) target = rightChild;
        if (target == now) break; // 더 이상 내려가지 않아도 될 때 종료
        else {
            swap(&pq->heap[now], &pq->heap[target]);
            now = target;
            leftChild = now * 2 + 1;
            rightChild = now * 2 + 1;
        }
    }
    return res;
}

 

* 우선순위 큐의 사용

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 10000

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

typedef struct {
    int heap[MAX_SIZE];
    int count;
} priorityQueue;

void push(priorityQueue *pq, int data) {
    if (pq->count >= MAX_SIZE) return;
    pq->heap[pq->count] = data;
    int now = pq->count;
    int parent = (pq->count - 1) / 2;
    // 새 원소를 삽입한 이후에 상향식으로 힙을 구성
    while (now > 0 && pq->heap[now] > pq->heap[parent]) {
        swap(&pq->heap[now], &pq->heap[parent]);
        now = parent;
        parent = (parent - 1) / 2;
    }
    pq->count++;
}

int pop(priorityQueue *pq) {
    if (pq->count <= 0) return -9999;
    int res = pq->heap[0];
    pq->count--;
    pq->heap[0] = pq->heap[pq->count];
    int now = 0, leftChild = 1, rightChild = 2;
    int target = now;
    // 새 원소를 추출한 이후에 하향식으로 힙을 구성
    while (leftChild < pq->count) {
        if (pq->heap[target] < pq->heap[leftChild]) target = leftChild;
        if (pq->heap[target] < pq->heap[rightChild] && rightChild < pq->count) target = rightChild;
        if (target == now) break; // 더 이상 내려가지 않아도 될 때 종료
        else {
            swap(&pq->heap[now], &pq->heap[target]);
            now = target;
            leftChild = now * 2 + 1;
            rightChild = now * 2 + 1;
        }
    }
    return res;
}

int main(void) {
    int n, data;
    scanf("%d", &n);
    priorityQueue pq;
    pq.count = 0;
    for (int i = 0; i < n; i++) {
        scanf("%d", &data);
        push(&pq, data);
    }
    for (int i = 0; i < n; i++) {
        int data = pop(&pq);
        printf("%d ", data);
    }
    system("pause");
    return 0;
}

'자료구조 알고리즘' 카테고리의 다른 글

그래프의 개념과 구현  (0) 2020.12.17
순차 탐색과 이진 탐색  (0) 2020.12.17
이진 트리의 구현 및 순회  (0) 2020.12.17
이진 트리의 개념  (0) 2020.12.17
기수 정렬  (0) 2020.12.17
Posted by khon98
,

스택

자료구조 알고리즘 2020. 12. 9. 23:57

스택

- 스택(stack)은 한쪽으로 들어가서 한쪽으로 나오는 자료 구조(Data Structure)

- 이러한 특성 때문에 수식 계산 등의 알고리즘에서 다방면으로 활용됨

 

push : 스택에 데이터를 넣음

pop : 스택에서 데이터를 빼냄

 

push(7) - push(5) - push(4) - pop() - push(6) - pop()

7 5

 

스택의 구현

- 스택(stack)은 배열을 이용한 구현 방법과 연결 리스트를 이용한 구현 방법으로 나누어짐

- 가장 기본적인 형태의 자료구조로 구현 난이도는 낮은 편

 

배열을 이용한 스택 구현

* 스택의 선언

#define SIZE 10000 // 전체 스택의 크기
#define INF 99999999

int size[SIZE];
int top = -1; // 스택의 최 상단을 의미 하는 변수 top

 

* 스택 삽입 함수

- 오버플로우 : 데이터가 넘친다, 데이터가 들어갈 수 없을 만큼 스택이 가득 찼다

void push(int data) {
    if (top == SIZE - 1) { // 만약 top이 size -1이라면(9999라면)
        printf("스택 오버플로우 발생. \n");
        return;
    }
    stack[++top] = data;
}

 

* 스택 추출 함수

int pop() {
    if (top == -1) { // top이 -1이라면
        printf("스택 언더플로우 발생. \n");
        return -INF;
    }
    return stack[top--];
}

 

* 스택 전체 출력 함수

void show() {
    printf("--- 스택의 최상단 ---\n");
    for (int i = top; i >= 0; i--) {
        printf("%d\n", stack[i]);
    }
    printf("--- 스택의 최하단 ---\n");
}

 

* 완성된 스택 사용하기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10000 // 전체 스택의 크기
#define INF 99999999

int stack[SIZE];
int top = -1; // 스택의 최 상단을 의미 하는 변수 top

void push(int data) {
    if (top == SIZE - 1) { // 만약 top이 size -1이라면(9999라면)
        printf("스택 오버플로우 발생. \n");
        return;
    }
    stack[++top] = data;
}

int pop() {
    if (top == -1) { // top이 -1이라면
        printf("스택 언더플로우 발생. \n");
        return -INF;
    }
    return stack[top--];
}

void show() {
    printf("--- 스택의 최상단 ---\n");
    for (int i = top; i >= 0; i--) {
        printf("%d\n", stack[i]);
    }
    printf("--- 스택의 최하단 ---\n"); // 가장 먼저 들어온 값
}

int main(void) {
    push(7); // 가장 먼저 들어온 값
    push(5);
    push(4);
    pop();
    push(6);
    pop();
    show();
    system("pause");
    return 0;
}

 

연결 리스트를 이용한 스택 구현

* 스택의 선언

#define INF 99999999

typedef struct {
    int data;
    struct Node *next;
} Node;

typedef struct {
    Node *top;
} Stack;

 

배열을 이용한 스택 구현

- 스택 삽입 과정

1. data next(Top) > data next(일반 노드) > data next(일반 노드) > null

2. data next(Top) > data next(일반 노드) > data next(일반 노드) > null

            data next(삽입할 노드)

3. data next(일반 노드) > data next(일반 노드) > data next(일반 노드) > null

            data next(Top)

 

* 스택 삽입 함수

void push(Stack *stack, int data) {
    Node *node = (Node*) malloc(sizeof(Node));
    node->data = data;
    node->next = stack->top;
    stack->top = node;
}

 

- 스택 추출 과정

1. next(Top, 삭제할 노드) > data next(일반 노드) > data next(일반 노드) > null

2. next(삭제할 노드) > data next(Top, 일반 노드) > data next(일반 노드) > null

3. data next(Top, 일반 노드) > data next(일반 노드) > null

 

* 스택 추출 함수

void pop(Stack *stack) {
    if (stack->top == NULL) {
        printf("스택 언더플로우 발생.\n");
        return -INF;
    }
    Node *node = stack->top;
    int data = node->data;
    stack->top = node->next;
    free(node);
    return data;
}

 

* 스택 전체 출력 함수

void show(Stack *stack) {
    Node *cur = stack->top;
    printf("--- 스택의 최상단 ---\n");
    while (cur != NULL) {
        printf("%d\n", cur->data);
        cur = cur->next;
    }
    printf("--- 스택의 최하단 ---\n");
}

 

* 완성된 스택 사용하기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define INF 99999999

typedef struct {
    int data;
    struct Node *next;
} Node;

typedef struct {
    Node *top;
} Stack;

void push(Stack *stack, int data) {
    Node *node = (Node*) malloc(sizeof(Node));
    node->data = data;
    node->next = stack->top;
    stack->top = node;
}

void pop(Stack *stack) {
    if (stack->top == NULL) {
        printf("스택 언더플로우 발생.\n");
        return -INF;
    }
    Node *node = stack->top;
    int data = node->data;
    stack->top = node->next;
    free(node);
    return data;
}

void show(Stack *stack) {
    Node *cur = stack->top;
    printf("--- 스택의 최상단 ---\n");
    while (cur != NULL) {
        printf("%d\n", cur->data);
        cur = cur->next;
    }
    printf("--- 스택의 최하단 ---\n");
}

int main(void) {
    Stack stack;
    stack.top = NULL;
    show(&stack);
    push(&stack, 7);
    push(&stack, 5);
    push(&stack, 4);
    pop(&stack);
    push(&stack, 6);
    pop(&stack);
    show(&stack);
    system("pause");
    return 0;
}

 

 

- 스택은 배열 혹은 연결 리스트를 이용해서 구현할 수 있음

'자료구조 알고리즘' 카테고리의 다른 글

  (0) 2020.12.10
스택을 활용한 계산기 만들기  (0) 2020.12.10
양방향 연결 리스트  (0) 2020.12.09
연결 리스트  (0) 2020.12.09
자료구조의 개요  (0) 2020.12.09
Posted by khon98
,