//叶子结点的构造方法 public Node(string value) { this.Left = null; this.Right = null; this.Value = value; }
//修正树结构,并计算得出最后的值。 //修正包括范围: //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("啊呀呀,在计算的时候出了奇怪的错误。"); } }
//翻转子树,为了修补程序所用 public void Transfer(Node root) { Node Temp; Temp = root.Left; root.Left = root.Right; root.Right = Temp; }
//非叶结点的构造方法(非叶结点必然含有两个子结点) public Node(string value, Node left,Node right) { this.Left = left; this.Right = right; this.Value = value; }
//将一个后缀表达式转换为一个二叉树 public void SuffixToTree(string Suffix) { Stack<Node> Stack = new Stack<Node>(); string[] split = Suffix.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); foreach(string token in split) { if (token == "-" || token == "+" || token == "×" || token == "÷") { //栈中先弹出的是右儿子 Node RChild = Stack.Pop(); //后弹出的是左儿子 Node LChild = Stack.Pop(); //以左结点与右结点和当前键值构建根结点,并压入栈 Node tokenRoot = new Node(token, LChild, RChild); Stack.Push(tokenRoot); } //否则可能是等号,则令当前Root=栈顶的结点 else if (token == "=") { Root = Stack.Pop(); break; } //如果是操作数的话需要压栈 else Stack.Push(new Node(token)); } }
//在修补不带括号的表达式后要重新生成一下其表达式,同样不能带括号 public string InOrderToInfixWithoutBrack(Node root) { if (root.Left == null && root.Right == null) return root.Value; return InOrderToInfixWithoutBrack(root.Left) + " " + root.Value + " " + InOrderToInfixWithoutBrack(root.Right); }
//通过层次遍历的方法直接生成一颗二叉树 // public void GenerateBinaryTree(Fraction[] numbers,string[] operation) // { // //将两个数组混合成为一个队列,当队列为空时标明二叉树建立成功 // Queue<Node> Nodes = new Queue<Node>(); // foreach(string op in operation) // Nodes.Enqueue(new Node(op)); // foreach(Fraction num in numbers) // Nodes.Enqueue(new Node(num.ToString())); // //设立一个队列用于按层次构建二叉树 // Queue<Node> NodeQ = new Queue<Node>(); // //以Nodes[0]建立根结点 // //从待选取队列中除去头结点 // Root = Nodes.Dequeue(); // //根结点入队 // NodeQ.Enqueue(Root); // //当待选取队列不为空的时候要一直出队入队进行 // while (Nodes.Count()!=0) // { // //头结点出队 // Node Head = NodeQ.Dequeue(); // //如果没有左结点,则从Nodes中获取 // if (Head.Left == null) // Head.Left = Nodes.Dequeue(); // //由于该结点已经被选取了并加入了树中,所以加入NodeQ中 // NodeQ.Enqueue(Head.Left); // //如果没有右结点,则从Nodes中获取 // if (Head.Right == null) // Head.Right = Nodes.Dequeue(); // //由于右结点已经被选取了并加入了树中,所以加入NodeQ中 // NodeQ.Enqueue(Head.Right); // } // } //中序遍历得到二叉树对应中缀表达式 public string InOrderToInfixWithBrack(Node root) { //如果不是为叶结点或者不是根结点,则加括号 if (!root.IsLeaf() && root != Root) return "( " + InOrderToInfixWithBrack(root.Left) + " " + root.Value + " " + InOrderToInfixWithBrack(root.Right) + " )"; //如果不是叶结点却是根结点 else if (!root.IsLeaf()) return InOrderToInfixWithBrack(root.Left) + " " + root.Value + " " + InOrderToInfixWithBrack(root.Right); else return root.Value; }
//根据root递归生成最小表示法获得的字符串 public string GenerateMinusExp(Node root) { //如果是叶结点的话,则直接返回该结点的值 if (root.IsLeaf()) return root.Value; else if (root.Value == "+" || root.Value == "×") { //对左子树进行递归,得到左子树的最小表示字符串 string LeftMinus = GenerateMinusExp(root.Left); //对右子树进行递归,得到右子树的最小表示字符串 string RightMinus = GenerateMinusExp(root.Right); //对左子树和右子树进行统一排序 if (string.Compare(LeftMinus, RightMinus) <= 0) return root.Value + LeftMinus + RightMinus; else return root.Value + RightMinus + LeftMinus; } //否则就按照正常次序进行最小字符串表示 else return root.Value + GenerateMinusExp(root.Left) + GenerateMinusExp(root.Right); }
public void GenerateBinaryTree(ref Node root,ref Stack<Fraction> StackNum,ref Stack<string> StackOp,Random rand) { //先看是不是根结点 if(root==null) root = new Node(StackOp.Pop()); if(StackOp.Count()==0) { root.Left = new Node(StackNum.Pop().ToString()); root.Right = new Node(StackNum.Pop().ToString()); return; } int RandKey = rand.Next(0,3); //如果两边都是符号的话,则两边都递归 if(RandKey==0) { root.Left = new Node(StackOp.Pop()); //一次Pop之后栈可能为空了,所以要注意判断 if (StackOp.Count == 0) { //如果栈空了要注意对左侧进行递归 root.Right = new Node(StackNum.Pop().ToString()); GenerateBinaryTree(ref root.Left, ref StackNum, ref StackOp, rand); } else { root.Right = new Node(StackOp.Pop()); GenerateBinaryTree(ref root.Left, ref StackNum, ref StackOp, rand); GenerateBinaryTree(ref root.Right, ref StackNum, ref StackOp, rand); } } //如果左边是符号,右边是数字的话,则只进行左边的递归 else if(RandKey==1) { root.Left = new Node(StackOp.Pop()); root.Right = new Node(StackNum.Pop().ToString()); GenerateBinaryTree(ref root.Left,ref StackNum,ref StackOp,rand); } //如果右边是符号,左边是数字的话,则只进行右边的递归 else{ root.Right = new Node(StackOp.Pop()); root.Left = new Node(StackNum.Pop().ToString()); GenerateBinaryTree(ref root.Right,ref StackNum,ref StackOp,rand); } }