当前位置首页 > 百科> 正文

调度场算法

2020-01-25 18:33:24 百科

调度场算法

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

基本介绍

  • 中文名:调度场算法
  • 外文名:Shunting Yard Algorithm

详细的算法

  • 当还有记号可以读取时:
  • 读取一个记号。
  • 如果这个记号表示一个数字,那幺将其添加到输出伫列中。
  • 如果这个记号表示一个函式,那幺将其压入栈当中。
  • 如果这个记号表示一个函式参数的分隔设定(例如,一个半角逗号,):
  • 从栈当中不断地弹出操作符并且放入输出伫列中去,直到栈顶部的元素为一个左括弧为止。如果一直没有遇到左括弧,那幺要幺是分隔设定放错了位置,要幺是括弧不匹配。
  • 如果这个记号表示一个操作符,记做o1,那幺:
  • 只要存在另一个记为o2的操作符位于栈的顶端,并且
  • 如果o1是左结合性的并且它的运算符优先权要小于或者等于o2的优先权,或者
  • 如果o1是右结合性的并且它的运算符优先权比o2的要低,那幺
  • 将o2从栈的顶端弹出并且放入输出伫列中(循环直至以上条件不满足为止);
  • 然后,将o1压入栈的顶端。
  • 如果这个记号是一个左括弧,那幺就将其压入栈当中。
  • 如果这个记号是一个右括弧,那幺:
  • 从栈当中不断地弹出操作符并且放入输出伫列中,直到栈顶部的元素为左括弧为止。
  • 将左括弧从栈的顶端弹出,但并不放入输出伫列中去。
  • 如果此时位于栈顶端的记号表示一个函式,那幺将其弹出并放入输出伫列中去。
  • 如果在找到一个左括弧之前栈就已经弹出了所有元素,那幺就表示在表达式中存在不匹配的括弧。
  • 当再没有记号可以读取时:
  • 如果此时在栈当中还有操作符:
  • 如果此时位于栈顶端的操作符是一个括弧,那幺就表示在表达式中存在不匹配的括弧。
  • 将操作符逐个弹出并放入输出伫列中。
  • 退出算法。

C++程式实现

#include #include // 操作符// 优先权 符号 运算顺序// 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 stackif(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;}
声明:此文信息来源于网络,登载此文只为提供信息参考,并不用于任何商业目的。如有侵权,请及时联系我们:baisebaisebaise@yeah.net