출처 | DO IT C언어 자료구조 입문
이번 시간에는 스택에 대해 알아보자.
스택은 데이터를 일시적으로 저장하기 위해 사용하는 자료구조다.
데이터의 입력과 출력 순서는 후입선출이다.(LIFO, Last In First Out)
push : 스택에 데이터를 넣는 작업을 푸시라고한다.
pop : 스택에서 데이터를 꺼내는 작업
top : push, pop를 하는 위치 (꼭대기) peek
bottom : 스택의 가장 밑바닥 부분을 (바닥)bottom이라고 한다.
다음은 함수의 호출과정을 알아보겠다.
void x()
{
}
void y()
{
}
void z()
{
x();
y();
}
int main()
{
z();
}
<함수 호출과정>
1. main 함수를 실행한다.
(main함수를 push)
2. z함수를 호출한다.
(z함수를 push)
3. x함수를 호출한다.
(x함수 push) / 스택(main - z- x)
4. x함수가 종료되고, z함수로 돌아온다.
(x함수 pop) /스택(main-z)
5. y함수를 호출한다.
(y함수 push) / 스택 (main-z-y)
6. y함수를 종료하고 z함수로 돌아온다.
(y함수 pop) /스택(main-z)
7. z함수를 종료하고 main 함수로 돌아온다.
(z함수 pop) / 스택 (main)
8. main 함수를 종료한다.
(main 함수 pop) / 스택 (비어있음)
※전처리기에 관련된 모든 것
https://eskeptor.tistory.com/24 <참고
스택에대한 예제를 보자..
#ifndef ___IntStack
#define ___IntStack
typedef struct {
int max; // 스택의 최대용량 max
int ptr; // 스택에 쌓여있는 데이터의 개수를 나타내는 멤버 (스택 포인터라고 한다)
int* stk; // 스택으로 사용할 배열을 가리키는 포인터
}IntStack;
//스택 초기화
int Initialize(IntStack* s, int max);
// 스택에 데이터를 푸시
int Push(IntStack* s, int x);
//스택에 데이터를 팝
int Pop(IntStack* s, int* x);
// 스택에 데이터를 피크
int Peek(const IntStack* s, int* x);
//스택 비우기
void Clear(IntStack* s);
// 스택의 최대 용량
int Capacity(const IntStack* s);
// 스택의 데이터 개수
int Size(const IntStack* s);
// 스택이 비어 있나요?
int IsEmpty(const IntStack* s);
// 스택이 가득 찼나요?
int IsFull(const IntStack* s);
// 스택에서 검색
int Search(const IntStack* s, int x);
//모든 데이터를 출력
void print(const IntStack* s);
//스택 종료
void Terminate(IntStack* s);
#endif
InStack은 3개의 멤버로 구성된다.
stk
max
ptr
#include <stdio.h>
#include <stdlib.h>
#include "IntStack.h"
typedef struct
{
int max; // 스택 용량
int ptr; // 스택 포인터
int *stk; // 스택을 가리키는 포인터
}IntStack;
int Initialize(IntStack* s, int max)
{
s->ptr = 0; // 스택 포인터를 0으로 둔다. 왜냐하면 메모리 공간을 만들 때, 스택은 비어 있어야 하기 때문이다.
if ((s->stk = calloc(max, sizeof(int))) == NULL) // 배열의 생성 실패 했을 경우
{
s->max = 0; // max가 0이라는 의미는 생성 x
return -1; // -1를 반환하고 빠져나온다.
}
s->max = max;
return 0;
}
int Push(IntStack* s, int x) //새로 추가할 데이터 x
{
if (s->stk >= s->max) // 스택이 가득찬 경우
//if(s->stk == s->max)도 가능하다.
//IntStack.c에서 제공하는 함수는 ptr(0~Max)다. 그렇기 때문에 등가 연산자 사용가능
//부등호를 사용하면 스택 크기의 최댓값과 최솟값을 넘는 액세스를 막을 수 있다.
return -1;
//스택이 가득차면 푸시를 할 수 없으면 -1 반환
s->stk[s->ptr++] = x;
//스택이 가득차지 않으면 x를 배열의 요소 stk[ptr]에 저장
//ptr를 증가시킨다.
return 0;
}
만약 main에서 pop(&s, &x)라고 호출했다면,
int pop(IntStack* s, int* x)
{
if (s->ptr <= 0)
return -1; //스택이 비어 있어 팝을 할 수 없는 경우에는 -1를 반환
*x = s->stk[s->ptr--]; // 스택 포인터 ptr의 값을 감소 시키고 stk[ptr]에 저장된 값을 포인터 x가 가리키는 변수에 저장한다.
return 0;//팝에 성공할 경우 0을 반환
}
int Peek(const IntStack* s, int* x)
{
if (s->ptr <= 0)
return -1;
*x = s->stk[s->ptr - 1];
//스택이 비어있지 않으면
//꼭대기 요소 stk[ptr-1]의 값을 포인터 x가 가리키는 변수에 저장
//데이터의 입력 및 출력이 없기 때문에 스택 포인터는 변화가 없다.
return 0; // 피크에 성공하면 0를 반환
}
void Clear(IntStack* s)
{
s->ptr = 0;
// 스택에 대한 push, pop은 -> 스택 포인터를 바탕으로 이루어진다. (ptr)
// 스택의 배열 요솟갑을 변경할 필요가 x
// 모든 요소의 삭제는 ptr = 0으로 하면 끝난다.
}
오늘 배운걸 정리해보자.