1. 程式人生 > >資料結構 棧(順序棧,鏈式棧,用棧實現計算器)

資料結構 棧(順序棧,鏈式棧,用棧實現計算器)

一、棧的概念

1. 棧是一個特殊的線性表,只能在一端操作:棧頂(top):允許操作 的一端

                                                                    棧底(bottom):不允許操作的一端

2. 特點:後進先出

二、順序棧 

1. 若儲存棧的長度為StackSize,則棧頂位置top必須小於StackSize

若棧存在一個元素,top = 0空棧的條件:top = -1

2. 結構體定義:struct sqStack

{

                    int top;

                    int

*data;

                };

3. (1)棧的初始化兩次malloc分配

                 (*s) = (Stack *)malloc(sizeof(Stack) * 1);  //分配一個結構體,用於儲存資訊

                 (*s)->top = -1; //空棧,棧頂指標為-1
                 (*s)->data = (ElemType *)malloc(sizeof(ElemType) * SIZE);   //為棧分配空間

    (2)進棧 s - > data[ s - > top + 1 ] = e;   //先放入內容,再移動top指標
            s - > top++;

    (3)出棧 e = s - > data[ s -> top ];    //先取出內容,再移動top指標
            s - > top - -;

    (4)清空棧 s -> top = -1;

    (5)銷燬棧 free( ( *s ) - > data );
               free( *s );
               *s = NULL;

三、鏈式棧

1. 棧頂放在單鏈表的頭部;

    鏈棧不需要頭結點;

    鏈棧不存在棧滿的情況。

2. 結構體定義:

/*結點資訊*/
struct node
{
    ElemType data;  //資料域
    struct node *next;   //指標域
};
typedef struct node Node;

/*棧的資訊*/
struct stack
{
    Node *top;  //頭指標
    int count;  //結點個數
};

3. 鏈式棧初始化時只要分配stack空間,即malloc一次,裡面節點的空間是放一個分配一個

4. 棧的鏈式儲存 原始碼

(1)LinkStack.h

#ifndef _LINKSTACK_H
#define _LINKSTACK_H

#define SUCCESS  10000
#define FAILURE  10001
#define TRUE     10002
#define FALSE    10003

typedef int ElemType;

/*結點資訊*/
struct node
{
    ElemType data;  //資料域
    struct node *next;   //指標域
};
typedef struct node Node;

/*棧的資訊*/
struct stack
{
    Node *top;  //頭指標
    int count;  //結點個數
};
typedef struct stack Stack;

int StackInit(Stack **s);
int StackEmpty(Stack *s);
int push(Stack **s, ElemType e);
int GetTop(Stack *s);
int pop(Stack **s);
int StackClear(Stack **s);
int StackDestroy(Stack **s);

#endif

(2)LinkStack.c

#include "LinkStack.h"
#include <stdlib.h>

/*初始化*/
int StackInit(Stack **s)
{
    if(NULL == s)
    {
        return FAILURE;
    }

    (*s) = (Stack *)malloc(sizeof(Stack) * 1);  //分配stack的空間
    if(NULL == (*s))
    {
        return FAILURE;
    }

    (*s)->top = NULL;
    (*s)->count = 0;

    return SUCCESS;
}

/*判斷是否為空*/
int StackEmpty(Stack *s)
{
    if(NULL == s)
    {
        return FAILURE;
    }

    return (s->top == NULL) ? TRUE : FALSE;
}

/*進棧*/
int push(Stack **s, ElemType e)
{
    if(NULL == s || NULL == (*s))
    {
        return FAILURE;
    }

    Node *p = (Node *)malloc(sizeof(Node));
    if(NULL == p)
    {
        return FAILURE;
    }

    p->data = e;
    p->next = (*s)->top;
    (*s)->top = p;
    (*s)->count++;

    return SUCCESS;
}

/*取棧頂元素*/
int GetTop(Stack *s)
{
    if(NULL == s || NULL == s->top)
    {
        return FAILURE;
    }

    return s->top->data;
}

/*出棧*/
int pop(Stack **s)
{
    if(NULL == s || NULL == *s)
    {
        return FAILURE;
    }

    Node *p = (*s)->top;
    ElemType e = p->data;
    (*s)->top = p->next;
    (*s)->count--;
    free(p);

    return e;
}

/*清空*/
int StackClear(Stack **s)
{
    if(NULL == s || NULL == *s)
    {
        return FAILURE;
    }

    Node *p = (*s)->top;

    while(p)
    {
        (*s)->top = p->next;
        free(p);
        p = (*s)->top;
        (*s)->count--;
    }

    return SUCCESS;
}

/*銷燬*/
int StackDestroy(Stack **s)
{
    if(NULL == s || NULL == *s)
    {
        return FAILURE;
    }

    free(*s);
    (*s) = NULL;

    return SUCCESS;
}

3.  TestLinkStack.c (main函式)

#include "LinkStack.h"
#include <stdio.h>

