栈实现计算器

本文介绍了一种使用栈数据结构来解析和计算数学表达式的方法。通过创建两个栈,分别用于存储数值和运算符,文章详细解释了如何处理运算符的优先级,以及如何在遍历表达式字符串的过程中进行正确的计算。
public static void main(String[] args) {
         //完成表达式运算
        String s="30+2*5-6+7";
        //创建两个栈 一个数栈 一个符号栈
        ArrayStack arrayStack=new ArrayStack(10);
        ArrayStack arrayStack1=new ArrayStack(10);

        int index=0;
        int num1=0;
        int num2=0;
        int oper=0;
        int res=0;
        char ch=' ';
        String keepnum="";
        while (true)
        {
            //依次得到s中的每一个字符
            ch=s.charAt(index);

            if(!arrayStack.isOper(ch))
            {
                keepnum+=ch;
                if(index==s.length()-1)
                arrayStack.push(ch-48);
                else
                {
                    if(arrayStack.isOper(s.charAt(index+1)))
                    {
                        arrayStack.push(Integer.parseInt(keepnum));
                        System.out.println(keepnum);
                        keepnum="";

                    }
                }

            }
            else if(arrayStack.isOper(ch))
            {
                if(arrayStack1.isEmpty())
                {
                    arrayStack1.push(ch);
                }
              else   if(arrayStack.priority(ch)<=arrayStack.priority(arrayStack1.peek()))
                {

                    num1=arrayStack.pop();
                    num2=arrayStack.pop();
                    oper=arrayStack1.pop();
                    res=arrayStack.cal(num1,num2,oper);
                    arrayStack.push(res);
                    arrayStack1.push(ch);
                }
                else
                {
                    arrayStack1.push(ch);
                }
            }
            if(index==s.length()-1)
            {
                break;
            }
            index++;
        }
        while (!arrayStack1.isEmpty())
        {
            num1=arrayStack.pop();
            num2=arrayStack.pop();
            oper=arrayStack1.pop();
            res=arrayStack.cal(num1,num2,oper);
           arrayStack.push(res);
        }
        System.out.println(arrayStack.pop());
    }
}
//定义一个栈 增加一些功能
class ArrayStack
{
    private  int maxSize;
    private  int[]stack;
    private  int top=-1;
    public ArrayStack(int maxSize)
    {
        this.maxSize=maxSize;
        stack=new int[this.maxSize];

    }
    //判断栈满
    public  boolean isFull()
    {
        return  top==maxSize-1;
    }
    //判断栈空
    public  boolean isEmpty()
    {
        return  top==-1;
    }
    //入栈
    public  void push(int val)
    {
        if( isFull()) return;
        top++;
        stack[top]=val;
    }
    //出栈
    public int pop()
    {
        if(isEmpty()) return -1;
        int val=stack[top];
        top--;
        return   val;

    }
    //显示栈顶
    public int peek()
    {
        if(isEmpty()) return -1;
        int val=stack[top];
        return   val;

    }
    //返回运算符的优先级 优先级使用数字表示 数字越大 优先级越高
    public int priority(int oper)
    {
        if(oper=='*'||oper=='/') return 1;
        else if(oper=='+'||oper=='-') return 0;
        else
        {
            return -1; //假定目前表达式只有+ - * /
        }
    }
    //判断是否是一个运算符
    public  boolean isOper(char val)
    {
        return  val=='+'|| val=='-'|| val=='*'|| val=='/';
    }
    //计算方法
    public  int cal(int num1,int num2,int oper) {
        int res = 0;
        switch (oper) {
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1;
                break;
            case '/':
                res = num2 / num1;
                break;
            case '*':
                res = num1 * num2;
            default:
                break;
        }
        return  res;
    }
<think>我们使用实现一个计算器,能够处理加减乘除和括号的表达式。基本思路是使用两个:一个操作数(存放数字),一个运算符(存放运算符)。算法遵循以下步骤:1.初始化两个,运算符可以先压入一个优先级最低的运算符(如'#')作为哨兵。2.从左到右扫描表达式:a.如果是数字,则读取完整的数字(可能有多位和小数点),然后压入操作数。b.如果是运算符(包括括号):i.如果当前运算符是左括号'(',直接压入运算符。ii.如果当前运算符是右括号')',则不断弹出运算符顶的运算符并计算,直到遇到左括号(左括号弹出但不计算)。iii.如果是其他运算符(加减乘除),则与运算符顶的运算符比较优先级:-若当前运算符优先级高于顶运算符,则压入。-否则,弹出顶运算符并计算(从操作数弹出两个操作数),然后将当前运算符压入。3.当表达式扫描完后,如果运算符中还有运算符,则依次弹出并计算。4.最后操作数中剩下的一个数就是结果。注意:需要处理运算符的优先级,我们定义优先级:'(' >'*'='/' >'+' ='-' >'#',但是注意在中,左括号只有在遇到右括号时才弹出,所以左括号在内时优先级可以认为较低,但在外(即当前扫描到的)优先级较高。具体实现时,我们用一个函数来比较优先级:顶运算符和当前运算符。下面我们给出C语言的实现代码。由于C语言没有内置,我们需要自己实现的基本操作(初始化、入、出、取顶等)。注意:本实现假设输入的表达式是合法的,并且只包含数字、加减乘除和括号,以及小数点。我们使用字符串来存储表达式。步骤:1.定义结构及基本操作。 2.实现计算器类,包括读取数字、读取运算符、优先级比较、计算函数和主计算函数。由于用户要求使用C语言,我们将用C语言实现。注意:我们使用数组来实现(固定大小),并假设表达式长度不超过一定限制。代码实现如下:</think>### C语言实现计算器算法详解 我们将使用两个(操作数和运算符实现支持加减乘除和括号的四则运算计算器。核心算法基于运算符优先级比较和操作,以下是完整实现: ```c #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <math.h> #define MAX_SIZE 100 // 结构定义 typedef struct { double data[MAX_SIZE]; int top; } NumStack; // 操作数 typedef struct { char data[MAX_SIZE]; int top; } OprStack; // 运算符 // 初始化 void initNumStack(NumStack* s) { s->top = -1; } void initOprStack(OprStack* s) { s->top = -1; } // 操作函数 void pushNum(NumStack* s, double val) { if (s->top < MAX_SIZE - 1) s->data[++(s->top)] = val; } double popNum(NumStack* s) { if (s->top >= 0) return s->data[(s->top)--]; return 0; } void pushOpr(OprStack* s, char op) { if (s->top < MAX_SIZE - 1) s->data[++(s->top)] = op; } char popOpr(OprStack* s) { if (s->top >= 0) return s->data[(s->top)--]; return '\0'; } char topOpr(OprStack* s) { if (s->top >= 0) return s->data[s->top]; return '\0'; } // 运算符优先级判断 int precedence(char op) { switch (op) { case '+': case '-': return 1; case '*': case '/': return 2; case '(': return 0; // 括号特殊处理 default: return -1; } } // 执行二元运算 void calculate(NumStack* numStack, char op) { double b = popNum(numStack); double a = popNum(numStack); switch (op) { case '+': pushNum(numStack, a + b); break; case '-': pushNum(numStack, a - b); break; case '*': pushNum(numStack, a * b); break; case '/': if (fabs(b) < 1e-6) { fprintf(stderr, "Error: Division by zero\n"); exit(EXIT_FAILURE); } pushNum(numStack, a / b); break; } } // 主计算函数 double evaluateExpression(const char* expr) { NumStack numStack; OprStack oprStack; initNumStack(&numStack); initOprStack(&oprStack); pushOpr(&oprStack, '#'); // 哨兵运算符 int i = 0; while (expr[i] != '\0') { // 处理数字(含小数) if (isdigit(expr[i]) || expr[i] == '.') { char numStr[20]; int j = 0; while (isdigit(expr[i]) || expr[i] == '.') { numStr[j++] = expr[i++]; } numStr[j] = '\0'; pushNum(&numStack, atof(numStr)); continue; } // 处理运算符 else if (strchr("+-*/()", expr[i])) { char currentOp = expr[i]; // 左括号直接入 if (currentOp == '(') { pushOpr(&oprStack, currentOp); } // 右括号:计算直到匹配左括号 else if (currentOp == ')') { while (topOpr(&oprStack) != '(') { calculate(&numStack, popOpr(&oprStack)); } popOpr(&oprStack); // 弹出左括号 } // 普通运算符:比较优先级 else { while (precedence(currentOp) <= precedence(topOpr(&oprStack))) { calculate(&numStack, popOpr(&oprStack)); } pushOpr(&oprStack, currentOp); } i++; } // 跳过空格 else if (isspace(expr[i])) { i++; } // 非法字符处理 else { fprintf(stderr, "Error: Invalid character '%c'\n", expr[i]); exit(EXIT_FAILURE); } } // 处理中剩余运算符 while (topOpr(&oprStack) != '#') { calculate(&numStack, popOpr(&oprStack)); } return popNum(&numStack); } int main() { char expression[100]; printf("输入表达式 (支持+-*/()): "); fgets(expression, sizeof(expression), stdin); expression[strcspn(expression, "\n")] = '\0'; // 移除换行符 double result = evaluateExpression(expression); printf("结果: %.2f\n", result); return 0; } ``` ### 算法核心逻辑 1. **双结构**: - 操作数 (`NumStack`):存储运算数字 - 运算符 (`OprStack`):存储运算符和括号 2. **优先级处理**: - 运算符优先级:`*/` > `+-` > `(` - 遇到高优先级运算符时先计算顶操作 - 括号特殊处理:左括号直接入,右括号触发内计算直到左括号 3. **计算流程**: ```mermaid graph TD A[开始] --> B{扫描字符} B -->|数字| C[读取完整数字入操作数] B -->|运算符| D{是括号?} D -->|'('| E[直接入运算符] D -->|')'| F[计算直到弹出'('] D -->|其他| G[比较优先级并计算] B -->|结束| H[计算内剩余操作] H --> I[返回结果] ``` 4. **关键函数**: - `precedence()`:定义运算符优先级 - `calculate()`:执行二元运算 - `evaluateExpression()`:主调度函数 ### 示例运算过程 对于表达式 `3*(5-2)+4`: 1. 操作数:`[3]` → `[3,5]` → `[3,5,2]` 2. 运算符:`[#]` → `[#, *]` → `[#, *, (]` → `[#, *]` (遇到`-`) 3. 计算 `5-2=3` → 操作数变为 `[3,3]` 4. 计算 `3*3=9` → 操作数 `[9]` 5. 继续处理 `+4` → 最终结果 `13` ### 注意事项 1. 支持小数运算(如 `3.14*2`) 2. 错误检测:除零错误、非法字符 3. 括号必须成对出现 4. 输入表达式不应包含空格以外的特殊字符 此实现完整展示了在表达式求值中的应用,通过运算符优先级管理实现了正确的计算顺序[^1][^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值