栈的应用

栈的简单应用


我们可以重复利用之前写过的[栈的链式存储](http://blog.csdn.net/strugglingmice/article/details/75195411)中的代码,在此基础上完成栈的一下的一些简单的应用。

(一)就近匹配

**几乎所有的编译器都具有检测括号是否匹配的能力,如何实现编译器中的符号成对检测?**
当需要检测成对出现但又互不相邻的事物,可以使用栈“后进先出”的特,栈非常适合于需要'就近匹配'的场合。
    #include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0; 

算法思路

①从第一个字符开始描;
②当遇见普通字符时忽略,当遇见左符号时压入中;
③当遇见右符号时从栈中弹出栈顶符号,并进行配;
匹配成功:继续读入下一个字符;
匹配失败:立即停止,并报错;
④结束:
成功:所有字符扫描完毕,且栈为空;
失败:匹配失败或所有所有字符扫描完毕但栈非空。

就近匹配的实现

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

int isLeft(char c)
{
    int ret = 0;

    switch (c)
    {
    case '<':
    case '(':
    case'{':
    case'[':
    case '\'':
    case '\"':
        ret = 1;
        break;
    default:
        break;
    }
    return ret;
}

int isRight(char c)
{
    int ret = 0;

    switch (c)
    {
    case '>':
    case ')':
    case'}':
    case']':
    case '\'':
    case '\"':
        ret = 1;
        break;
    default:
        break;
    }
    return ret;
}

int match(char left, char right)
{
    int ret = 0;

    switch (left)
    {
    case '<':
        if (right == '>')
        {
            ret = 1;
        }
        break;
    case '(':
        if (right == ')')
        {
            ret = 1;
        }
        break;
    case '{':
        if (right == '}')
        {
            ret = 1;
        }
        break;
    case '[':
        if (right == ']')
        {
            ret = 1;
        }
        break;
    case '\'':
        if (right == '\'')
        {
            ret = 1;
        }
        break;
    case '\"':
        if (right == '\"')
        {
            ret = 1;
        }
        break;
    default:
        break;
    }
    return ret;
}

int scanner(const char *code)
{
    LinkStack *stack = LinkStack_Create();
    int ret = 0;
    int i = 0;

    while (code[i] != '\0')
    {
        //当遇见普通字符时忽略
        if (isLeft(code[i]))
        {//当遇见左符号时压入栈中
            LinkStack_Push(stack, (LinkStackNode*)(code + i));//&code[i]
        }

        if (isRight(code[i]))
        {// 当遇见右符号时从栈中弹出栈顶符号,并进行匹配
         //匹配成功:继续读入下一个字符;
            char *c = (char *)LinkStack_Pop(stack);

            if ((c == NULL) || !match(*c, code[i]))
            {//匹配失败:立即停止,并报错。
                printf("%c does not match!\n", code[i]);
                ret = 0;
                break;
            }
        }
        i++;
    }
    if ((LinkStack_Size(stack) == 0) && (code[i]) == '\0')
    {//成功:所有字符扫描完毕,且栈为空
        printf("Succeed!\n");
        ret = 1;
    }
    else
    {//失败:匹配失败或所有字符扫描完毕,但栈非空
        printf("Invalide code!\n");
        ret = 0;
    }
    LinkStack_Destroy(stack);

    return ret;
}


void main()
{
    const char *code = "#include <stdio.h> int main(){int a[4][4], int (*p)[4];p=a[0];return 0;";
    scanner(code);
    system("pause");
    return;
}

结果截图

括号匹配


(二)中缀转后缀

计算机的本质工作就是做数学运算,那计算机可以读入字符串“9 + (3 - 1) * 5 + 8 / 2”并计算值吗?
(1)中缀表达式符合人类的阅读和思维习惯;
(2)后缀表达式符合计算机的”运算习惯”;
(3)如何将中缀表达式转换成后缀表达式?

算法思路

①遍历中缀表达式中的数字和符号;
②对于数字:直接输出;
③对于符号:
左括号:进栈;
运算符:与栈顶运算符号进行优先级比较;若栈顶优先级低,此符号进栈(默认栈顶若是左括号,左括号优先级最低);若是栈顶符号优先级不低,将栈顶符号弹出并输出,之后进栈;
右括号:将栈顶符号弹出,直到匹配左括号;
④遍历结束:将栈中的所有符号弹出并输出。

中缀转后缀的实现

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "linkstack.h"

int isNumber(char c)
{
    return ('0' <= c) && (c <= '9');
}

int isOperator(char c)
{
    return (c == '+') || (c == '-') || (c == '*') || (c == '/');
}

int isLeft(char c)
{
    return (c == '(');
}

int isRight(char c)
{
    return (c == ')');
}

int priority(char c)
{
    int ret = 0;

    if ((c == '+') || (c == '-'))
    {
        ret = 1;
    }

    if ((c == '*') || (c == '/'))
    {
        ret = 2;
    }

    return ret;
}

void output(char c)
{
    if (c != '\0')
    {
        printf("%c", c);
    }
}

void transform(const char* exp)
{
    int i = 0;
    LinkStack* stack = LinkStack_Create();

    while (exp[i] != '\0')
    {
        if (isNumber(exp[i]))
        {
            output(exp[i]);
        }
        else if (isOperator(exp[i]))
        {
            if (LinkStack_Size(stack)>0)//往栈中插入第一个符号时
            {
                while (priority(exp[i]) <= priority((char)(int)LinkStack_Top(stack)))
                {
                    output((char)(int)LinkStack_Pop(stack));

                }
            }

            LinkStack_Push(stack, (void*)(int)exp[i]);
        }
        else if (isLeft(exp[i]))
        {
            LinkStack_Push(stack, (void*)(int)exp[i]);
        }
        else if (isRight(exp[i]))
        {
            //char c = '\0';
            while (!isLeft((char)(int)LinkStack_Top(stack)))
            {
                output((char)(int)LinkStack_Pop(stack));
            }

            LinkStack_Pop(stack);
        }
        else
        {
            printf("Invalid expression!");
            break;
        }

        i++;
    }

    while ((LinkStack_Size(stack) > 0) && (exp[i] == '\0'))
    {
        output((char)(int)LinkStack_Pop(stack));
    }

    LinkStack_Destroy(stack);
}

int main()
{
    transform("8+(3-1)*5");

    printf("\n");
    system("pause");
    return 0;
}

结果截图

中缀转后缀


(三)后缀表达式的计算

实例
中缀表达式:8+(3-1)﹡5的后缀表达式为:831-5﹡+ 。

算法思路

①对于数字:进栈;
②对于符号: 从栈中弹出右操作数; 从栈中弹出左操作数;根据符号进行运算; 根据符号进行运算;
③遍历结束:栈中的唯一数字为计算结果。

后缀表达式计算的实现

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


int isNumber(char c)
{
    return (('0' <= c) && (c <= '9'));
}

int isOperator(char c)
{
    return ((c == '+') || (c == '-') || (c == '*') || (c == '/'));
}

int vlaue(char c)
{
    return (c - '0');
}

int express(int left, int right, int op)
{
    int ret = 0;
    switch (op)
    {
    case '+':
        ret = left + right;
        break;
    case '-':
        ret = left - right;
        break;
    case '*':
        ret = left*right;
        break;
    case '/':
        ret = left / right;
        break;
    default :
        break;
    }
    return ret;
}

int computer(const char *exp)
{
    LinkStack *stack = LinkStack_Create();
    int ret = 0;
    int i = 0;

    while (exp[i] != '\0')
    {
        if (isNumber(exp[i]))
        {
            LinkStack_Push(stack, (LinkStackNode *)vlaue(exp[i]));    //831-5*+
        }
        else if (isOperator(exp[i]))
        {
            int right = (int)LinkStack_Pop(stack);
            int left = (int)LinkStack_Pop(stack);

            int result = express(left, right, exp[i]);
            LinkStack_Push(stack, (LinkStackNode *)result);
        }
        else 
        {
            printf("Invalid expression!\n");
            break;
        }
        i++;
    }

    if (LinkStack_Size(stack) == 1 && (exp[i] == '\0'))
    {
        ret = (int)LinkStack_Pop(stack);
    }
    else
    {
        printf("Invalid expression!\n");
    }
    LinkStack_Destroy(stack);
    return ret;
}


int main()
{
    printf("8+(3-1)*5=%d\n", computer("831-5*+"));
    system("pause");
    return 0;
}

结果截图
后缀表达式的计算

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值