靠人不如靠己,准备做自己得MathLib,在学校的时候,就想过把数学数理的东西都计算机化,但一直没有时间去做这件事情,现在觉得空余 时间比较闲,就做做这件事情,先从线性代数开始,毕竟这里面的很多算法,实际共走中都有用到。在做这些算法的过程中,也体会到了:数学中的东西不是没有用,而是你没用到。下面的算法(除全排列外)都是自己原创想得,做的不够效率的地方,也请大家分享更好的东西。好了,啰嗦这么多,让代码说话吧:
/// <summary> /// 行列式计算,本程序属于MyMathLib的一部分,欢迎使用,参考,提意见。 /// 有时间用函数语言改写,做自己得MathLib,里面的算法经过验证,但没经过 /// 严格测试,如需参考,请慎重. /// </summary> public static partial class LinearAlgebra { /// <summary> /// 求逆序数 /// </summary> /// <param name="Numbers">数字序列</param> /// <returns></returns> public static int CalcInverseNumber(string Numbers) { int theRet = 0; if (string.IsNullOrWhiteSpace(Numbers)) { return theRet; } else { string[] theNumbers = Numbers.Split(new string[] { ",", " " }, StringSplitOptions.RemoveEmptyEntries); return CalcInverseNumber(theNumbers); } } /// <summary> /// 求逆序数 /// </summary> /// <param name="Numbers">数字序列</param> /// <returns></returns> public static int CalcInverseNumber(string[] Numbers) { var theRet = 0; if (Numbers.Count() <= 0) { return theRet; } else { string[] theNumbers = Numbers.ToArray(); int[] theNums = new int[theNumbers.Count()]; for (int i = 0; i < theNumbers.Count(); i++) { theNums[i] = Convert.ToInt32(theNumbers[i]); } for (int theI = 0; theI < theNums.Count() - 1; theI++) { for (int theJ = theI + 1; theJ < theNums.Count(); theJ++) { if (theNums[theI] > theNums[theJ]) { theRet++; } } } } return theRet; } private static string HandlingMultiExp(string Exp, int Sign) { decimal theRetNum = Sign; var theRetLine = ""; var theDigits = Exp.Split('*'); foreach (var theD in theDigits) { decimal theDec = 0; if (decimal.TryParse(theD, out theDec)) { theRetNum *= theDec; } else { if (theRetLine == "") { theRetLine = theD; } else { theRetLine += "*" + theD; } } } if (theRetNum == 0) { return ""; } else { if (theRetNum == 1) { return theRetLine; } if (theRetNum == -1) { return "-" + theRetLine; } return theRetNum.ToString() + theRetLine; } } /// <summary> /// 行列式表达式展开 /// </summary> /// <param name="Determinants">N阶行列式</param> /// <returns></returns> public static string DeterminantToExpression(string[,] Determinants) { int theR = Determinants.GetLength(0); int theC = Determinants.GetLength(1); if (theR != theC) { throw new Exception("不是N阶行列式!"); } var theResults = new List<string>(); List<string> theNs = new List<string>(); for (int i = 1; i <= theC; i++) { theNs.Add(i.ToString()); } FullPermutation(theNs, 0, theC - 1, theResults); var theNExp = ""; var thePExp = ""; foreach (var theAL in theResults) { var theInverseNum = Convert.ToInt32(Math.Pow(-1, CalcInverseNumber(theAL))); var theLine = ""; string[] theNums = theAL.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries); for (int i = 1; i <= theC; i++) { var theV = Determinants[i - 1, int.Parse(theNums[i - 1]) - 1]; theLine += "*" + theV; } theLine = HandlingMultiExp(theLine.Substring(1), theInverseNum); if (!string.IsNullOrEmpty(theLine)) { if (theLine[0] == '-') { theNExp += "" + theLine; } else { thePExp += "+" + theLine; } } } return thePExp.Substring(1) + theNExp; } /// <summary> /// 对数组进行全排列 /// </summary> /// <param name="lsArray">要进行全排列的数组</param> /// <param name="begin">进行全排列的开始下标</param> /// <param name="end">进行全排列的结束下标</param> public static void FullPermutation(List<string> lsArray, int begin, int end, List<string> Result) { if (begin == end) { string theLine = ""; for (int i = 0; i <= end; i++) { theLine += "," + lsArray[i]; } Result.Add(theLine.Substring(1)); } for (int i = begin; i <= end; i++) { Swap(lsArray, begin, i); FullPermutation(lsArray, begin + 1, end, Result); Swap(lsArray, begin, i); } } /// <summary> /// 交换数组中的下标为x,y的值 /// </summary> /// <param name="lsArray">该数组</param> /// <param name="x"></param> /// <param name="y"></param> private static void Swap(List<string> lsArray, int x, int y) { string t = lsArray[x]; lsArray[x] = lsArray[y]; lsArray[y] = t; } /// <summary> /// 化三角法行列式计算, /// </summary> /// <param name="Determinants">N阶行列式</param> /// <returns>计算结果</returns> public static decimal CalcDeterminant(decimal[,] Determinants) { int theSign = 1;//正负符号,如果需要变换,将记录变换后的符号. int theN = Determinants.GetLength(0); //从第1列到第theN-1列 for (int i = 0; i < theN - 1; i++) { //从第theN-1行到第i+1行,将D[j,i]依次变为0 for (int j = theN - 1; j > i; j--) { //如果为当前值为0,则不处理,继续处理上一行 if (Determinants[j, i] == 0) { continue; } //如果[j,i]的上一行[j-1, i]的值为0则交换 if (Determinants[j - 1, i] == 0) { //每次交换,行列式的值大小不变,符号取反 theSign = 0 - theSign; for (int k = 0; k < theN; k++) { decimal theTmpDec = Determinants[j, k]; Determinants[j, k] = Determinants[j - 1, k]; Determinants[j - 1, k] = theTmpDec; } } else { //将当前行减去上一行与theRate的积。 var theRate = Determinants[j, i] / Determinants[j - 1, i]; for (int k = 0; k < theN; k++) { Determinants[j, k] = Determinants[j, k] - Determinants[j - 1, k] * theRate; } } } } //结果为对角线上的元素的乘积,注意符号的处理。 decimal theRetDec = theSign; for (int i = 0; i < theN; i++) { theRetDec *= Determinants[i, i]; } return theRetDec; } }