int main()
{
    int ret, i;
    Stack *stack = NULL;

    /*初始化*/
    ret = StackInit(&stack);
    if(ret == SUCCESS)
    {
        printf("Init Link Stack Success!\n");
    }
    else
    {
        printf("Init Failure!\n");
    }

    /*判斷是否為空*/
    ret = StackEmpty(stack);
    if(ret == TRUE)
    {
        printf("Stack is Empty!\n");
    }
    else if(ret == FALSE)
    {
        printf("Stack is not Empty!\n");
    }
    else
    {
        printf("Stack error!\n");
    }

    /*進棧*/
    for(i = 0; i < 10; i++)
    {
        ret = push(&stack, i);
        if(ret = FAILURE)
        {
            printf("Push %d Failure!\n", i);
        }
        else
        {
            printf("Push %d Success!\n", i);
        }
    }

    /*取棧頂元素*/
    ret = GetTop(stack);
    if(ret == FAILURE)
    {
        printf("Gettop Failure!\n");
    }
    else
    {
        printf("Top is %d\n", ret);
    }

    /*出棧*/
    for(i = 0; i < 5; i++)
    {
        ret = pop(&stack);
        if(ret == FAILURE)
        {
            printf("Pop Failure!\n");
        }
        else
        {
            printf("Pop %d is Success!\n", ret);
        }
    }

    /*清空*/
    ret = StackClear(&stack);
    if(ret == FAILURE)
    {
        printf("Clear Failure!\n");
    }
    else
    {
        printf("Clear Success!\n");
    }

    /*清空後判斷是否為空*/
    ret = StackEmpty(stack);
    if(ret == TRUE)
    {
        printf("Stack is Empty!\n");
    }
    else if(ret == FALSE)
    {
        printf("Stack is not Empty!\n");
    }
    else
    {
        printf("Stack error!\n");
    }

    /*銷燬*/
    ret = StackDestroy(&stack);
    if(ret == FAILURE)
    {
        printf("Destroy Failure!\n");
    }
    else
    {
        printf("Destroy Success!\n");
    }

    /*銷燬後進棧*/
    for(i = 0; i < 2; i++)
    {
        ret = push(&stack, i);
        if(ret = FAILURE)
        {
            printf("Push %d Failure!\n", i);
        }
        else
        {
            printf("Push %d Success!\n", i);
        }
    }

    return 0;
}

四、用棧的鏈式儲存結構實現計算器功能

中綴表示式轉字尾表示式情況歸納:

1. 運算元 :進棧

2. 操作符 :(1)進棧:空棧

                                       優先順序高

                                       棧頂是‘( ’同時表示式不是‘ )’

                   (2)出棧並計算:表示式符號的優先順序不高於棧頂符號

                                                  表示式為‘ )’同時棧頂不為‘( ’

                                                  表示式為‘\0’(即表示式結束)同時棧不為空

                   (3)出棧但不計算:表示式為‘ )’同時棧頂為‘( ’

#include "LinkStack.h"
#include <stdio.h>

int Priority(char ch)
{
    switch(ch)
    {
        case '(':
            return 3;
        case '*':
        case '/':
            return 2;
        case '+':
        case '-':
            return 1;
        default:
            return 0;
    }
}

int main()
{
    Stack *s_opt, *s_num;
    char opt[1024] = {0};   //存放表示式
    int i = 0, num1 = 0, num2 = 0, temp = 0;

    if(StackInit(&s_opt) != SUCCESS || StackInit(&s_num) != SUCCESS) //棧的初始化
    {
        printf("Init Failure!\n");
    }

    printf("Please input:\n");
    scanf("%s", opt);

    while(opt[i] != '\0' || StackEmpty(s_opt) != TRUE) //表示式沒結束或操作符棧不為空
    {
        if(opt[i] >= '0' && opt[i] <= '9')
        {
            temp = temp * 10 + opt[i] - '0';
            i++;
            if(opt[i] > '9' || opt[i] < '0') //操作符
            {
                push(&s_num, temp);
                temp = 0;
            }
        }
        else //操作符
        {
            if(opt[i] == ')' && GetTop(s_opt) == '(') //出棧不計算
            {
                pop(&s_opt);
                i++;
                continue;
            }

            if(StackEmpty(s_opt) == TRUE ||
                    (Priority(opt[i]) > Priority(GetTop(s_opt)))
                     || (GetTop(s_opt)) == '(' && opt[i] != ')') //出棧計算
                    {
                         push(&s_opt, opt[i]);
                         i++;
                         continue;
                    }

            if((opt[i] == '\0' && StackEmpty(s_opt) != TRUE)
                    || (opt[i] == ')' && GetTop(s_opt) != '(') ||
                        (Priority(opt[i]) <= Priority(GetTop(s_opt)))) //全部進棧完成開始計算
            {
                switch(pop(&s_opt))
                {
                    case '+':
                        num1 = pop(&s_num);
                        num2 = pop(&s_num);
                        push(&s_num, (num1 + num2));
                        break;
                    case '-':
                        num1 = pop(&s_num);
                        num2 = pop(&s_num);
                        push(&s_num, (num2 - num1));
                        break;
                    case '*':
                        num1 = pop(&s_num);
                        num2 = pop(&s_num);
                        push(&s_num, (num1 * num2));
                        break;
                    case '/':
                        num1 = pop(&s_num);
                        num2 = pop(&s_num);
                        push(&s_num, (num2 / num1));
                        break;
                }
            }
        }
    }

    printf("%d\n", GetTop(s_num));
    return 0;
}