数据结构笔记2:栈

数据结构笔记2:栈

栈是一种后进先出的线性表,一般还是用顺序存储结构的比较多,链栈用的较少。

关键注意top指针指向的是最后一个入栈元素的下一个位置;

base指针指向首地址,也是指向最先入栈的元素;realloc函数的用法;清空和销毁栈的区别。

s.base-s.top差值就是此时栈中的元素个数,因为指针+1与地址值+1不同

一、下面是一个可以实现混合运算的基于栈实现的计算器。

在这里插入图片描述
在这里插入图片描述

Stack.h

#ifndef _STACK_H_
#define _STACK_H_
using namespace std;
typedef int status;
typedef char ElemType;
#define ERROR -1
#define OK 1
typedef struct StackList
{
    ElemType *top; //指向栈顶的指针
    ElemType *base;//指向栈底的指针
    int stacksize;//存储栈的大小,如果不够是在这里扩容
    //主要用处是方便判断栈满
}Stack;

/***********************************************************/
status Stack_Init(Stack &s);
status Stack_IfFull(Stack &s);//判断栈是否为满,为满则返回OK
status Stack_IfEmpty(Stack &s);//判断栈是否为空,为空则返回OK
status Stack_Push(Stack &s,ElemType &e);
status Stack_Pop(Stack &s,ElemType &e);
ElemType Stack_GetTop(Stack s);
status Stack_Clear(Stack &s);
status Stack_Destroy(Stack &s);

#endif

Stack.cpp

#include <iostream>
#include <Stack.h>
#include <cstdlib>
using namespace std;
#define STACKINITSIZE 100 //这里是给栈初始化时分配内存的
#define STACKINCREMENT 10
/*************************************************************/
status Stack_Init(Stack &s) 
{
    s.base = (ElemType*)malloc(STACKINITSIZE * sizeof(ElemType));
    s.top = s.base;
    s.stacksize = STACKINITSIZE;//初始化时分配好栈的大小
    return OK;
}
status Stack_IfFull(Stack &s)
{
    if(s.top-s.base >= s.stacksize) //两个指针指向的地址相减得到此时栈的大小(即所占空间大小)
    return OK;
    else
    return 0;
}
status Stack_IfEmpty(Stack &s)
{
    if(s.top == s.base) //两个指针指向相同地址
    return OK;
    else
    return 0;
}
status Stack_Push(Stack &s,ElemType &e)
//感觉这个地方e不用引用直接传参也可以啊,可能就是省的额外给形参分配空间了吧
//这里注意一下,top指向的是最后一个入栈元素的下一个位置,而不是最后一个入栈的元素
//而base作为栈的起始指针,其实是指向最早入栈的元素的,而不存在一个空位置专门存放base指针
{
    if(Stack_IfFull(s))//先判断栈有没有满
    {
        s.base = (ElemType*)realloc(s.base,(s.stacksize + STACKINCREMENT) 
        * sizeof(ElemType));//相当于重新分配了一段内存,把原来栈的内容直接复制过去
        if(!s.base) return ERROR;
        s.top = s.base + s.stacksize;//栈的位置变了,top指针不再是指向原来的地方,重新赋值
        s.stacksize += STACKINCREMENT;//扩容,其实是起标示作用
    }
    *(s.top) = e;
    s.top++;
    return OK;
}
status Stack_Pop(Stack &s,ElemType &e)//出栈,并用e保存出栈元素
{
    if(s.base == s.top) return ERROR;
    s.top--;
    e = *(s.top);
    return OK;
}
ElemType Stack_GetTop(Stack s)//得到栈顶元素,因为不能改变栈本身的结构,
//但是需要操作top指针,因此这里不用引用而用形参操作,函数主体与出栈类似
{
    ElemType e;
    if(s.base == s.top) return ERROR;
    s.top--;
    e = *(s.top);
    return e;
}
status Stack_Clear(Stack &s)//清空栈,不用释放存储空间
{
    s.top = s.base;//top指到base就行了
    return OK;
}
status Stack_Destroy(Stack &s) //完全释放
{
    int i,len;
    len = s.stacksize;
    for(i=0;i<len;i++)
    {
        free(s.base);//利用base指针清除,清除后指向下一个元素
        s.base++;
    }
    s.base = s.top =NULL;
    s.stacksize = 0;
    return OK; 
}

Culculate.h

#ifndef _CULCULATE_H_
#define _CULCULATE_H_
#include "Stack.h"
status char_or_num(char a);
char cul_plus(char a,char b);
char cul_minus(char a,char b);
char cul_mul(char a,char b);
char cul_div(char a,char b);
int culculate(Stack s,char str[],int &len);
int judge(char a);
status translate(Stack &s,char str1[],char str2[],int &strlen);
#endif

Culculate.cpp

