///////////////////////////////// // public string Suffix; // // For test // ///////////////////////////////// //Note:表达式树的构造函数,括号选项为HasBrack,默认为无括号 public ExpTree(Fraction[] numbers,string[] operation,bool hasNegative,bool hasBrack,bool hasFrac,int leftRange,Random rand) { this.HasNegative = hasNegative; this.HasFrac = hasFrac; this.HasBrack = hasBrack; this.LeftRange = leftRange; //根据是否有括号生成是否有括号的树 if (hasBrack) GenerateTreeWithBrack(numbers, operation,rand,LeftRange); else GenerateTreeWithoutBrack(numbers, operation,rand,LeftRange); }
//生成合法的预定数量的分数或整数组合 FracCount=OpCount+1 public Fraction[] GenerateNumber(Random rand, int count,bool hasNegative,bool hasFrac,int leftRange,int rightRange) { Fraction[] Number = new Fraction[count]; long RandDe; long RandMo; long Int; int IsNega = 0;//默认没有负数 //Note:我为什么舍弃这段代码?因为没用... //if (hasNegative) // leftRange = -leftRange; for (int i = 0; i < count; i++) { //如果可以有负数,就摇色子 if (hasNegative) IsNega = rand.Next(0, 2); //如果要求生成的是分数 if (hasFrac) { //先生成分母 RandDe = GetLongRandom(leftRange, rightRange, rand); //如果生成的分母为0,则将其置为1 if (RandDe == 0) RandDe = 1; //生成的带分数的范围要控制在leftRange ~ rightRange之间,所以如下范围 RandMo = GetLongRandom(leftRange * RandDe, rightRange * RandDe, rand); //生成一个分母不为0的分数表达式 Fraction number = new Fraction(RandMo, RandDe); Number[i] = number; } //如果要求不能生成分数 else { //生成一个值域范围内的整数 Int = GetLongRandom(leftRange, rightRange, rand); //构造一个整数式 Fraction number = new Fraction(Int, 1); Number[i] = number; } //默认是0,如果不幸摇色子摇中了,就变成负数了 if (IsNega == 1) Number[i] = 0 - Number[i]; } return Number; }
//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); }
//因为裂解而被废弃的代码——如果可能有所优化的话——在Amend里使用 ////Note:这个生成是为了通过裂解产生一种带括号式子除法只可能整除的例子 ////这种情况下,数字都是整数,所以好解决。 //public void GenerateBinaryWithoutFrac(string[] operation) //{ //} //Note:生成一颗有几率带括号的表达式树 //步骤:生成一个二叉树,再得到答案,然后中序遍历得到中缀表达式 public void GenerateTreeWithBrack(Fraction[] numbers, string[] operation,Random rand,int leftRange) { Stack<string> StackOp = new Stack<string>(operation); Stack<Fraction> StackNum = new Stack<Fraction>(numbers); //根据numbers和opertaion数组生成根结点——改变了Root GenerateBinaryTree(ref this.Root,ref StackNum,ref StackOp,rand); //对表达树进行适当的修补与改动,使其合法——改变了表达式树 Answer = AmendTreeAndCalculate(this.Root,leftRange).ToString(); //通过表达式树,生成一个带括号的中缀表达式 TreeInfix = InOrderToInfixWithBrack(this.Root) +" ="; //生成最小表示法生成的表达式树 TreeMinusLamda = GenerateMinusExp(this.Root); }