求解思路:

中缀表达式转成后缀表达式,根据后缀表示式生成二叉表达式数,在根据上树生成导函数树。牛顿迭代法求解一元多次方程

牛顿迭代法:

http://www.devacg.com/?post=351
一元非线性方程的求解是高等数学研究的重要课题之一,早在2000多年前,古巴比伦的数学家就能解一元二次方程了,中国的《九章算术》也有对一元二次方程求解的记载。目前人们普遍认为低阶(5阶以下)元非线性方程可以通过求根公式求解,但是高于或等于5阶的一元非线性方程不存在求根公式,要精确求解非常困难。对高阶方程,一般采用迭代法近似求解,牛顿迭代法因为方法简单,迭代收敛速度快而被广泛使用。

牛顿迭代法(Newton’s method)又称牛顿-拉弗森方法(Newton-Raphson method),它是一种在实数域和复数域上近似求解方程的方法。方法使用函数(x)的泰勒级数的前面几项来寻找方程(x)-0的根。
牛顿迭代法逼近示意图:
求解一元多次方程 - 图1
首先,选择一个接近函数(x)零点的x0作为迭代初始值,计算相应的(x0)和切线斜率(xO)(这里(x)是函数(x)的一阶导函数)。然后我们经过点(xO,f(x))做一条斜率为f(x0)的直线,该直线与x轴有一个交点,可通过以下方程的求解得到这个交点的x坐标:

求解一元多次方程 - 图2

求解这个方程,可以得到:

求解一元多次方程 - 图3

我们将新求得的点的x坐标命名为x1,通常x1会比x0更接近方程(X)-0的解。因此我们现在可以利用x1开始下一轮迭代。根据上述方程中x1和x0的关系,可以得到一个求解x的迭代公式:

求解一元多次方程 - 图4

这就是牛顿迭代公式。目前已经证明,如果(x)的一阶导函数(x)是连续函数,并且待求的零点x是孤立的,则在零点x周围存在一个区间,只要初始值x0位于这个区间,牛顿迭代必定收敛。并且,只要(x)0,牛顿送代法具有平方收敛的性能。这意味着每迭代一次,结果的有效数字将增加一倍,这比二分逼近法的线性收敛速度快了一个数量级。

导函数的求解与近似公式

  1. using System;
  2. namespace NewtonTest
  3. {
  4. class Program
  5. {
  6. public delegate double Function(double x);
  7. const double PRECISION = 0.1;//计算精度
  8. static void Main(string[] args)
  9. {
  10. double x = NewtonRaphson(TestFun, -8);
  11. Console.WriteLine("f({0})={1}", x, TestFun(x));
  12. Console.Read();
  13. }
  14. //示例方程:一元二次方程
  15. //求解y=0时,x的值.
  16. public static double TestFun(double x)
  17. {
  18. //注意:要确保这个方程是有解的。
  19. double y = 5 * Math.Pow(x, 2) + 8 * x + 2;
  20. return y;
  21. }
  22. /// <summary>
  23. /// 计算函数f在x附近的一阶导数值
  24. /// </summary>
  25. /// <param name="f">原函数</param>
  26. /// <param name="x">x值</param>
  27. /// <returns></returns>
  28. public static double CalcDerivative(Function f, double x)
  29. {
  30. return (f(x + 0.000005) - f(x - 0.000005))/0.00001;
  31. }
  32. /// <summary>
  33. /// 牛顿迭代法
  34. /// 用于求解一元非线性方程
  35. /// </summary>
  36. /// <param name="f">原函数</param>
  37. /// <param name="x0">迭代初始值</param>
  38. /// <returns></returns>
  39. public static double NewtonRaphson(Function f, double x0)
  40. {
  41. double x1 = x0 - f(x0) / CalcDerivative(f, x0);
  42. while(Math.Abs(x1 - x0) > PRECISION)
  43. {
  44. x0 = x1;
  45. x1 = x0 - f(x0) / CalcDerivative(f, x0);
  46. }
  47. return x1;
  48. }
  49. }
  50. }

