为什么我关于 Bracket Fixing 的代码挂起?

Why does my code about Bracket Fixing hangs?

我的代码将带有右括号的表达式的不完整组合")" 转换为带有右括号 "(" 的正确位置的表达式的完整组合。如果右括号和左括号仍然不相等,则使第一个表达式到最后一个优先级,如果仍然不相等,则对第一个索引进行左括号。最多三个表达式(表达式=数字运算符数字)。

示例输入: 4 + 3 ) * 4 - 2 ) * 6 - 6 ) ) )

示例输出: ((4 + 3 ) * ((4 - 2 ) * (6 - 6 ) ) )

我的代码在仅放置 1-2 个右括号时有效。如果超过两个,程序就会挂起。

源代码:

import java.util.Scanner;
import java.lang.String;

public class brackets {     //Declaration of Variables
    static String Str, Strr="";
    static Integer ope=0;
    static int temp=0,lent,pr=0,prl=0,prr=0;   //Temp = Opening Brackets placed, lent = string length, pr=Closing Brackets, prl = number of opening brackets made from last index, prr=TBA
    static  Scanner scan = new Scanner(System.in);

    public static void main(String[]args){
        
        System.out.println("Enter the combined experessions: ");  
        Str = scan.nextLine();        
        lent = Str.length();       //Setting the full expression to a string (Str)
    

        for(int i=0; i<lent;i++){        //Finding how many Closing Brackets There are
 
            if(Str.charAt(i)==')'){
                pr++;
            }   

        }
        Popping(lent);                 //Method
        System.out.print(Strr);          //Printing Final Ouput
            

        scan.close();
        


    }

    public static void Popping(int lent){ 
     
        for(int j =lent-1; j>-1;j--){        //I set j to lent because I want to search from rightmost to leftmost
            if(Str.charAt(j)==')')          //I need to find a closing bracket first before the program could start to input an opening bracket
                prr++;

            if(prr>0){
                if(Str.charAt(j)=='+'||Str.charAt(j)=='-'||Str.charAt(j)=='*'||Str.charAt(j)=='/'||(j<=lent-2&&Character.isDigit(Str.charAt(j+1))&&Str.charAt(j)==')')){   //Finding an operator or finding a closing bracket which has a digit next to it 
                    ope++;
                }
                if(ope==2){  //finding two operators mean that I can now put an opening bracket
                    Strr = '('+Strr;
                    temp++;
                    ope=0;
                }
            }

        Strr = Str.charAt(j)+Strr;  

        if(prr>0){                 
            if(j==0&&temp!=pr){    //If J==0 and Closing brackets still is not equal to Opening Brackets, I'll set opening bracket to the 0 index
                Strr = '('+Strr;
                temp++;
            }
        }

        }

        while(temp!=pr) {   // If still not equal, I'll set an opening bracket to the second opening bracket there is, making the last two expression a priority
            for(int j =lent-1; j>-1;j--){
                if(Str.charAt(j)=='(')
                    prl++;
                if(prl>1&&Str.charAt(j)=='('){
                    Strr= Strr.substring(0,j-1)+'('+Strr.substring(j,lent-1);
                    temp++;
                }
            }
        }
   
       
    }
}

我认为问题出在你最后的 while 循环上。

问题是您正在 运行 遍历 Str(您的原始字符串),寻找左括号。但是,您的原始字符串 4 + 3 ) * 4 - 2 ) * 6 - 6 ) ) ) 不包含任何左括号,因此 Str.charAt(j)=='(' 永远不会 true 并且 temp 永远不会递增以匹配 pr。因此条件 temp!=pr 总是 true,因此 while 循环继续执行。

您可能希望将此循环中出现的所有 Str 更改为 Strr,这是您插入左括号的字符串。

然后您将遇到以下行的问题:

                    Strr= Strr.substring(0,j-1)+'('+Strr.substring(j,lent-1);

如果j > 0,这一行将排除Strr中位置j-1的字符。如果 j == 0 这将导致抛出 StringIndexOutOfBoundsException.substring 方法的第二个参数不是要包含在子字符串中的最后一个字符的索引,而是该字符之后的下一个字符的索引。 Strr 的子串从头开始,直到但不包括位置 j 的字符,是 Strr.substring(0,j) 而不是 Strr.substring(0,j-1).

另外,为了简单起见,如果希望子串到运行字符串的结尾,可以省略第二个参数。在下面的行中,我对您对 .substring:

的第二次调用进行了修改
                    Strr= Strr.substring(0,j)+'('+Strr.substring(j);

对您的 class 进行这些更改后,我能够 运行 它在您的示例输入 4 + 3 ) * 4 - 2 ) * 6 - 6 ) ) ) 上并从中获得输出 ((4 + 3 ) *(( 4 - 2 ) *( 6 - 6 ) ) )


然而,我 运行 你的代码在 1 + 5 ) / 4 + 3 ) * 4 - 2 ) * 6 - 6 ) ) ) 上,它再次挂起。

这里的问题是,当您的代码到达 while 循环的顶部时,它将插入四个左括号,还有两个要关闭。然而,通过 for 循环的 运行ning 将向 str 添加三个左括号,使 temp 达到 7,而 pr 为 6。7 不会等于 6,因此 while 的主体再次循环 运行s,插入更多括号,依此类推,直到字符串变得太大而无法放入内存并且程序崩溃。

最简单的修复方法是将条件 temp<pr 添加到行

if(prl>1&&Strr.charAt(j)=='('){

给你

if(prl>1&&Strr.charAt(j)=='('&&temp<pr){

这样你就不会插入太多的左括号。


最后,为了可读性,我强烈建议你给你的变量起一个更具描述性的名字。例如,temp 对于计算到目前为止插入的左括号数量的变量来说不是一个好名字:更好的名字应该是 openParenCount 或者 insertedOpenParensCount。同样,pr 会比 closeParenCount 更好。 Str 可以重命名为 originalStringStrr 可以重命名为 modifiedString

我不确定您的代码在 while 循环中究竟做了什么,但是我可以确认的一件事是,当输入大于 3 个右括号“)”时,您的代码将进入 while 循环

while(temp!=pr) {   // If still not equal, I'll set an opening bracket to the second opening bracket there is, making the last two expression a priority
        for(int j =lent-1; j>-1;j--){
            if(Str.charAt(j)=='(')
                prl++;
            if(prl>1&&Str.charAt(j)=='('){
                Strr= Strr.substring(0,j-1)+'('+Strr.substring(j,lent-1);
                temp++;
            }
        }
    }

此时您的 while 检查 temp!=pr 如果调用此条件是否始终为真,从而创建一个无限循环。