| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3810 人关注过本帖, 2 人收藏
标题:如果检验一个输入的"常量表达式"是否合法~
只看楼主 加入收藏
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
结帖率:99.25%
收藏(2)
已结贴  问题点数:100 回复次数:12 
如果检验一个输入的"常量表达式"是否合法~
现在有一个表达式(里面都是合法运算符合常量而且可能会有括号和浮点数)
现在需要一个程序来判断该表达式是否合法~

表达式运算符只有'+','-''*','/','(',')'和小数点'.'
数字以十进制0-9的形式输入~

所谓合法就是指能在编译器正常通过编译的表达式~

例如:
1+2+3---合法
2.2+3*4---合法
-5+6*(4+1)/3+2---合法(最前一位可以是负号)
((4+3)+2---非法(左右括号不匹配)
4.65**2--非法(运算符号问题)
.45+1和45.和5.666.7---非法(小数点不合法)
45+22+   ---非法(最后一个运算符号找不到数字匹配)
56#33    ---非法(含有非法运算符)
777+()/3 ---非法(括号内容不能为空)
12+(34)3 ---非法(括号右端必须跟运算符)

PS:3+-4或者3-+4也是合法表达式,但3--4和3++4就是非法表达式了(不能正常通过编译)~

总之~能通过编译器编译的常量表达式都是合法表达式~
否则就不是合法表达式~

输入一串字符串,判断该表达式是否是合法表达式(字符串长度在100以内)~

感觉要考虑的情况很多的样子~看看有没有高手能给些高见?~感觉数据结构很冷清啊~还是发在人气较旺的C论坛比较好~希望有高手能做出来~~~



[此贴子已经被作者于2017-3-22 23:03编辑过]

搜索更多相关主题的帖子: 编译器 表达式 十进制 小数点 
2017-03-22 22:55
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
公测一下这个~~~
检查表达式是否正确是实现四则混合运算的基础~
这段代码只是完善了检查表达式是否合法的功能~暂时还没有检查出BUG(除了前导0这个问题可以忽略)~~~

程序代码:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>

#define LEN_Node sizeof (Node)
#define LEN_Single sizeof (Single)

typedef enum COM
{

 
    NUMBER,             //数字 
    SINGLE,             //运算符号(加减乘除)

    ADD,                //加号
    SUB,                //减号
    MUL,                //乘号
    DIV,                //除法
    POINT,              //小数点
    LEFT_PARENTHESES,   //左括号
    RIGHT_PARENTHESES,  //右括号

    WAIT_USE,           //等待使用(对于小数点处理)
    CAN_USE,            //可以使用
    CANNOT_USE,         //不能使用
    OK,                 //正常
    ERROR,              //出错
}COM;

typedef struct Single    //运算符号
{
    char c;              //符号标记
    int level;           //符号运算优先等级
}Single;

Single single[]={'(',1,')',1,'*',2,'/',2,'+','3','-',3,'.',4};

typedef struct Single_Style
{
    COM num;                      //检查能否使用数字
    COM add;                      //加法状态
    COM sub;                      //减法状态
    COM mul;                      //乘法状态
    COM div;                      //除法状态
    COM point;                    //小数点状态
    COM left_parentheses;         //左括号状态
    COM right_parentheses;        //右括号状态

}Single_Style;

Single_Style com={0};

typedef struct Node  
{
    char c;
    struct Node* next;
}Node,*PNode;

char Num_Buff[100]={0};                          //数据缓冲空间

PNode New_Node(PNode head,int size);             //创建一个头节点
PNode Init(PNode head);                          //创建一个表达式

COM Find_Single(char c,char*ch ,int* level);     //查找是否存在符号
void Single_CAN_USE();                           //运算符可以使用
void Single_CANNOT_USE();                        //运算符不可以使用
 
COM Check(PNode head);                           //检查表达式输入是否合法
void Print(PNode p);                             //输出数据

int main()
{
    PNode head=NULL;

    head=New_Node(head,LEN_Node);

    head=Init(head);

    if (Check(head)==ERROR)
    {
        puts("输入表达式有误!");
        exit(0);
    }

    Print(head);

    return 0;
}

PNode New_Node(PNode p,int Size)  //创建一个头节点
{
    p=(PNode)malloc(Size);

    if (p==NULL)
    {
        puts("创建失败!");
        exit(0);
    }
    memset(p,0,Size);

    return p;
}

PNode Init(PNode head)   //创建一个表达式
{
    PNode p=head;
    char ch=0;

    while (p->next)      //把指针移到尾部
        p=p->next;

    puts("请输入表达式:");
    while ((ch=getchar())!='\n')
    {
        p=p->next=New_Node(p,LEN_Node);
        p->c=ch;
    }

    return head;
}

void Print(PNode p)      //输出数据
{
    puts("输入表达式如下:");
    for (;p=p->next;printf("%c",p->c));
    puts("");
}

int Find_Single(char c,char*ch ,int* level)    //查找是否存在符号
{
    int i=0;
    if (isdigit(c))
        return NUMBER;  //返回数字

    for (i=0;c!=single[i].c&&i<sizeof(single)/sizeof(*single);++i);

    if (i==sizeof(single)/sizeof(*single))  //如果找不到运算符号,则显示出错
        return ERROR;

    *ch=single[i].c;
    *level=single[i].level;

    switch (single[i].c)  
    {
        case '(':
            return LEFT_PARENTHESES;
        case ')':
            return RIGHT_PARENTHESES;
        case '+':
            return ADD;
        case '-':
            return SUB;
        case '*':
            return
                MUL;
        case '/': 
            return DIV;
        case '.':
            return POINT;

        default :
            return ERROR;
    }
}

void Single_CAN_USE()        
{
    com.add=CAN_USE;               //可以使用加法
    com.sub=CAN_USE;               //可以使用减法
    com.mul=CAN_USE;               //可以使用乘法
    com.div=CAN_USE;               //可以使用除法
}

void Single_CANNOT_USE()
{
    com.add=CANNOT_USE;              //不可以使用加法
    com.sub=CANNOT_USE;              //不可以使用减法
    com.mul=CANNOT_USE;              //不可以使用乘法
    com.div=CANNOT_USE;              //不可以使用除法
    com.point=CAN_USE;
    com.left_parentheses=CAN_USE;    //可以使用左括号
    com.right_parentheses=CANNOT_USE;//不可以使用右括号
}

COM Check(PNode head)
{
    PNode p=head;

    COM cc=0;
    int parentheses=0;          //判断括号是否合理,初始记录括号数目为0
    int point=WAIT_USE;         //判断小数点是否合理  
    char ch=0;
    char t_ch=0;                //暂存单元
    int level=0;                //运算符优先等级记录(初始化暂不需要)

    com.num=CAN_USE;
    com.add=CAN_USE;                  //初始化加号可以用
    com.sub=CAN_USE;                  //初始化减号可以用
    com.mul=CANNOT_USE;               //初始化乘号可以用
    com.div=CANNOT_USE;               //初始化除号可以用
    com.point=WAIT_USE;               //初始化小数点等待使用
    com.left_parentheses=CAN_USE;     //初始化左括号可以使用
    com.right_parentheses=CANNOT_USE; //初始化右括号不可以使用

    while (p=p->next)                //判断所有字符输入都是合法数据
    {
        switch (Find_Single(p->c,&ch,&level))
        {
            case NUMBER:   //数字
                if (com.num==CANNOT_USE) 
                    return ERROR;

                Single_CAN_USE();         //运算符号可以使用
                if (com.point==WAIT_USE)
                    com.point=CAN_USE;

                com.right_parentheses=CAN_USE;  //数字后面可以跟右括号
                break;

            case ADD:
                if (com.add==CANNOT_USE)
                    return ERROR;

                Single_CANNOT_USE();        //不可以连续使用运算符号
                com.point=WAIT_USE;         //小数点可以等待使用
                com.sub=CAN_USE;             //加号后面可以跟减号
                com.num=CAN_USE;            //符号右边可以使用数字
                break;

            case SUB:
                if (com.sub==CANNOT_USE)
                    return ERROR; 

                Single_CANNOT_USE();        //不可以连续使用运算符号
                com.point=WAIT_USE;
                com.add=CAN_USE;            //可以使用加号
                com.num=CAN_USE;
                break;

            case MUL:
                if (com.mul==CANNOT_USE)
                    return ERROR;
            case DIV:
                if (com.div==CANNOT_USE)
                    return ERROR;

                Single_CANNOT_USE();        //如果遇到乘除运算符号,则该符号不能连续使用
                com.point=WAIT_USE;
                com.num=CAN_USE;
                break;

            case POINT:
                if (com.point==CAN_USE)
                {
                    Single_CANNOT_USE();                //小数点后面不能直接跟运算符号
                    com.left_parentheses=CANNOT_USE;    //左括号不能使用
                    com.right_parentheses=CANNOT_USE;   //右括号不能使用
                    com.point=CANNOT_USE;

                }
                else 
                    return ERROR;
                break;

            case LEFT_PARENTHESES:
                if (com.left_parentheses==CANNOT_USE)
                    return ERROR;

                ++parentheses;                         //记录括号标记个数+1
                Single_CANNOT_USE();                   //不可以使用运算符号
                com.right_parentheses=CANNOT_USE;      //右括号不能使用
                com.add=CAN_USE;                       //重置可以使用加号
                com.sub=CAN_USE;                       //重置可以使用减号
                break;

            case RIGHT_PARENTHESES:
                if (com.right_parentheses==CANNOT_USE)
                    return ERROR;

                --parentheses;                         //记录括号标记个数-1
                if (parentheses<0)                     //如果括号标记小于0
                    return ERROR;

                Single_CAN_USE();                      //可以使用运算符号
                com.num=CANNOT_USE;                    //右括号右端不能使用数字
                break;

            case ERROR:
                return ERROR;

            default :
                return ERROR;
        } 

        t_ch=p->c;   //记录暂存单元
    }
    
    cc=Find_Single(t_ch,&ch,&level);

    if (t_ch!='\0'&&cc!=NUMBER&&cc!=RIGHT_PARENTHESES)  //考虑尾数不是数字和右括号的情况
        return ERROR;

    if (parentheses!=0)         //如果括号不匹配
        return ERROR;

    return OK;
}




[此贴子已经被作者于2017-3-23 05:26编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-03-23 00:43
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
更新完毕~可以实现四则混合运算功能~还没有去优化~感觉还可以~试试效果如何~

程序代码:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<conio.h>
#include<string.h>

#define LEN_Node sizeof (Node)
#define LEN_Single sizeof (Single)
#define LEN_Ltem sizeof (Ltem)

typedef enum COM
{

 
    NUMBER,             //数字 
    SINGLE,             //运算符号(加减乘除)

    ADD,                //加号
    SUB,                //减号
    MUL,                //乘号
    DIV,                //除法
    POINT,              //小数点
    LEFT_PARENTHESES,   //左括号
    RIGHT_PARENTHESES,  //右括号

    WAIT_USE,           //等待使用
    CAN_USE,            //可以使用
    CANNOT_USE,         //不能使用

    OK,                 //正常
    ERROR,              //出错
}COM;

typedef struct Single    //运算符号
{
    char c;              //符号标记
    int level;           //符号运算优先等级
}Single;

Single single[]={'(',1,')',1,'*',2,'/',2,'+','3','-',3,'.',4};

typedef struct Single_Style
{
    COM num;                      //检查能否使用数字
    COM add;                      //加法状态
    COM sub;                      //减法状态
    COM mul;                      //乘法状态
    COM div;                      //除法状态
    COM point;                    //小数点状态
    COM left_parentheses;         //左括号状态
    COM right_parentheses;        //右括号状态

}Single_Style;

Single_Style com={0};

typedef struct Node  
{
    char c;
    struct Node* next;
}Node,*PNode;

typedef union Date            //用共用体储存数据
{
    double num;
    Single single;
}Date;

typedef struct Ltem
{
    COM com;
    Date date;
    struct Ltem* next;

}Ltem,*PLtem;

PNode New_Node(int size);                        //创建一个头节点
PNode Init(PNode head);                          //创建一个表达式
PNode Del_Node(PNode p);                         //删除一个节点            

COM Find_Single(char c,char*ch ,int* level);     //查找是否存在符号
void Single_CAN_USE();                           //运算符可以使用
void Single_CANNOT_USE();                        //运算符不可以使用
 
COM Check(PNode head);                           //检查表达式输入是否合法
void Print(PNode p);                             //输出数据

PLtem New_Ltem();                                //创建一个项
PLtem Push_Ltem(PLtem h_ltem,PNode h_node);      //插入一个项
PLtem Del_Ltem(PLtem p);                         //删除一个项
void Print_Ltem(PLtem p);                        //输出一个项

PLtem Del_Parentheses(PLtem h_ltem);              //消去括号(原理:括号里面只有一个常数项就可以消除)
PLtem Count_Mul_Div(PLtem h_ltem);                //计算乘除法运算
PLtem Count_Add_Sub(PLtem h_ltem);                //计算加减法运算

int main()
{
    puts("说明:输入表达式只含有+-*/四种运算符号,支持括号和浮点数运算,按ESC键退出");

    while (1)
    {
        PNode head=NULL;
        PLtem h_ltem=NULL;

        head=New_Node(LEN_Node);
        head=Init(head);

        if (head->next==NULL)
        {
            free(head);
            continue;
        }

        if (Check(head)==ERROR)
        {
             puts("输入表达式有误!");
            free(head);
             continue;
        }

        h_ltem=New_Ltem(h_ltem);
        h_ltem=Push_Ltem(h_ltem,head);

        free(head);
        head=NULL;

        Print_Ltem(h_ltem);

        while (h_ltem->next&&h_ltem->next->next)
        {
            h_ltem=Del_Parentheses(h_ltem);        //去除括号处理
            h_ltem=Count_Mul_Div(h_ltem);          //计算乘除法运算
            h_ltem=Count_Add_Sub(h_ltem);          //计算加减运算
        }      

        printf("运算结果是:%g\n",h_ltem->next->date.num);

        free(h_ltem->next);
        free(h_ltem);
        h_ltem=NULL;

        puts("按ESC键退出,其余键继续");

        if (getch()==27)
            break;
    }

    return 0;
}

PNode New_Node(int Size)  //创建一个头节点
{
    PNode p=(PNode)malloc(Size);

    if (p==NULL)
    {
        puts("创建失败!");
        exit(0);
    }
    memset(p,0,Size);

    return p;
}

PNode Init(PNode head)   //创建一个表达式
{
    PNode p=head;
    char ch=0;

    while (p->next)      //把指针移到尾部
        p=p->next;

    puts("请输入表达式:");
    while ((ch=getchar())!='\n')
    {
        p=p->next=New_Node(LEN_Node);
        p->c=ch;
    }

    return head;
}

PNode Del_Node(PNode p)            //删除一个节点,并把链表指针移动向下一个节点(相当于出队功能) 
{
    PNode tp=NULL;
    PNode ttp=p;    

    if (p==NULL||p->next==NULL)
        return NULL;

    tp=p->next;
    p=tp->next;
    free(tp);

    ttp->next=p;

    return ttp;
}

void Print(PNode p)      //输出数据
{
    puts("输入表达式如下:");
    for (;p=p->next;printf("%c",p->c));
    puts("");
}

int Find_Single(char c,char*ch ,int* level)    //查找是否存在符号
{
    int i=0;

    if (isdigit(c))
        return NUMBER;  //返回数字

    for (i=0;c!=single[i].c&&i<sizeof(single)/sizeof(*single);++i);

    if (i==sizeof(single)/sizeof(*single))  //如果找不到运算符号,则显示出错
        return ERROR;

    *ch=single[i].c;
    *level=single[i].level;

    switch (single[i].c)  
    {
        case '(':
            return LEFT_PARENTHESES;
        case ')':
            return RIGHT_PARENTHESES;
        case '+':
            return ADD;
        case '-':
            return SUB;
        case '*':
            return
                MUL;
        case '/': 
            return DIV;
        case '.':
            return POINT;

        default :
            return ERROR;
    }
}

void Single_CAN_USE()        
{
    com.add=CAN_USE;               //可以使用加法
    com.sub=CAN_USE;               //可以使用减法
    com.mul=CAN_USE;               //可以使用乘法
    com.div=CAN_USE;               //可以使用除法
}

void Single_CANNOT_USE()
{
    com.add=CANNOT_USE;              //不可以使用加法
    com.sub=CANNOT_USE;              //不可以使用减法
    com.mul=CANNOT_USE;              //不可以使用乘法
    com.div=CANNOT_USE;              //不可以使用除法
    com.point=CAN_USE;
    com.left_parentheses=CAN_USE;    //可以使用左括号
    com.right_parentheses=CANNOT_USE;//不可以使用右括号
}

COM Check(PNode head)
{
    PNode p=head;

    COM cc=0;
    int parentheses=0;          //判断括号是否合理,初始记录括号数目为0
    int point=WAIT_USE;         //判断小数点是否合理  
    char ch=0;
    char t_ch=0;                //暂存单元
    int level=0;                //运算符优先等级记录(初始化暂不需要)

    com.num=CAN_USE;
    com.add=CAN_USE;                  //初始化加号可以用
    com.sub=CAN_USE;                  //初始化减号可以用
    com.mul=CANNOT_USE;               //初始化乘号可以用
    com.div=CANNOT_USE;               //初始化除号可以用
    com.point=WAIT_USE;               //初始化小数点等待使用
    com.left_parentheses=CAN_USE;     //初始化左括号可以使用
    com.right_parentheses=CANNOT_USE; //初始化右括号不可以使用

    while (p=p->next)                //判断所有字符输入都是合法数据
    {
        switch (Find_Single(p->c,&ch,&level))
        {
            case NUMBER:   //数字
                if (com.num==CANNOT_USE) 
                    return ERROR;

                Single_CAN_USE();         //运算符号可以使用
                if (com.point==WAIT_USE)
                    com.point=CAN_USE;

                com.right_parentheses=CAN_USE;  //数字后面可以跟右括号
                break;

            case ADD:
                if (com.add==CANNOT_USE)
                    return ERROR;

                Single_CANNOT_USE();        //不可以连续使用运算符号
                com.point=WAIT_USE;         //小数点可以等待使用
                com.sub=CAN_USE;             //加号后面可以跟减号
                com.num=CAN_USE;            //符号右边可以使用数字
                break;

            case SUB:
                if (com.sub==CANNOT_USE)
                    return ERROR; 

                Single_CANNOT_USE();        //不可以连续使用运算符号
                com.point=WAIT_USE;
                com.add=CAN_USE;            //可以使用加号
                com.num=CAN_USE;
                break;

            case MUL:
                if (com.mul==CANNOT_USE)
                    return ERROR;
            case DIV:
                if (com.div==CANNOT_USE)
                    return ERROR;

                Single_CANNOT_USE();        //如果遇到乘除运算符号,则该符号不能连续使用
                com.point=WAIT_USE;
                com.num=CAN_USE;
                break;

            case POINT:
                if (com.point==CAN_USE)
                {
                    Single_CANNOT_USE();                //小数点后面不能直接跟运算符号
                    com.left_parentheses=CANNOT_USE;    //左括号不能使用
                    com.right_parentheses=CANNOT_USE;   //右括号不能使用
                    com.point=CANNOT_USE;

                }
                else 
                    return ERROR;
                break;

            case LEFT_PARENTHESES:
                if (com.left_parentheses==CANNOT_USE)
                    return ERROR;

                ++parentheses;                         //记录括号标记个数+1
                Single_CANNOT_USE();                   //不可以使用运算符号
                com.right_parentheses=CANNOT_USE;      //右括号不能使用
                com.sub=CAN_USE;                       //重置可以使用加号
                com.add=CAN_USE;                       //重置可以使用减号
                break; 

            case RIGHT_PARENTHESES:
                if (com.right_parentheses==CANNOT_USE)
                    return ERROR;

                --parentheses;                         //记录括号标记个数-1
                if (parentheses<0)                     //如果括号标记小于0
                    return ERROR;

                Single_CAN_USE();                      //可以使用运算符号
                com.num=CANNOT_USE;                    //右括号右端不能使用数字
                break;

            case ERROR:
                return ERROR;

            default :
                return ERROR;
        } 

        t_ch=p->c;   //记录暂存单元
    }
    
    cc=Find_Single(t_ch,&ch,&level);

    if (t_ch!='\0'&&cc!=NUMBER&&cc!=RIGHT_PARENTHESES)  //考虑尾数不是数字和右括号的情况
        return ERROR;

    if (parentheses!=0)         //如果括号不匹配
        return ERROR;

    return OK;
}

PLtem New_Ltem()        //创建一个项
{
    PLtem p=(PLtem)malloc(LEN_Ltem);

    if (p==NULL)
    {
        puts("创建失败!");
        exit(0);
    }
    memset(p,0,LEN_Ltem);

    return p;
}

PLtem Push_Ltem(PLtem h_ltem,PNode h_node)   //把合法表达式的储存数据转化为浮点型和保存运算符号
{
    PLtem ltem=h_ltem;
    PNode node=h_node;
    int i=0;
    int flag=0;

    char Num_Buff[100]={0};                   //数据缓冲空间

    for (;node->next;i=0)
    {
        while (node->next->next&&isdigit(node->next->c)||(node->next->c=='.'))
        {
            Num_Buff[i++]=node->next->c;
            node=Del_Node(node);
        }

        Num_Buff[i]=node->next->c;
        if (i)
        {
            ltem=ltem->next=New_Ltem();
            ltem->com=NUMBER;
            ltem->date.num=atof(Num_Buff);
            flag=1;
        }
        else if (isdigit(node->next->c)&&flag==0)   //处理尾部读取数据情况
        {
                ltem=ltem->next=New_Ltem();
                ltem->com=NUMBER;
                ltem->date.num=atof(Num_Buff);
                node=Del_Node(node);
        }
        else if (!isdigit(node->next->c))
        {
            ltem=ltem->next=New_Ltem();
            ltem->com=SINGLE;
            Find_Single(node->next->c,&ltem->date.single.c,&ltem->date.single.level);

            node=Del_Node(node);
            flag=0;
        }
        else
            node=Del_Node(node);

        memset(Num_Buff,0,sizeof(Num_Buff));
    }

    return h_ltem;
}

PLtem Del_Ltem(PLtem p)     //删除一个项
{
    PLtem tp=NULL;
    PLtem ttp=p;    

    if (p==NULL||p->next==NULL)
        return NULL;

    tp=p->next;
    p=tp->next;
    free(tp);

    ttp->next=p;

    return ttp;
}

void Print_Ltem(PLtem p)
{
    puts("您输入的表达式为:");

    while (p=p->next)
    {
        if (p->com==NUMBER)
            printf("%g",p->date.num);
        else
            printf("%c",p->date.single.c);
    }

    puts("");
}

PLtem Del_Parentheses(PLtem h_ltem)  //去括号
{
    PLtem p1=h_ltem->next;
    PLtem p2=h_ltem->next;

    double temp=0;

    int this_single=0;          //判断正负号
    COM flag=WAIT_USE;
    COM flag2=WAIT_USE;

    while (p1=p2=h_ltem->next)
    {
        flag2=WAIT_USE;            //判断有没有消除括号
        while (p1&&p2)
        {
            p1=p2;                //每次p1和p2两个指针对齐
            this_single=0;        //判断正负号标记初始化为0
            flag=WAIT_USE;        //消除括号条件待定成立
            
            if (p2->com==NUMBER)  //如果是数字就继续移动
            {
                 p2=p2->next;
                continue;
            }

            if (p2->date.single.c!='(')  //如果是运算符号但不是左括号也继续移动
            {
                p2=p2->next;
                continue;
            }

            while (p1->com!=SINGLE||p1->date.single.c!=')')  //当遇到左括号时,要判断里面是否只有一个常数
            {
                p1=p1->next;

                if (p1->com==SINGLE&&p1->date.single.c=='-')  //用来判断正负号
                    this_single=!this_single;

                if (p1->com==SINGLE&&p1->date.single.c=='(')  //意味着这里面不是最内层括号
                    break;

                if (p1->com==NUMBER&&flag==WAIT_USE)
                {
                    temp=p1->date.num;
                    flag=CAN_USE;
                }
                else if (p1->com==NUMBER&&flag!=WAIT_USE)
                    flag=CANNOT_USE;
            }

            if (p1->com==SINGLE&&p1->date.single.c=='(')
            {
                p2=p1;
                continue;
            }

            if (flag!=CAN_USE)   //如果里面不只一个常数意味着不可以删除可以删除
            {
                p2=p1;
                continue;
            }

            if (this_single)   //这条件成立意味着里面是一个负数
                temp=-temp;

            p2->com=NUMBER;    //把左括号的位置换成数字    
            p2->date.num=temp; //赋值给这个位置

            while (p2->next!=p1)
                p2=Del_Ltem(p2);

            p2=Del_Ltem(p2);
            p1=p2;

            flag2=CAN_USE;
        }

        if (flag2!=CAN_USE)
            break;
    }

    return h_ltem;
}

PLtem Count_Mul_Div(PLtem h_ltem)                //计算乘除运算
{
    PLtem p1=h_ltem->next;

    while (p1->next)
    {
        if (p1->com==NUMBER&&p1->next->com==SINGLE&&p1->next->date.single.c=='*'&&p1->next->next->com==NUMBER)
        {
            p1->date.num*=p1->next->next->date.num;
            p1=Del_Ltem(p1);
            p1=Del_Ltem(p1);

            continue;
        }

        if (p1->com==NUMBER&&p1->next->com==SINGLE&&p1->next->date.single.c=='/'&&p1->next->next->com==NUMBER)
        {
            p1->date.num/=p1->next->next->date.num;
            p1=Del_Ltem(p1);
            p1=Del_Ltem(p1);

            continue;
        }

        p1=p1->next;
    }

    return h_ltem;
}

PLtem Count_Add_Sub(PLtem h_ltem)                //计算加减法运算
{

    PLtem p1=h_ltem->next;

    int flag=0;

     while (p1->next)      
    {
        if (p1->com==NUMBER||p1->next->com==NUMBER)  
        {
            p1=p1->next;
            continue;
        }

        if (p1->date.single.c!='+'&&p1->date.single.c!='-')
        {
            p1=p1->next;
            continue;
        }

        while (p1->next->com==SINGLE&&(p1->next->date.single.c=='+'||p1->next->date.single.c=='-'))
        {
            if (p1->next->date.single.c=='-')
                flag=!flag;

            p1=Del_Ltem(p1);
        }

        if (flag&&p1->date.single.c=='+')
            p1->date.single.c='-';
        else if (flag)
            p1->date.single.c='+';

        p1=p1->next;

    }

    p1=h_ltem->next;

    while (p1->next)
    {

        if (p1->com==NUMBER&&p1->next->com==SINGLE&&p1->next->date.single.c=='+'&&p1->next->next->com==NUMBER)
        {
            p1->date.num+=p1->next->next->date.num;
            p1=Del_Ltem(p1);
            p1=Del_Ltem(p1);

            continue;
        }

        if (p1->com==NUMBER&&p1->next->com==SINGLE&&p1->next->date.single.c=='-'&&p1->next->next->com==NUMBER)
        {
            p1->date.num-=p1->next->next->date.num;
            p1=Del_Ltem(p1);
            p1=Del_Ltem(p1);

            continue;
        }

        p1=p1->next;
    }

    return h_ltem;
}


[此贴子已经被作者于2017-3-24 12:46编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-03-23 05:26
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9025
专家分:54030
注 册:2011-1-18
收藏
得分:80 
参考一下这个链接
http://zh.
2017-03-23 09:31
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 4楼 rjsp
我还是尴尬一下那个网址我不知道什么原因用手机和电脑均不能链接上去啊~不知道有没有人上过去了~~

不过无论如何还是感谢大佬~~~

[此贴子已经被作者于2017-3-23 13:13编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-03-23 13:11
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9025
专家分:54030
注 册:2011-1-18
收藏
得分:0 
回复 5楼 九转星河
被墙了吧,你得学会翻墙^_^
调度场算法

调度场算法(Shunting Yard Algorithm)是一个用于将中缀表达式转换为后缀表达式的经典算法,由艾兹格·迪杰斯特拉引入,因其操作类似于火车编组场而得名。

目录
    1 简例
    2 详细的算法
    3 更详细的例子
    4 C++程序实现
    5 参见

简例
算法示意图,使用了3个空间。输入用符号代替,如果输入是一个数字则直接进输出队列,即图中 b),d),f),h)。如果输入是运算符,则压入操作符堆栈,即图中 c),e),但是,如果输入运算符的优先级低于或等于运算符栈顶的操作符优先级,则栈内元素进入输出队列,输入操作符压入运算符堆栈,即图中 g)。 最后,运算符堆栈内元素入输出队列,算法结束.

    输入:3+4

    将3入输出队列(每当输入一个数字时,直接进入输出队列)
    将+号压入运算堆栈
    将4入输出队列
    输入结束,将操作符堆栈中剩余操作符入输出队列
    在本情况下只有+号
    输出 3 4 +