中缀表达式转后缀表达式—C#代码实现

https://blog.csdn.net/Czhenya/article/details/78067542
版主没用递归来实现,有些繁琐

  1. namespace 玩嗨的练习
  2. {
  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. //运行时用建议输入空格
  8. Console.WriteLine("请输入您要转换的表达式:");
  9. string inputstr = Console.ReadLine();
  10. //测试用
  11. //string inputstr = "9 * (3 - 1) + (10 - 1) / 2";
  12. //string inputstr = "1 - 2 - 3 * 4 + 10 / 5";
  13. Console.WriteLine("您转换后的结果为:");
  14. Change(inputstr);
  15. Console.ReadKey();
  16. }
  17. private static void Change(string inputstr)
  18. {
  19. Stack<char> arrStark = new Stack<char>();
  20. char[] arrChar = inputstr.ToCharArray();
  21. int a = 4; //默认状态是什么都没有,这里是4状态,,
  22. for (int i = 0; i < arrChar.Length; i++)
  23. {
  24. //数字空格就直接输出
  25. if (arrChar[i] <= '9' && arrChar[i] >= '0')
  26. {
  27. Console.Write(arrChar[i]);
  28. }
  29. if (arrChar[i] == ' ')
  30. {
  31. Console.Write(" ");
  32. }
  33. //运算符走状态机
  34. switch (a)
  35. {
  36. //=============================状态1 * / ====================================
  37. case 1: //表示当前是+- 状态
  38. if (arrChar[i] == '+' || arrChar[i] == '-')
  39. {
  40. a = 1;
  41. Console.Write(arrStark.Pop());
  42. arrStark.Push(arrChar[i]);
  43. }
  44. else
  45. if (arrChar[i] == '*' || arrChar[i] == '/')
  46. {
  47. a = 2;
  48. arrStark.Push(arrChar[i]);
  49. }
  50. else
  51. if (arrChar[i] == '(')
  52. {
  53. a = 3;
  54. arrStark.Push(arrChar[i]);
  55. }
  56. else
  57. if (arrChar[i] == ')')
  58. {
  59. a = 4;
  60. for (int j = 0; j < arrStark.Count; j++)
  61. {
  62. //输出括号中间的符号,,,
  63. if (arrStark.Peek() == '(')
  64. {
  65. //把左括号,,弹出栈外
  66. arrStark.Pop();
  67. break;
  68. }
  69. else
  70. {
  71. Console.Write(arrStark.Pop());
  72. }
  73. }
  74. }
  75. break;
  76. //=============================状态2 * / ====================================
  77. case 2: //表示当前是* / 状态
  78. if (arrChar[i] == '+' || arrChar[i] == '-')
  79. {
  80. a = 1;
  81. for (int j = 0; j <= arrStark.Count; j++)
  82. {
  83. //Console.Write(arrStark.Count);
  84. Console.Write(arrStark.Pop());
  85. }
  86. arrStark.Push(arrChar[i]);
  87. }
  88. else
  89. if (arrChar[i] == '*' || arrChar[i] == '/')
  90. {
  91. a = 2;
  92. Console.Write(arrStark.Pop());
  93. arrStark.Push(arrChar[i]);
  94. }
  95. else
  96. if (arrChar[i] == '(')
  97. {
  98. a = 3;
  99. arrStark.Push(arrChar[i]);
  100. }
  101. else
  102. if (arrChar[i] == ')')
  103. {
  104. a = 4;
  105. for (int j = 0; j < arrStark.Count; j++)
  106. {
  107. if (arrStark.Peek() == '(')
  108. {
  109. //把左括号,,弹出栈外
  110. arrStark.Pop();
  111. break;
  112. }
  113. else
  114. {
  115. //输出括号中间的符号,,,
  116. Console.Write(arrStark.Pop());
  117. }
  118. }
  119. }
  120. break;
  121. //=============================状态3 ) ====================================
  122. case 3: //表示当前是( 状态
  123. if (arrChar[i] == '+' || arrChar[i] == '-')
  124. {
  125. arrStark.Push(arrChar[i]);
  126. }
  127. else
  128. if (arrChar[i] == '*' || arrChar[i] == '/')
  129. {
  130. arrStark.Push(arrChar[i]);
  131. }
  132. else
  133. if (arrChar[i] == '(')
  134. {
  135. a = 3;
  136. arrStark.Push(arrChar[i]);
  137. }
  138. else
  139. if (arrChar[i] == ')')
  140. {
  141. a = 4;
  142. for (int j = 0; j < arrStark.Count; j++)
  143. {
  144. if (arrStark.Peek() == '(')
  145. {
  146. //把左括号,,弹出栈外
  147. arrStark.Pop();
  148. break;
  149. }
  150. else
  151. {
  152. //输出括号中间的符号,,,
  153. Console.Write(arrStark.Pop());
  154. }
  155. }
  156. }
  157. break;
  158. //=============================状态4 ( ====================================
  159. case 4: //表示当前是 ) 状态
  160. if (arrChar[i] == '+' || arrChar[i] == '-')
  161. {
  162. if (arrStark.Count == 0)
  163. {
  164. a = 1;
  165. arrStark.Push(arrChar[i]);
  166. }
  167. else
  168. {
  169. if (arrStark.Peek() == '+' || arrStark.Peek() == '-')
  170. {
  171. a = 1;
  172. arrStark.Push(arrChar[i]);
  173. }
  174. else
  175. if (arrStark.Peek() == '*' || arrStark.Peek() == '/')
  176. {
  177. a = 1;
  178. for (int j = 0; j < arrStark.Count; j++)
  179. {
  180. Console.Write(arrStark.Pop());
  181. }
  182. arrStark.Push(arrChar[i]);
  183. }
  184. }
  185. }
  186. else
  187. if (arrChar[i] == '*' || arrChar[i] == '/')
  188. {
  189. if (arrStark.Count == 0)
  190. {
  191. a = 2;
  192. arrStark.Push(arrChar[i]);
  193. }
  194. else
  195. {
  196. if (arrStark.Peek() == '+' || arrStark.Peek() == '-')
  197. {
  198. a = 2;
  199. arrStark.Push(arrChar[i]);
  200. }
  201. else if (arrStark.Peek() == '*' || arrStark.Peek() == '/')
  202. {
  203. a = 2;
  204. arrStark.Push(arrChar[i]);
  205. }
  206. }
  207. }
  208. else
  209. if (arrChar[i] == '(')
  210. {
  211. a = 3;
  212. arrStark.Push(arrChar[i]);
  213. }
  214. if (arrChar[i] == ')')
  215. {
  216. a = 4;
  217. for (int j = 0; j < arrStark.Count; j++)
  218. {
  219. if (arrStark.Peek() == '(')
  220. {
  221. //把左括号,,弹出栈外
  222. arrStark.Pop();
  223. break;
  224. }
  225. else
  226. {
  227. //输出括号中间的符号,,,
  228. Console.Write(arrStark.Pop());
  229. }
  230. }
  231. }
  232. break;
  233. default:
  234. Console.WriteLine("Wrong");
  235. break;
  236. }
  237. }
  238. //遍历栈中剩余的符号输出,并清空栈,
  239. foreach (char item in arrStark)
  240. {
  241. Console.Write(" " + item);
  242. }
  243. arrStark.Clear();
  244. }
  245. }
  246. }
  247. ————————————————
  248. 版权声明:本文为CSDN博主「Czhenya」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
  249. 原文链接:https://blog.csdn.net/Czhenya/article/details/78067542

表达式树及其实现

https://www.chaoswork.cn/904.html