C#算法优化
来源: | 作者:JYTEK | 发布时间: 2023-12-14 | 537 次浏览 | 分享到:

关键词:PCIe-PXIe-68565、工控机


1.问题描述

本期KB总结了一些在使用C#编程时能够提高效率的算法优化。


2.优化的算法

下面介绍几个常用的算法优化方法,并使用StopWatch对优化前后的效率进行对比。

1. 使用ref关键字或其他in - place方法,直接对输入数组进行操作

        static int[] AddOne_Outplace()

        {

            int[] array = { 12, 5, 8, 4, 3 };

            for (int i = 0; i < array.Length ; i++)

            {

                array[i]++;

            }

            return array;

        }

        static void AddOne_Inplace(ref int[] array)

        {

            for (int i = 0; i < array.Length; i++)

            {

                array[i]++;

            }

        }

        private static void Main(string[] args)

        {

            Stopwatch sw = Stopwatch.StartNew();

            int[] a;

            for (int i = 0; i < 100000; i++)

            {

                a = AddOne_Outplace();

            }

            Console.WriteLine(sw.ElapsedMilliseconds);

 

            sw.Restart();

            int[] array = { 12, 5, 8, 4, 3 };

            for (int i = 0; i < 100000; i++)

            {

                AddOne_Inplace(ref array);

            }

            Console.WriteLine(sw.ElapsedMilliseconds);

            Console.Read();

          }

  图 1  使用In-place方法前后效率对比

 

2. 对比较简单的循环使用循环展开的方法

int length = 50000000;

            double[] a = new double[length];


         Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < length; i++)

            {

                a[i]++;

            }

         Console.WriteLine(sw.ElapsedMilliseconds);

 

         sw.Restart();

            for (int i = 0; i < length; i += 4)

            {

                a[i]++;

                a[i + 1]++;

                a[i + 2]++;

                a[i + 3]++;

            }

         Console.WriteLine(sw.ElapsedMilliseconds);

          Console.Read();

图 2  使用循环展开前后效率对比


3. 所有涉及到数学计算级联方法的调用都放到一个for循环中进行

  int length = 50000000;

            double a=1, b=2;

            double[] c = new double[length];

         Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < length; i++)

            {

                c[i] =  b * 2;

            }

            for (int i = 0; i < length; i++)

            {

                c[i] =c[i]+a;

            }

         Console.WriteLine(sw.ElapsedMilliseconds);

 

         sw.Restart();

 

            for (int i = 0; i < length; i++)

            {

                c[i] = a + b * 2;

            }

            Console.WriteLine(sw.ElapsedMilliseconds);

Console.Read();

图 3 数学级联方法调用优化前后效率对比

4. 将Linq语句都替换为for循环

int length = 5000000;

            double[] a = new double[length];

 

         Stopwatch sw = Stopwatch.StartNew();

            double[] b = a.Select(x => x++).ToArray();

         Console.WriteLine(sw.ElapsedMilliseconds);

 

          sw.Restart();

            for (int i = 0; i < length; i++)

            {

                a[i]++;

            }

         Console.WriteLine(sw.ElapsedMilliseconds);

Console.Read();

图 4 Ling语句与for循环效率对比


5. 检查循环中的值类型与引用类型之间的转换,减少拆箱和装箱

string a;

            string b;

            string c;

         Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < 5000000; i++)

            {

                a = 1.ToString();

                b = 2.ToString();

                c = a + ""+b;

            }

         Console.WriteLine(sw.ElapsedMilliseconds);

 

         sw.Restart();

            a = 1.ToString();

            b = 2.ToString();

            for (int i = 0; i < 5000000; i++)

            {

                c = a + "" + b;

            }

         Console.WriteLine(sw.ElapsedMilliseconds);

Console.Read();



图 5  减少装箱前后效率对比


6. 嵌套的for循环,当数组较大时,索引终值为常量可以缩短执行时间

            int[] data = new int[100000000];

            const int a = 100000000;//常量

         Stopwatch sw = Stopwatch.StartNew();

            for (int i = 0; i < data.Length; i++)

            {

                data[i] = i;

            }

         Console.WriteLine(sw.ElapsedMilliseconds);

         sw.Restart();

            for (int i = 0; i < a; i++)

            {

                data[i] = i;

            }

         Console.WriteLine(sw.ElapsedMilliseconds);

图 6  for循环索引终值为变量和常量的对比

       Console.Read();


7. Array类的静态方法效率很高,比如Array.Copy方法快于List的AddRange,后者又快于Linq语句的Concat方法。

            int length = 5000000;

            double[] a = new double[length];

            double[] b = new double[length];

            double[] c = new double[length * 2];

            Random rd = new Random();

            for (int i = 0; i < length; i++)

         {

                a[i] = rd.NextDouble();

                b[i] = rd.NextDouble();

         }

         Stopwatch sw = Stopwatch.StartNew();

            c = a.Concat(b).ToArray();

         Console.WriteLine(sw.ElapsedMilliseconds);

 

         sw.Restart();

            List<double> list = new List<double>();

            list.AddRange(a);

            list.AddRange(b);

         Console.WriteLine(sw.ElapsedMilliseconds);

 

         sw.Restart();

            Array.Copy(a, 0, c, 0, length);

            Array.Copy(b, 0, c, length, length);

         Console.WriteLine(sw.ElapsedMilliseconds);

图 7  Linq方法,List方法,Array方法效率对比

       Console.Read();