[자료구조] 스택을 C로 구현하기

학원에서 배운 C로 스택을 구현하는 과정을 이 포스트에다가 저장한다.

전체 소스코드


#include <stdio.h>
#include <stdlib.h>

#pragma warning (disable : 4996)

typedef struct stack{
    int* arr; //동적 메모리의 주소를 저장
    int top; //배열 스택의 저장 위치
    int capacity; //배열의 최대 용량
}stack;


void stack_init(stack* st, int size);
void push(stack* st, int data);
void pop(stack* st);
void print(stack* st);
void clear(stack* st);

int main() {

    int choice;
    stack st; 
    int size, data;

    printf("스택의 크기 입력 : ");
    scanf("%d", &size);

    stack_init(&st, size); // 스택 초기화 함수
    // st의 값을 변경할 수 있도록 주소값을 전송해야함. (Call by Address)

    while (1) {
        system("clear");
        printf("*** Integer Stack ***\n\n");
        printf("1. push\n");
        printf("2. pop\n");
        printf("3. print\n");
        printf("4. clear\n");
        printf("0. terminate\n\n");

        printf("select : [ ]\b\b");
        scanf("%d", &choice);
        getchar();

        switch (choice)
        {
        case 1:
            printf("\n\ndata push : ");
            scanf("%d", &data);
            getchar();
            push(&st, data);
            getchar();
            break;
        case 2:
            pop(&st);
            break;
        case 3:
            print(&st);
            break;
        case 4:
            clear(&st);
            break;
        case 0:
            free(st.arr); // st.arr이 가리키는 동적메모리가 해제됨. arr 자체가 포인터 변수이므로 st.arr로 접근.
            printf("종료합니다.\n");
            exit(0);
        }
    }

    return 0;
}

void stack_init(stack* st, int size) {
    st->arr = (int*)malloc(sizeof(int) * size); // 배열에 저장
    st->top = 0; // 저장할 위치가 0번째임을 가리킴.
    st->capacity = size; // 입력 받은 용량만큼 count함.
}

void push(stack* st, int data) {

    int top = st->top;

    if (top >= st->capacity) {
        printf("stack overflow가 발생합니다.\n");
        return;
    }

    st->arr[top] = data;
    st->top++; // 저장 후 탑의 값 증가

    printf("저장완료.\n");
    return;
}

void pop(stack* st) { // 코드 상으로 top의 위치를 조정하는 형식. 실제로 데이터를 꺼내는 것이 아님.

    if (st->top <= 0) {
        printf("stack underflow가 발생합니다.\n");
        st->top = 0;
        getchar();
        return;
    }

    st->top--;

    printf("데이터 값 : %d\n", st->arr[st->top]);
    getchar();
    return;
}

void print(stack* st) {

    int cur = st->top - 1;

    if (st->top == 0) {
        printf("데이터가 없습니다.\n");
        getchar();
        return;
    }
    
    while (cur >= 0) {
        printf("%d ", st->arr[cur]);
        cur--;
    }
    
    getchar();
    return;
}

void clear(stack* st) {
    st->top = 0;
    printf("초기화 완료.\n");
    getchar();
    return;
}

스택의 자료구조 정의


typedef struct stack{
    int* arr; //동적 메모리의 주소를 저장
    int top; //배열 스택의 저장 위치
    int capacity; //배열의 최대 용량
}stack;


스택의 생성


void stack_init(stack* st, int size) {
    st->arr = (int*)malloc(sizeof(int) * size); // 배열에 저장
    st->top = 0; // 저장할 위치가 0번째임을 가리킴.
    st->capacity = size; // 입력 받은 용량만큼 count함.
}

생성 코드를 통해서 동적 메모리를 할당하고, 자료를 저장할 포인터 st->top을 0으로 설정해준다.
그리고 스택의 용량을 미리 지정해준다.

스택의 자료 푸시(push)


void push(stack* st, int data) {

    int top = st->top;

    if (top >= st->capacity) {
        printf("stack overflow가 발생합니다.\n");
        return;
    }

    st->arr[top] = data;
    st->top++; // 저장 후 탑의 값 증가

    printf("저장완료.\n");
    return;
}

값의 변경을 위해서 주소를 호출하며 데이터를 푸시한 후 top의 위치를 변경시켜준다.

스택의 용량 늘리기 (Vector)


만일 stack overflow가 발생할 시 저장을 계속하고 싶다면 realloc을 사용하여 용량을 늘리면 된다.

void push(stack* st, int data) {

    int top = st->top;

    if (top >= st->capacity) {
        /*
        printf("stack overflow가 발생합니다.\n");
        */
        st->capacity *= 2; // 용량을 2배로 늘림.

        // realloc(원래 데이터가 있던 주소, 재할당 크기)
        st->arr = (int*)realloc(st->arr, sizeof(int) * st->capacity); // 데이터의 재할당
        printf("스택의 크기가 2배로 증가되었습니다.\n");
        printf("용량 : %d", st->capacity);

        return;
    }

    st->arr[top] = data;
    st->top++; // 저장 후 탑의 값 증가

    printf("저장완료.\n");
    return;
}

realloc은 이미 할당된 메모리를 재할당 시켜주는 함수이다.

이렇게 용량을 늘려가는 스택의 자료구조를 벡터(Vector)라고한다.

스택의 자료 팝(pop)


void pop(stack* st) { // 코드 상으로 top의 위치를 조정하는 형식. 실제로 데이터를 꺼내는 것이 아님.

    if (st->top <= 0) {
        printf("stack underflow가 발생합니다.\n");
        st->top = 0;
        getchar();
        return;
    }

    st->top--;

    printf("데이터 값 : %d\n", st->arr[st->top]);
    getchar();
    return;
}

여기서 핵심은 자료를 실제로 꺼내고 제거하는 것이 아니라
top의 위치를 변경시켜서 자료가 제거된 것 처럼 보이게 하는 것이다.

메모리 상에는 자료가 남아있지만, 새로운 자료를 push한다면 같은 자리에 덮어씌워지게 되므로
자연스럽게 이전 데이터는 삭제된다.

스택의 초기화


void clear(stack* st) {
    st->top = 0;
    printf("초기화 완료.\n");
    getchar();
    return;
}

따라서 top의 위치를 0으로 조정하면 자동으로 초기화 된 것으로 생각할 수 있다.


© 2022.07. by Wookey_Kim

Powered by Hydejack v7.5.2