C 栈实例

就近匹配:
应用1:就近匹配
几乎所有的编译器都具有检测括号是否匹配的能力
如何实现编译器中的符号成对检测?
#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0; 

算法思路
从第一个字符开始扫描
当遇见普通字符时忽略,
当遇见左符号时压入栈中
当遇见右符号时从栈中弹出栈顶符号,并进行匹配
匹配成功:继续读入下一个字符
匹配失败:立即停止,并报错
结束:
成功: 所有字符扫描完毕,且栈为空
失败:匹配失败或所有字符扫描完毕但栈非空
当需要检测成对出现但又互不相邻的事物时
可以使用栈“后进先出”的特性
栈非常适合于需要“就近匹配”的场合

计算机的本质工作就是做数学运算,那计算机可以读入字符串
“9 + (3 - 1) * 5 + 8 / 2”并计算值吗?
#include "stdio.h"
#include "stdlib.h"
#include "linkstack.h"

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

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

    return ret;
}

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

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

    return ret;
}

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

    switch(left)
    {
    case ‘<‘:
        ret = (right == ‘>‘);
        break;
    case ‘(‘:
        ret = (right == ‘)‘);
        break;
    case ‘[‘:
        ret = (right == ‘]‘);
        break;
    case ‘{‘:
        ret = (right == ‘}‘);
        break;
    case ‘\‘‘:
        ret = (right == ‘\‘‘);
        break;
    case ‘\"‘:
        ret = (right == ‘\"‘);
        break;
    default:
        ret = 0;
        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, (void*)(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("Invalid 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 ;
}
中缀表达式和后缀表达式
应用2:中缀 后缀
计算机的本质工作就是做数学运算,那计算机可以读入字符串
“9 + (3 - 1) * 5 + 8 / 2”并计算值吗?
后缀表达式  ==?符合计算机运算
波兰科学家在20世纪50年代提出了一种将运算符放在数字后面的后缀表达式对应的,
我们习惯的数学表达式叫做中缀表达式===》符合人类思考习惯

实例:
5 + 4=> 5 4 +
1 + 2 * 3 => 1 2 3 * +
8 + ( 3 – 1 ) * 5 => 8 3 1 – 5 * +
中缀表达式符合人类的阅读和思维习惯
后缀表达式符合计算机的“运算习惯”
如何将中缀表达式转换成后缀表达式?
中缀转后缀算法:
遍历中缀表达式中的数字和符号
对于数字:直接输出
对于符号:
左括号:进栈
运算符号:与栈顶符号进行优先级比较
若栈顶符号优先级低:此符合进栈  (默认栈顶若是左括号,左括号优先级最低)
若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
右括号:将栈顶符号弹出并输出,直到匹配左括号
遍历结束:将栈中的所有符号弹出并输出
中缀转后缀
计算机是如何基于后缀表达式计算的?
8 3 1 – 5 * +
遍历后缀表达式中的数字和符号
对于数字:进栈
对于符号:
从栈中弹出右操作数
从栈中弹出左操作数
根据符号进行运算
将运算结果压入栈中
遍历结束:栈中的唯一数字为计算结果
栈的神奇!
中缀表达式是人习惯的表达方式
后缀表达式是计算机喜欢的表达方式
通过栈可以方便的将中缀形式变换为后缀形式
中缀表达式的计算过程类似程序编译运行的过程  

扩展:给你一个字符串,计算结果
“1 + 2 * (66 / (2 * 3) + 7 )”
1
字符串解析
词法语法分析
优先级分析
数据结构选型===》栈还是树?
#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]) )
        {
            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;
}

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

int isNumber3(char c)
{
    return (‘0‘ <= c) && (c <= ‘9‘);
}

int isOperator3(char c)
{
    return (c == ‘+‘) || (c == ‘-‘) || (c == ‘*‘) || (c == ‘/‘);
}

int value(char c)
{
    return (c - ‘0‘);
}

int express(int left, int right, char 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 compute(const char* exp)
{
    LinkStack* stack = LinkStack_Create();
    int ret = 0;
    int i = 0;

    while( exp[i] != ‘\0‘ )
    {
        if( isNumber3(exp[i]) )
        {
            LinkStack_Push(stack, (void*)value(exp[i]));
        }
        else if( isOperator3(exp[i]) )
        {
            int right = (int)LinkStack_Pop(stack);
            int left = (int)LinkStack_Pop(stack);
            int result = express(left, right, exp[i]);

            LinkStack_Push(stack, (void*)result);
        }
        else
        {
            printf("Invalid expression!");
            break;
        }

        i++;
    }

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

    LinkStack_Destroy(stack);

    return ret;
}

int main()
{
    printf("8 + (3 - 1) * 5  = %d\n", compute("831-5*+"));
    system("pause");
    return 0;
}
时间: 2024-10-06 15:02:17

C 栈实例的相关文章

压栈出栈遍历栈实例代码

#include<stdio.h> #include<stdlib.h> #include<malloc.h> typedef struct Node//定义一个链表结构体 { int data; struct Node* pNext; }NODE,*PNODE; typedef struct Stack//定义一个栈结构体 { PNODE pTop; PNODE pBottom; }STACK,*PSTACK; void initStack(PSTACK); void

JAVA栈实例—括号匹配

1 import java.util.Stack; 2 3 public class test { 4 public static void main(String[] args){ 5 System.out.print(isStringBalanced("asdasd)d")); 6 } 7 8 public static boolean isStringBalanced(String string){ 9 final char openrb = '('; //定义常量 10 fin

C语言函数调用栈(三)

6 调用栈实例分析 本节通过代码实例分析函数调用过程中栈帧的布局.形成和消亡. 6.1 栈帧的布局 示例代码如下: 1 //StackReg.c 2 #include <stdio.h> 3 4 //获取函数运行时寄存器%ebp和%esp的值 5 #define FETCH_SREG(_ebp, _esp) do{ 6 asm volatile( 7 "movl %%ebp, %0 \n" 8 "movl %%esp, %1 \n" 9 : "

框架学习之Struts2(三)---OGNL和值栈

一.OGNL概述 1.1OGNL是对象图导航语言(Object-Graph Navigation Languaged)的缩写,他是一种功能强大的表达式语言,通过简单一致的表达式语法,可以存取Java对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型的转化功能.他使用相同的表达式去存取对象的属性.如果吧表达式看作一个带有语义的字符串,那么OGNL无疑成为了这个语义字符串与java对象之间沟通的桥梁. 1.2OGNL的要素 表达式:表达式是整个OGNL的核心,OGNL会根据表达式去对

JVM 堆跟栈

需要说明一点,现存的JVM有好多种,Sun公司的是Sun Hotspot JVM 堆:是JVM用来储存对象的地方,他是存储单位(部门) 什么是对象? 首先要知道,Java并不是完全的面向对象的,因为基本数据类型的变量就不是一个对象. 除了Java的基本数据类型之外的所有的Object都是对象. 包括,类对象,接口对象和数组对象. 堆中的数据是所有线程共享的,所以在其中追加一个对象需要给他加上锁,这也是为什么new一个对象的系统开销比较大的原因. Sun Hotspot JVM中new一个对象,如

OGNL与值栈

一.OGNL入门 1.什么是OGNL OGNL的全称是对象图导航语言(Object-Graph Navigation Language),它是一种功能强大的开源表达式语言.使用这种表达式语言,可以通过使用某种表达式语言,来存取Java对象的任意属性,调用Java的方法,同时能够自动实现必要的数据类型转换, 2.OGNL的作用 Struts2默认的表达式语言就是ognl表达式语言,该语句具有以下的特点 支持对象方法的调用.例如:objectName.methodName(). 支持静态方法调用和值

[ SSH框架 ] Struts2框架学习之三(OGNl和ValueStack值栈学习)

一.OGNL概述 1.1 什么是OGNL OGNL的全称是对象图导航语言( object-graph Navigation Language),它是一种功能强大的开源表达式语言,使用这种表达式语言,可以通过某种表达式语法,存取Java对象的任意属性,调用Java对象的方法,同时能够自动实现必要的类型转换.如果把表达式看作是一个带有语义的字符串,那么OGNL无疑成为了这个语义字符串与Java对象之间沟通的桥梁. 1.2 OGNL的作用 Struts2默认的表达式语言就是OGNL,它具有以下特点:

PWN菜鸡入门之函数调用栈与栈溢出的联系

一.函数调用栈过程总结 Fig 1. 函数调用发生和结束时调用栈的变化 Fig 2. 将被调用函数的参数压入栈内 Fig 3. 将被调用函数的返回地址压入栈内 Fig 4. 将调用函数的基地址(ebp)压入栈内,并将当前栈顶地址传到 ebp 寄存器内 Fig 5. 将被调用函数的局部变量压入栈内 二.函数调用栈实例说明 首先我们来看看以下程序调用栈的过程: int sum(int a,int b) { int temp = 0; temp = a+b; return temp; } int ma

转 C# 装箱和拆箱[整理]

1.      装箱和拆箱是一个抽象的概念 2.      装箱是将值类型转换为引用类型 :拆箱是将引用类型转换为值类型       利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类型的值相互转换,将值类型与引用类型链接起来 例如: int val = 100; object obj = val; Console.WriteLine (“对象的值 = {0}", obj); 这是一个装箱的过程,是将值类型转换为引用类型的过程 int val = 100; object obj =