#include"Culculate.h"
#include <iostream>
#include "stdlib.h"
status char_or_num(char a)//判断数字还是字符
{
    if(a>='0' && a<='9')
    return 1;
    else return 0;
}
char cul_plus(char a,char b)//字符加法
{
    int c;
    char m;
    c = (int(a)-48) + (int(b)-48);
    m = c + 48;
    return m;
}
char cul_minus(char a,char b)//字符减法
{
    int c;
    char m;
    c = (int(a)-48) - (int(b)-48);
    m = c + 48;
    return m;
}
char cul_mul(char a,char b)//字符乘法
{
    int c;
    char m;
    c = (int(a)-48) * (int(b)-48);
    m = c + 48;
    return m;
}
char cul_div(char a,char b)//字符除法
{
    int c;
    char m;
    c = (int(a)-48) / (int(b)-48);
    m = c + 48;
    return m;
}
int judge(char a)//判断符号优先级
{
    int ret;
    if(a == '*'|| a == '/')
    ret = 2;
    if(a == '+'|| a == '-')
    ret = 1;
    return ret;
}
//translate函数,将标准表达式转化乘逆波兰表达式。
//具体思路,遍历字符串,遇到数字直接放到str2中,碰到运算符号
//左括号入栈,等待匹配右括号,匹配成功的话把左右括号中的符号全部输出,包括括号出栈
//*/的优先级高于+-,碰到*/入栈(优先级不低于栈顶元素),碰到+-让元素全部出栈(没有比+-优先度低的),
//再将该元素入栈。全部遍历后再把栈里剩余元素全部输出。
status translate(Stack &s,char str1[],char str2[],int &strlen)
{
    int i,j;
    int len = 0;
    char e;
    while(1)
    {
        if(str1[len] == '\0') break;
        len++;
    }
    for(i = 0,j = 0;i<len;i++)
    {
        if(char_or_num(str1[i]))//输出数字
        {
            str2[j] = str1[i];
            j++;
        }
        else
        {
            if(str1[i] == '('||str1[i] == ')')//匹配括号
            {
                if(str1[i] == '(')
                    Stack_Push(s,str1[i]);
                if(str1[i] == ')')
                {
                    while(Stack_GetTop(s) != '(')
                    {
                        Stack_Pop(s,str2[j]);
                        j++;
                    }
                    Stack_Pop(s,e);
                }
            }
            else
            {  //判断优先级
                if((judge(str1[i]) > judge(Stack_GetTop(s)))||Stack_IfEmpty(s))
                {
                    Stack_Push(s,str1[i]);
                }
                else
                {
                    while(!Stack_IfEmpty(s))
                    {
                        Stack_Pop(s,str2[j]);
                        j++;
                    }
                    Stack_Push(s,str1[i]);
                }
            }
            
        }        
    }
    while(!Stack_IfEmpty(s))//输出剩余元素
    {
        Stack_Pop(s,str2[j]);
        j++;
    }
    strlen = j+1;
    Stack_Clear(s);//记得清空用过的栈给之后用
    return OK;
}
//碰到数字,入栈;碰到运算符,让栈的倒数两个元素出栈进行运算,运算结果入栈。直到运算结束。
int culculate(Stack s,char str[],int &len)
{
    int i,cul;
    char nex,pre,ret;
    Stack_Push(s,str[0]);
    for(i=1;i<len;i++)
    {
        if(char_or_num(str[i]))
        {
            Stack_Push(s,str[i]);//是数字,入栈
        }
        else
        {
            Stack_Pop(s,nex);
            Stack_Pop(s,pre);//栈顶两个元素出栈
            switch(str[i])
            {
                case '+':ret = cul_plus(pre,nex);break;
                case '-':ret = cul_minus(pre,nex);break;
                case '*':ret = cul_mul(pre,nex);break;
                case '/':ret = cul_div(pre,nex);break;
            }
            Stack_Push(s,ret);//运算完的结果入栈
        }   
    }
    ret = Stack_GetTop(s);//最后栈中只剩一个元素为运算结果
    cul = int(ret)-48;
    return cul;
}

main.cpp

#include "Stack.h"
#include "Culculate.h"
#include <iostream>
using namespace std;
int a[3] = {1,2,3};
/**************************字符串计算器逆波兰表达式运算求解**************************/
/***********这个计算器存在弊端,输入的数只能是0-9以内,大于9的数在整型字符型转换上相对复杂一些******/

//"9*2-(7+1)/((2+2)*2)="; //例子
char str1[22];
char str2[20];
int main()
{
    Stack s;
    int i = 0;
    Stack_Init(s);
    cout << "本计算器可运算混合运算,但输入的数字只能是0-9内的,主要还是本人太菜了"<<endl;
    cout << "请输入运算表达式,输入“=”按下回车开始运算"<<endl;
    int cul,len;
    for(i=0;;i++) //输入原表达式
    {
        cin >> str1[i];//可以直接把表达式敲进去
        if(str1[i] == '=')//输入结束
        {
            str1[i] = '\0';
            break;
        }
    }
    translate(s,str1,str2,len);//翻译成逆波兰表达式
    i = 0;
    cout << "逆波兰表达式为:";
    while(str2[i] != '\0')//输出翻译后的逆波兰表达式
    {
        cout << str2[i];
        i++;
    }
    cout << endl;
    cul = culculate(s,str2,len);
    cout << "计算结果为:";
    cout << cul <<endl;
    return 0;
}

运行结果

在这里插入图片描述

易错整理:

1、在这里插入图片描述
在这里插入图片描述

2、
在这里插入图片描述
在这里插入图片描述
3、栈顶top,队头,队尾的定义不是唯一的,要审题。

比如top大多数情况指最后入栈元素的下一个位置,有的时候题中指向最后一个入

栈的元素。

4、共享栈更有效利用存储空间,存取数据时间复杂度O(1),可能会发生上溢。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值