[자료구조] 스택(1)
스택
식판을 쌓듯이 자료를 차곡차곡 쌓아 올린 형태 순서리스트 (=pushdown 리스트)의 특별한 자료구조를 말함
- 후입선출(LIFO : Last-In-First-Out) 프로토콜을 구현하는 자료구조
- 스택의 주소를 알려주는 포인터
- top의 위치에서만 원소를 삽입하므로 먼저 삽입한 원소는 밑에 쌓이고, 나중에 삽입한 원소는 위에 쌓임
- 스택에 저장된 원소는 top으로 정한 곳에서만 접근 가능함
- 스택의 밑(bottom)에서부터 스택의 크기까지의 범위를 가짐
스택의 삽입
스택 S = (a0, … , an-1)
- a0 : bottom 원소, an-1 : top 원소, ai : 스택원소 (0 < i < n , i+1 번째 원소)
삽입은 리스트의 마지막에서 이루어짐 - push()
삽입 알고리즘
push(s, e){
if(top == SIZE) stack-overflow;
top = top+1;
stack[top] = e;
}
스택의 삭제
삭제도 리스트의 마지막에서 이루어짐 - pop()
삭제 알고리즘
pop(s){
if(top == 0) stack-underflow;
e = stack[top];
top = top-1;
return e;
}
스택의 순차 표현
1차원 배열을 이용한 스택의 구현
스택을 표현하는 가장 간단한 방법임
- n = 스택에 저장할 수 있는 최대 원소 수
- top = 스택의 최상위 원소
- 공백상태 => top = -1(초기값), 포화 상태 => top = n-1
스택도 배열에 의해 저장되므로 배열의 속성을 가짐
- 동일한 자료형만 저장
- 배열의 크기에 의해 원소 개수의 제한을 받음
스택의 1차원 배열 표현의 장단점
- 장점 - 순차 자료구조인 1차원 배열을 사용하여 쉽게 구현할 수 있음
- 단점 - 물리적으로 크기가 고정된 배열을 사용하므로 스택의 크기 변경이 어려움
스택 연산의 구현
1차원 배열의 크기(stack[8])에서 오버플로우와 언더플로우를 검사하는 프로그램
#include<stdio.h>
int MAXSIZE = 8;
int stack[8];
int top = -1;
int isempty(){
if(top == -1)
return 1;
else
return 0;
}
int isfull(){
if(top == MAXSIZE)
return 1;
else
return 0;
}
int peek(){
return stack[top];
}
int push(int data){
if(!isfull()){
top = top + 1;
stack[top] = data;
} else{
printf("Could not insert data, Stack is full.\n");
}
}
int pop(){
int data;
if(!isempty()){
data = stack[top];
top = top - 1;
return data;
} else{
printf("Could not retrieve data, Stack is empty.\n");
}
}
int main(){
push(3);
push(5);
push(9);
push(1);
push(12);
push(15);
printf("Element at top of the stack: %d\n", peek());
printf("Elements:\n");
while(!isempty()){
int data = pop();
printf("%d\n", data);
}
printf("Stack full: %s\n", isfull()?"true":"false");
printf("Stack empty: %s\n", isempty()?"true":"false");
return 0;
}
실행 결과
Element at top of the stack: 15
Elements:
15
12
1
9
5
3
Stack full: false
Stack empty: true
스택의 응용 : 시스템 스택
시스템 스택(system stack)/실행시간 스택(runtime stack)
기억 공간의 데이터들을 효율적으로 관리하기 위한 데이터 참조 방식의 자료구조를 말함
- 프로그램 실행 시 시스템이 사용하는 대표적인 스택(기억공간)
- 실행 스택(excution stack), 제어 스택(control stack), 런 타임 스택(run-time) 스택, 기계 스택(machine stack)이라고도 함
함수간의 호출과 복귀에 따른 실행순서관리를 위한 제어
- 함수 호출 시 시스템은 호출한 함수 수행에 필요한 지역변수, 매개변수 및 수행 후 복귀할 주소 등의 정보를 활성화 레코드(activation record) 또는 스택 프레임(stack frame)을 만들어 스택에 삽입
스택의 응용 : 문자열 역순/괄호검사
문자열 역순 출력 방법 및 예
- 문자열을 읽어 문자열 끝까지 차례대로 스택에 삽입(push)
- 스택이 비워질(empty) 때까지 문자들을 삭제(pop)
문자열 = “computer science”를 역순으로 출력하는 프로그램
#include<stdio.h>
#include<string.h>
#define MAX 100 // 최대 문자열의 길이
int top = -1; // 스택 변수
int item;
char stack_string[MAX];
void pushChar(char item);
char popChar(void);
int isEmpty(void);
int isFull(void);
int main(){
char str[MAX];
int i;
printf("Input a string:");
scanf("%[^\n]s",str); // 문자열 입력
for(i=0; i<strlen(str); i++)
pushChar(str[i]);
for(i=0; i<strlen(str); i++)
str[i] = popChar();
printf("Reversed String is: %s\n",str);
return 0;
}
void pushChar(char item){
if(isFull()){
printf("\nStack is FULL!!!\n");
return;
}
top = top+1;
stack_string[top] = item;
}
char popChar(){
if(isEmpty()){
printf("\nStack is EMPTY!!!\n");
return 0;
}
item = stack_string[top];
top = top-1;
return item;
}
int isEmpty(){
if(top == -1)
return 1;
else
return 0;
}
int isFull(){
if(top == MAX-1)
return 1;
else
return 0;
}
실행 결과
Input a string: computer science
Reversed String is: ecneics retupmoc
괄호 검사
괄호( (, ), {, }, [ ,] )가 서로 대응하며 적절하게 내포되었는지 파악하는 검사를 말함 - 컴파일러에서 구문 체크 시 활용
수식에 포함되어있는 괄호는 가장 마지막에 열린 괄호를 가장 먼저 닫아 주어야 하는 LIFO구조로 구성되어 있음
괄호 검사 방법
- 입력 문자열(수식)에서 현재의 문자가 시작 괄호이면 스택에 삽입함(push)
- 현재의 문자가 닫는 괄호이면 스택에서 삭제(pop)
- 입력 문자열의 마지막 문자까지 읽었을 때 스택에 시작 괄호가 남아 있으면 균형을 이루지 못함, 즉 괄호가 닫히지 않음
괄호 검사하는 프로그램
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 20
struct stack{
char stk[MAX];
int top;
}s;
void push(char item){
if(s.top == (MAX - 1))
printf("Stack is Full\n");
else{
s.top = s.top + 1; //포인터를 1 증가 후 괄호를 삽입
s.stk[s.top] = item;
}
}
void pop(){
if(s.top == -1){
printf("Stack is Empty\n");
}
else{
s.top = s.top-1; // 괄호를 삭제 후 포인터 감소
}
}
int main(){
char exp[MAX];
int i = 0;
s.top = -1;
printf("\n입력 식:");
scanf("%s", exp);
for(i=0; i<strlen(exp); i++){
if(exp[i] == '(' || exp[i] == '[' || exp[i] == '{'){
push(exp[i]); // 시작 괄호를 스택에 삽입
continue;
}
else if(exp[i] == ')' || exp[i] == ']' || exp[i] == '}'){
if(exp[i] == ')'){ // 닫는 괄호이면 스택에서 삭제
if(s.stk[s.top] == '('){
pop();
}
else{
printf("\n괄호의 균형을 이루지 못한 수식\n");
break;
}
}
if(exp[i] == ']'){
if(s.stk[s.top] == '['){
pop();
}
else{
printf("\nUNBALANCED EXPRESSION\n");
break;
}
}
if(exp[i] == '}'){
if(s.stk[s.top] == '{'){
pop();
}
else{
printf("\nUNBALANCED EXPRESSION\n");
break;
}
}
}
}
if(s.top == -1){ //stack이 empty이면 balanced함
printf("\n입력식의 괄호 개수가 BALANCED이다.\n");
}
}
출력결과
입력 식:{(a+b)/[{(c-d)/2}*2]}
입력식의 괄호 개수가 BALANCED이다.