通过这个例子可以看出两条规则:

    当读入一个数字时直接入输出队列
    当输入结束后,运算符队列中所有操作符入输出队列

详细的算法

    当还有记号可以读取时:

        读取一个记号。
        如果这个记号表示一个数字,那么将其添加到输出队列中。
        如果这个记号表示一个函数,那么将其压入栈当中。
        如果这个记号表示一个函数参数的分隔符(例如,一个半角逗号 , ):

            从栈当中不断地弹出操作符并且放入输出队列中去,直到栈顶部的元素为一个左括号为止。如果一直没有遇到左括号,那么要么是分隔符放错了位置,要么是括号不匹配。

        如果这个记号表示一个操作符,记做o1,那么:

            只要存在另一个记为o2的操作符位于栈的顶端,并且

                    如果o1是左结合性的并且它的运算符优先级要小于或者等于o2的优先级,或者
                    如果o1是右结合性的并且它的运算符优先级比o2的要低,那么

                将o2从栈的顶端弹出并且放入输出队列中(循环直至以上条件不满足为止);

            然后,将o1压入栈的顶端。

        如果这个记号是一个左括号,那么就将其压入栈当中。
        如果这个记号是一个右括号,那么:

            从栈当中不断地弹出操作符并且放入输出队列中,直到栈顶部的元素为左括号为止。
            将左括号从栈的顶端弹出,但并不放入输出队列中去。
            如果此时位于栈顶端的记号表示一个函数,那么将其弹出并放入输出队列中去。
            如果在找到一个左括号之前栈就已经弹出了所有元素,那么就表示在表达式中存在不匹配的括号。

    当再没有记号可以读取时:

        如果此时在栈当中还有操作符:

            如果此时位于栈顶端的操作符是一个括号,那么就表示在表达式中存在不匹配的括号。
            将操作符逐个弹出并放入输出队列中。

    退出算法。

