20150322_栈

20150322_栈

注:参考《大话数据结构》

栈(stack)是限定仅在表尾进行插入和删除操作的线性表
我们把允许插入和删除的一端称为栈顶(top),另一端称为端底(bottom),不含任何数据元素的栈称为空栈。
栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构。


栈的存储结构和实现

1.栈的顺序存储结构

栈是线性表的特例,那么栈的顺序结构其实也是线性表顺序结构的简化,我们简称顺序栈。线性表使用数组实现。
以下标为0的一端作为栈底。

栈的结构定义

typedef int SElemType ;
typedef struct
{
    SElemType data[MAXSIZE];
    int top;   // 栈顶指针,标识栈顶位置
}Sqstack;

进栈

Status push(Sqstack *S,SElemTpye e)
{
    if(S->top==MAXSIZE-1)
        return ERROR;      //栈满,不能进栈
    S->top++;
    S->data[S->top]=e;
    return OK;
}

出栈

Status pop(Sqstack *S,SElemTpye *e)
{
    if(S->top==-1)
        return ERROR;  //栈空
    *e=S->data[S->top];  //e出栈使用,通过形参返回
    S->top--;
    return OK;
}
2.栈的链式存储结构(链栈)

栈只在栈顶做插入和删除。既然使用链表来表示栈,那么考虑到单链表需要头指针,栈顶指针也不可缺少,所以可以把栈顶放在单链表的头部,合二为一。有了栈顶指针,头指针也就不是必须的了。通常,对于链栈来说,是不需要头指针的。

链栈的结构定义

typedef struct stacknode          //链表结点
{
    SElemType data;
    struct stacknode *next;
}stacknode, *linkstackptr;

typedef struct linkstack
{
    linkstackptr top;      //指向栈顶,不是链表结点
    int len;
}linkstack;

进栈

Status push(linkstack *S,SElemType e)
{
    linkstackptr p=(linkstackptr)malloc(sizeof(stacknode));
    p->data=e;
    p->next=S->top;
    S->top=p;
    S->len++;
    return OK;
}

出栈

Status pop(linkstack *S,SElemType *e)
{
    linkstackptr p=NULL;
    if(S->top==NULL)
        return ERROR;
    *e=S->top->data;
    p=S->top;
    S->top=S->top->next;
    free(p);
    S->len--;
    return OK;
}

总结:两者在时间复杂度上是一样的,均为O(1)。
如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好使用链栈,反之,如果它的变化在可控范围你,建议使用顺序栈。

栈的应用—四则运算表达式

实现:
  • 将中缀表达式转化为后缀表达式(栈用来进出运算的符号)(符号栈)
  • 将后缀表达式进行运算得出结果(栈用来进出运算的数字)(数字栈)

STEP:
1. 从左到右遍历中缀表达式的每个数字和符号,当是数字时就输出,即成为后缀表达式的一部分,若是符号,则判断其与当时栈顶的符号的优先级,是右括号或优先级(不包括括号)低于(等于)栈顶符号,则以此栈顶元素依次出栈并输出,直至当前栈顶元素优先级低于入栈符号,将当前符号入栈,直到最后最终输出后缀表达式为止。
2. 从左到右遍历后缀表达式的每个数字和符号,若是遇到数字就进栈,若是遇到符号,就将栈顶两个数字出栈,进行运算,运行结果进栈,一直到得到最终结果。

一点小问题:在代码中如何进行优先级的比较?
解决方案:构造一个优先级函数,将可能用到的符号设置数字优先级,当传入某符号时,通过该函数返回它的数字优先级,通过数字来进行比较。

初始版本

代码实现
int priority(char ch)
{
    if(ch=='+'||ch=='-')
        return 1;
    else if(ch=='*'||ch=='/')
        return 2;// 括号不设置优先级

}
#include "myfunc.h"
void myoperate(char ch,int *sec_top,int top)
{
    switch (ch)
    {
    case '+':
            *sec_top=top+(*sec_top);
            break;
    case '-':
            *sec_top=(*sec_top)-top;
            break;
    case '*':
            *sec_top=(*sec_top)*top;
            break;
    case '/':
            *sec_top=(*sec_top)/top;
            break;
    default:
            break;
    }
}
#include "myfunc.h"  
void stack_cal(char *s)                //,s为字符串数组,将屏幕输入以字符串的形式读入。另外,只能实现10以内的计算
{
    int num_stack[MAXSIZE];
    char ch_stack[MAXSIZE];
    int i=0;
    int j=-1;
    int k=-1;
    int cur_prio=0;    //标志当前栈顶元素的优先级,优先级均为自然数,大于0。

    while(s[i])
    {
        if(s[i]<='9'&&s[i]>='0')
        {
            num_stack[++j]=s[i]-'0';
            i++;
            continue;
        }
        if(s[i]=='(')
        {
            ch_stack[++k]=s[i];
            i++;
            continue;
        }

        if(s[i]=='*'||s[i]=='/')
        {
            ch_stack[++k]=s[i];
            cur_prio=priority(ch_stack[k]);
            i++;
            continue;
        }

         if(s[i]==')')
        {
            while(ch_stack[k]!='(')
            {
                myoperate(ch_stack[k],&num_stack[j-1],num_stack[j]);
                j--;
                k--;
            }
            k--;
            cur_prio=ch_stack[k];
            i++;
            continue;
        }

         while(priority(s[i])<=cur_prio&&k>=0&&ch_stack[k]!='(')    //优先级(不包括括号)低于(等于)栈顶符号,则以此栈顶元素依次出栈并输出,直至当前栈顶元素优先级低于入栈符号,将当前符号入栈,直到最后最终输出后缀表达式为止
        {
            myoperate(ch_stack[k],&num_stack[j-1],num_stack[j]);
            j--;
            k--;
            cur_prio=priority(ch_stack[k]);
        }

        ch_stack[++k]=s[i];
        cur_prio=priority(ch_stack[k]);
        i++;

    }
    while(k>=0)
    {
        myoperate(ch_stack[k],&num_stack[j-1],num_stack[j]);
        k--;
        j--;
    }
    printf("%d\n",num_stack[0]);
}

关于如何实现10以上的数据计算,有空再写。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值