//Note:生成一颗不可能带括号的树 //步骤:先生成一个中缀表达式,再生成一颗二叉树 public void GenerateTreeWithoutBrack(Fraction[] numbers, string[] operations, Random rand, int leftRange) { StringBuilder temp = new StringBuilder(); //通过给定的numbers和operations生成不带括号的中缀表达式 for (int i = 0; i < numbers.Count(); i++) { temp.Append(numbers[i].ToString() + " "); //在生成不带括号的表达式时,必须得学会反转 if (i == numbers.Count() - 1) { break; } //如果不带括号表达中出现了 x/0的情况,由于除法是左结合所以只要保证除法右侧的数不为0即可 if (operations[i] == "÷" && numbers[i + 1].GetMo() == 0) { numbers[i + 1] = new Fraction(1, 1); } //要求整除的前提下,这时候都是整数参与运算,没有分数 else if (operations[i] == "÷" && !HasFrac) { //如果本来就整除就不需要费事了... if (numbers[i].GetMo() % numbers[i + 1].GetMo() != 0 && (i == 0 || operations[i - 1] == "+" || operations[i - 1] == "-" || operations[i - 1] == "×")) { //在leftRange到numbers[i]的范围内取一随机数,求它与numbers[i]的分子的最大公约数 int a = rand.Next(leftRange, Math.Abs((int)numbers[i].GetMo()) + 1); long gcd = Fraction.GetGCD(numbers[i].GetMo(), a); //令numbers[i+1]的值为该数 numbers[i + 1] = new Fraction(gcd, 1); } } temp.Append(operations[i] + " "); } //获得了不带括号的中缀表达式,接下来要将它变为一颗树,这里一定要带=,这是判断的条件之一 TreeInfix = temp.ToString() + " ="; //中缀表达式要先转成后缀表达式 string Suffix = InfixToSuffix(TreeInfix); //后缀表达式转成树,设置Root为根结点 SuffixToTree(Suffix); //通过对树的修补进行表达式的合法化 Answer = AmendTreeAndCalculate(this.Root, leftRange).ToString(); //重新生成一个中缀表达式(不加任何括号的) TreeInfix = InOrderToInfixWithoutBrack(this.Root) + " ="; //通过最小表示法生成最小表示序列 TreeMinusLamda = GenerateMinusExp(this.Root); }
//修正树结构,并计算得出最后的值。 //修正包括范围: //1.减法中产生负数的情况(包括 有括号 与 无括号式子) //2.除法中需要整除的情况(这里只会修复有括号式子,无括号式子的情况已经在生成时修复了) //3.除法出现除数为0的情况(全部修复) public Fraction AmendTreeAndCalculate(Node root, int leftRange) { if (root.Left == null && root.Right == null) { return((Fraction)root.Value); } switch (root.Value) { case "+": return(AmendTreeAndCalculate(root.Left, leftRange) + AmendTreeAndCalculate(root.Right, leftRange)); case "-": Fraction LExp = AmendTreeAndCalculate(root.Left, leftRange); Fraction RExp = AmendTreeAndCalculate(root.Right, leftRange); //如果结果为负数的话且是没有括号的式子 //不允许结果中出现负数的话,就把两颗子树翻转 //并且要重新生成中缀表达式和最小表达式 if ((RExp > LExp) & !HasNegative & HasBrack) { Transfer(root); } //针对没有括号的情况 else if ((RExp > LExp) & !HasNegative) { root.Value = "+"; return(LExp + RExp); } return(LExp - RExp); case "×": return(AmendTreeAndCalculate(root.Left, leftRange) * AmendTreeAndCalculate(root.Right, leftRange)); case "÷": Fraction divider = AmendTreeAndCalculate(root.Left, leftRange); Fraction divisor = AmendTreeAndCalculate(root.Right, leftRange); //如果发现被除数不是0,而除数是0的话,就翻转两颗子树 if (divisor.GetMo() == 0 && divider.GetMo() != 0) { Transfer(root); return(0); } //如果不幸发现被除数和除数同时为0的话,那么还是默默地改掉这个符号吧... else if (divisor.GetMo() == 0 && divider.GetMo() == 0) { //除法自此改名为加法 root.Value = "+"; return(0); } //如果在满足了有效性的条件下,突然发现老板加了任务:你必须给我搞个整除出来,咋办? if (!HasFrac) { //如果你天生就能整除,我何必遭受这个罪呢... if (divider.GetMo() % divisor.GetMo() == 0) { return(divider.GetMo() / divisor.GetMo()); } //但如果你天生不能整除可咋办呢? else { //求得左侧被除数随机化产生的一个因子 int iRnd = DateTime.Now.Millisecond; Random rand = new Random(iRnd); //注意这里值域的下限 int a = rand.Next(leftRange, Math.Abs((int)divider.GetMo())); long gcd = Fraction.GetGCD(divider.GetMo(), a); //舍弃右侧原有子树,使用新的结点来代替,除法结果是 divider / gcd root.Right = new Node(new Fraction(gcd, 1).ToString()); return(divider.GetMo() / gcd); } } return(divider / divisor); default: throw new MyException.OwnDivException("啊呀呀,在计算的时候出了奇怪的错误。"); } }