数据结构之栈(四)

        本文将继续扩展Stack在Arithmetical Expression的处理方面的应用,其中包括:“Postfix2Prefix”、“Postfix2Infix”和“Infix2Postfix”。


一、Postfix2Prefix

        它是通过多次入栈和出栈来完成的。主要步骤是:遍历“postfix string”:

        1)是算子先压栈;

        2)是算符就先取出它需要的算子,调整顺序(保证算符在前,算子在后),并焊接在一个整体(string),再压栈。

bool IsOperator(char c)
{
    if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^')
        return true;
    else
        return false;
}

void Postfix2Prefix(string & postfix, string & prefix)
{
    // convert the input postfix expression to prefix format
    StackAsLinkedList stack;
    for (unsigned int i = 0; i < postfix.length(); ++i)    //process each char in the postfix string from left to right
    {
        string s{ postfix[i] };
        if (std::isdigit(postfix[i]))
            stack.Push(*new String(s));
        else if (IsOperator(postfix[i]))
        {
            String & arg2 = dynamic_cast<String&>(stack.Pop());
            String & arg1 = dynamic_cast<String&>(stack.Pop());
            stack.Push(*new String(s + string(arg1) + string(arg2)));
            delete &arg1;
            delete &arg2;
        }
    }

    String & arg = dynamic_cast<String&>(stack.Pop());
    prefix = string(arg);
    delete & arg;
}

二、 Postfix2Infix

        它的原理于上面的相似,只是在调整顺序的时候,保证“算符在算子中间,并添加圆括号”。

void Postfix2Infix(string & postfix, string & infix)
{
    // convert the input postfix expression to infix format
    StackAsLinkedList stack;
    for (unsigned int i = 0; i < postfix.length(); ++i)    //process each char in the postfix string from left to right
    {
        string s{ postfix[i] };
        if (std::isdigit(postfix[i]))
            stack.Push(*new String(s));
        else if (IsOperator(postfix[i]))
        {
            String & arg2 = dynamic_cast<String&>(stack.Pop());
            String & arg1 = dynamic_cast<String&>(stack.Pop());
            stack.Push(*new String(string("(") + string(arg1) + s + string(arg2) + string(")")));
            delete &arg1;
            delete &arg2;
        }
    }

    String & arg = dynamic_cast<String&>(stack.Pop());
    infix = string(arg);
    delete & arg;
}

注:类似的原理,也可以处理“prefix expression”。


三、Infix2Postfix

        它的原理要稍微复杂一些。需要比较运算符的优先级和考虑运算符的结合性以及圆括号。它也是遍历“infix string”:

        1)遇到数字,直接append到“postfix string”;

        2)遇到算符,与栈顶的算符比较优先级,如果栈顶算符优先级高,则将栈顶算符append到“postfix string”,反复进行比较,知道遇到圆括号,或者栈顶算符优先级更低为止,最后将新算符压栈(这样,栈内的算符优先级是从低到高顺序排序);

        3)遇到左括号压栈,遇到右括号出栈。(对于括号是成对处理)

int GetOperatorWeight(char op)
{
    int weight = -1;
    switch (op)
    {
    case '+':
    case '-':
        weight = 1;
        break;
    case '*':
    case '/':
        weight = 2;
        break;
    case '^':
        weight = 3;
        break;
    }
    return weight;
}

bool IsRightAssociative(char op)
{
    if (op == '^')
        return true;
    else
        return false;
}

bool HasHigherPrecendence(char lOperator, char rOperator)
{
    int op1Weight = GetOperatorWeight(lOperator);
    int op2Weight = GetOperatorWeight(rOperator);

    // If operators have equal precedence, return true if they are left associative. 
    // return false, if right associative. 
    // if operator is left-associative, left one should be given priority. 
    if (op1Weight == op2Weight)
    {
        if (IsRightAssociative(lOperator))
            return false;
        else
            return true;
    }
    return op1Weight > op2Weight ? true : false;
}

void Infix2Postfix(string & infix, string & postfix)
{
    // convert the input infix expression to postfix format
    StackAsLinkedList stack;
    for (unsigned int i = 0; i < infix.length(); ++i)    //process each char in the postfix string from left to right
    {
        string s{ infix[i] };
        if (infix[i] == ' ' || infix[i] == ',')    // If character is a delimitter, move on. 
            continue;
        else if (std::isdigit(infix[i]))
            postfix += infix[i];
        else if (IsOperator(infix[i]))    // If character is operator
        {
            while (!stack.IsEmpty() &&
                string(dynamic_cast<String&>(stack.Top())) != string("(") &&
                HasHigherPrecendence(string(dynamic_cast<String&>(stack.Top()))[0], infix[i]))    // operators in stack ordered by precedence
            {
                String & arg = dynamic_cast<String&>(stack.Pop());
                postfix += string(arg);
                delete &arg;
            }
            stack.Push(*new String(string{ infix[i] }));
        }
        else if (infix[i] == '(')
        {
            stack.Push(*new String(string{ infix[i] }));
        }
        else if (infix[i] == ')')    // a pair of parenthesis is a processing unit
        {
            while (string(dynamic_cast<String&>(stack.Top())) != string("("))
            {
                String & arg = dynamic_cast<String&>(stack.Pop());
                postfix += string(arg);
                delete &arg;
            }
            stack.Pop();
        }
    }

    while (!stack.IsEmpty())
    {
        String & arg = dynamic_cast<String&>(stack.Pop());
        postfix += string(arg);
        delete &arg;
    }
}

注:从该函数对圆括号的成对处理方法,可以扩展:在处理C++代码时,由于代码块是用花括号包裹,而花括号也是成对出现的,也可以采用栈进行缓存处理。或者,更简单的办法是“计算”。设定“int count = 0”;遇到左花括号则“++count”;遇到右花括号则“--count”;


你可能感兴趣的:(数据结构之栈(四))