更详细的例子
输入: 3 + 4 * 2 / ( 1 − 5 ) ^ 2 ^ 3 输入     动作     输出 (逆波兰表示法)     运算符栈     提示
3     将符号加入输出队列     3        

+     将符号压入操作符堆栈     3     +   

4     将符号加入输出队列     3 4     +   

*     将符号压入操作符堆栈     3 4     * +     *号的优先级高于+号
2     将符号加入输出队列     3 4 2     * +   

/     将堆栈中元素弹出,加入输出队列     3 4 2 *     +     /号和*号优先级相同
将符号压入操作符堆栈     3 4 2 *     / +     /号的优先级高于+号
(     将符号压入操作符堆栈     3 4 2 *     ( / +   

1     将符号加入输出队列     3 4 2 * 1     ( / +   

     将符号压入操作符堆栈     3 4 2 * 1     − ( / +   

5     将符号加入输出队列     3 4 2 * 1 5     − ( / +   

)     将堆栈中元素弹出,加入输出队列     3 4 2 * 1 5 −     ( / +     循环直到找到(号
将堆栈元素弹出     3 4 2 * 1 5 −     / +     括号匹配结束
^     将符号压入操作符堆栈     3 4 2 * 1 5 −     ^ / +     ^号的优先级高于/号
2     将符号加入输出队列     3 4 2 * 1 5 − 2     ^ / +   

^     将符号压入操作符堆栈     3 4 2 * 1 5 − 2     ^ ^ / +     ^号为从右至左求值
3     将符号加入输出队列     3 4 2 * 1 5 − 2 3     ^ ^ / +   

END     将栈中所有数据加入输出队列     3 4 2 * 1 5 − 2 3 ^ ^ / +        

C++程序实现

#include <cstring>
#include <cstdio>

// 操作符
// 优先级        符号        运算顺序
// 1        !        从右至左
// 2        * / %        从左至右
// 3        + -        从左至右
// 4        =        从右至左
int op_preced(const char c)
{
    switch(c)    {
        case '!':
            return 4;
        case '*':  case '/': case '%':
            return 3;
        case '+': case '-':
            return 2;
        case '=':
            return 1;
    }
    return 0;
}

unsigned int op_arg_count(const char c)
{
    switch(c)  {
        case '*': case '/': case '%': case '+': case '-': case '=':
            return 2;
        case '!':
            return 1;
    default:
         return c - 'A';
    }
    return 0;
}

#define op_left_assoc(c) (c == '+' || c == '-' || c == '/' || c == '*' || c == '%')
#define is_operator(c)   (c == '+' || c == '-' || c == '/' || c == '*' || c == '!' || c == '%' || c == '=')
#define is_function(c)   (c >= 'A' && c <= 'Z')
#define is_ident(c)      ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z'))

bool shunting_yard(const char *input, char *output)
{
    const char *strpos = input, *strend = input + strlen(input);
    char c, stack[32], sc, *outpos = output;
    unsigned int sl = 0;
    while(strpos < strend)   {
        c = *strpos;
        if(c != ' ')    {
            // 如果输入为一个数字,则直接入输出队列
            if(is_ident(c))  {
                *outpos = c; ++outpos;
            }
            // 如果输入为一个函数记号,则压入堆栈
            else if(is_function(c))   {
                stack[sl] = c;
                ++sl;
            }
            // 如果输入为函数分割符(如:逗号)
            else if(c == ',')   {
                bool pe = false;
                while(sl > 0)   {
                    sc = stack[sl - 1];
                    if(sc == '(')  {
                        pe = true;
                        break;
                    }
                    else  {
                        // 直到栈顶元素是一个左括号
                        // 从堆栈中弹出元素入输出队列
                        *outpos = sc; ++outpos;
                        sl--;
                    }
                }
                // 如果没有遇到左括号,则有可能是符号放错或者不匹配
                if(!pe)   {
                    printf("Error: separator or parentheses mismatched\n");
                    return false;
                }
            }
            // 如果输入符号为操作符,op1,然后:
            else if(is_operator(c))  {
                while(sl > 0)    {
                    sc = stack[sl - 1];
                    // While there is an operator token, o2, at the top of the stack
                    // op1 is left-associative and its precedence is less than or equal to that of op2,
                    // or op1 is right-associative and its precedence is less than that of op2,
                    if(is_operator(sc) &&
                        ((op_left_assoc(c) && (op_preced(c) <= op_preced(sc))) ||
                           (!op_left_assoc(c) && (op_preced(c) < op_preced(sc)))))   {
                        // Pop o2 off the stack, onto the output queue;
                        *outpos = sc; ++outpos;
                        sl--;
                    }
                    else   {
                        break;
                    }
                }
                // push op1 onto the stack.
                stack[sl] = c;
                ++sl;
            }
            // If the token is a left parenthesis, then push it onto the stack.
            else if(c == '(')   {
                stack[sl] = c;
                ++sl;
            }
            // If the token is a right parenthesis:
            else if(c == ')')    {
                bool pe = false;
                // Until the token at the top of the stack is a left parenthesis,
                // pop operators off the stack onto the output queue
                while(sl > 0)     {
                    sc = stack[sl - 1];
                    if(sc == '(')    {
                        pe = true;
                        break;
                    }
                    else  {
                        *outpos = sc; ++outpos;
                        sl--;
                    }
                }
                // If the stack runs out without finding a left parenthesis, then there are mismatched parentheses.
                if(!pe)  {
                    printf("Error: parentheses mismatched\n");
                    return false;
                }
                // Pop the left parenthesis from the stack, but not onto the output queue.
                sl--;
                // If the token at the top of the stack is a function token, pop it onto the output queue.
                if(sl > 0)   {
                    sc = stack[sl - 1];
                    if(is_function(sc))   {
                        *outpos = sc; ++outpos;
                        sl--;
                    }
                }
            }
            else  {
                printf("Unknown token %c\n", c);
                return false; // Unknown token
            }
        }
        ++strpos;
    }
    // When there are no more tokens to read:
    // While there are still operator tokens in the stack:
    while(sl > 0)  {
        sc = stack[sl - 1];
        if(sc == '(' || sc == ')')   {
            printf("Error: parentheses mismatched\n");
            return false;
        }
        *outpos = sc; ++outpos;
        --sl;
    }
    *outpos = 0; // Null terminator
    return true;
}

bool execution_order(const char *input) {
    printf("order: (arguments in reverse order)\n");
    const char *strpos = input, *strend = input + strlen(input);
    char c, res[4];
    unsigned int sl = 0, sc, stack[32], rn = 0;
    // While there are input tokens left
    while(strpos < strend)  {
        // Read the next token from input.
        c = *strpos;
        // If the token is a value or identifier
        if(is_ident(c))    {
            // Push it onto the stack.
            stack[sl] = c;
            ++sl;
        }
        // Otherwise, the token is an operator  (operator here includes both operators, and functions).
        else if(is_operator(c) || is_function(c))    {
            sprintf(res, "_%02d", rn);
            printf("%s = ", res);
            ++rn;
            // It is known a priori that the operator takes n arguments.
            unsigned int nargs = op_arg_count(c);
            // If there are fewer than n values on the stack
            if(sl < nargs) {
                // (Error) The user has not input sufficient values in the expression.
                return false;
            }
            // Else, Pop the top n values from the stack.
            // Evaluate the operator, with the values as arguments.
            if(is_function(c)) {
                printf("%c(", c);
                while(nargs > 0)    {
                    sc = stack[sl - 1];
                    sl--;
                    if(nargs > 1)    {
                        printf("%s, ", &sc);
                    }
                    else {
                        printf("%s)\n", &sc);
                    }
                    --nargs;
                }
            }
            else    {
                if(nargs == 1) {
                    sc = stack[sl - 1];
                    sl--;
                    printf("%c %s;\n", c, &sc);
                }
                else    {
                    sc = stack[sl - 1];
                    sl--;
                    printf("%s %c ", &sc, c);
                    sc = stack[sl - 1];
                    sl--;
                    printf("%s;\n",&sc);
                }
            }
            // Push the returned results, if any, back onto the stack.
            stack[sl] = *(unsigned int*)res;
            ++sl;
        }
        ++strpos;
    }
    // If there is only one value in the stack
    // That value is the result of the calculation.
    if(sl == 1) {
        sc = stack[sl - 1];
        sl--;
        printf("%s is a result\n", &sc);
        return true;
    }
    // If there are more values in the stack
    // (Error) The user input has too many values.
    return false;
}

int main() {
    // functions: A() B(a) C(a, b), D(a, b, c) ...
    // identifiers: 0 1 2 3 ... and a b c d e ...
    // operators: = - + / * % !
    const char *input = "a = D(f - b * c + d, !e, g)";
    char output[128];
    printf("input: %s\n", input);
    if(shunting_yard(input, output))    {
        printf("output: %s\n", output);
        if(!execution_order(output))
            printf("\nInvalid input\n");
    }
    return 0;
}

2017-03-23 13:21
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
收藏
得分:10 
回复 6楼 rjsp
过去百度正则表达式时,似乎看到过“兰姆达表达式”这个名词,不过没看懂。
在vb里我用递归写过,好像没九版主那么复杂啊!抽空转为c看看,主要是要写好多类似的字符串函数。
2017-03-23 19:46
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 6楼 rjsp
这个要慢慢消化才行~先收藏~

顺便也回xzlxzlxzl感觉有很大的优化空间~看来还要学的东西还有很多~

[此贴子已经被作者于2017-3-24 00:46编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-03-24 00:37
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
二楼已经更新完整~第一次做~没咋参考资料自己想的~感觉还好~到时看了相关算法后感觉还有很大的提升空间~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-03-24 00:39
邹特强
Rank: 2
等 级:论坛游民
帖 子:123
专家分:85
注 册:2016-9-21
收藏
得分:5 
回复 9楼 九转星河
C语言菜鸟,没深入学数据结构,看的一知半解,我只想知道COM什么意思啊?请版主指导下

............
2017-03-24 12:58
快速回复:如果检验一个输入的"常量表达式"是否合法~
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.053007 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved