精华内容
下载资源
问答
  • 程序优化方法

    千次阅读 2017-05-04 14:05:16
    程序优化方法1.代码优化代码优化一般需要与算法优化同步进行,代码优化主要是涉及到具体编码技巧。同样算法与功能,不同写法也可能让程序效率差异巨大。一般而言,代码优化主要是针对循环结构进行分析处理,...

    程序优化方法

    1.代码优化

    代码优化一般需要与算法优化同步进行,代码优化主要是涉及到具体的编码技巧。同样的算法与功能,不同的写法也可能让程序效率差异巨大。一般而言,代码优化主要是针对循环结构进行分析处理,目前想到的几条原则是:

    a.避免循环内部的乘(除)法以及冗余计算

    这一原则是能把运算放在循环外的尽量提出去放在外部,循环内部不必要的乘除法可使用加法来替代等。如下面的例子,灰度图像数据存在BYTE Img[MxN]的一个数组中,对其子块  (R1至R2行,C1到C2列)像素灰度求和,简单粗暴的写法是:

    int sum = 0; 
    for(int i = R1; i < R2; i++)
    {
        for(int j = C1; j < C2; j++)
        {
            sum += Image[i * N + j];
        }
    }

    但另一种写法:

    int sum = 0;
    BYTE *pTemp = Image + R1 * N;
    for(int i = R1; i < R2; i++, pTemp += N)
    {
        for(int j = C1; j < C2; j++)
        {
            sum += pTemp[j];
        }
    }

    可以分析一下两种写法的运算次数,假设R=R2-R1,C=C2-C1,前面一种写法i++执行了R次,j++和sum+=…这句执行了RC次,则总执行次数为3RC+R次加法,RC次乘法;同  样地可以分析后面一种写法执行了2RC+2R+1次加法,1次乘法。性能孰好孰坏显然可知。

    b.避免循环内部有过多依赖和跳转,使cpu能流水起来

    关于CPU流水线技术可google/baidu,循环结构内部计算或逻辑过于复杂,将导致cpu不能流水,那这个循环就相当于拆成了n段重复代码的效率。

    另外ii值是衡量循环结构的一个重要指标,ii值是指执行完1次循环所需的指令数,ii值越小,程序执行耗时越短。下图是关于cpu流水的简单示意图:

    简单而不严谨地说,cpu流水技术可以使得循环在一定程度上并行,即上次循环未完成时即可处理本次循环,这样总耗时自然也会降低。

    先看下面一段代码:

    for(int i = 0; i < N; i++)
    {
        if(i < 100) a[i] += 5;
        else if(i < 200) a[i] += 10;
        else a[i] += 20;
    }

    这段代码实现的功能很简单,对数组a的不同元素累加一个不同的值,但是在循环内部有3个分支需要每次判断,效率太低,有可能不能流水;可以改写为3个循环,这样循环内部就不  用进行判断,这样虽然代码量增多了,但当数组规模很大(N很大)时,其效率能有相当的优势。改写的代码为:

    for(int i = 0; i < 100; i++)
    {
        a[i] += 5;        
    }
    for(int i = 100; i < 200; i++)
    {
        a[i] += 10;        
    }
    for(int i = 200; i < N; i++)
    {
        a[i] += 20;
    }

    关于循环内部的依赖,见如下一段程序:

    for(int i = 0; i < N; i++)
    {
        int x = f(a[i]);
        int y = g(x);
        int z = h(x,y);
    }

    其中f,g,h都是一个函数,可以看到这段代码中x依赖于a[i],y依赖于x,z依赖于xy,每一步计算都需要等前面的都计算完成才能进行,这样对cpu的流水结构也是相当不利的,尽量避免此类写法。
    c.定点化

    定点化的思想是将浮点运算转换为整型运算,目前在PC上我个人感觉差别还不算大,但在很多性能一般的DSP上,其作用也不可小觑。定点化的做法是将数据乘上一个很大的数后,将  所有运算转换为整数计算。例如某个乘法我只关心小数点后3位,那把数据都乘上10000后,进行整型运算的结果也就满足所需的精度了。

    d.以空间换时间

    空间换时间最经典的就是查表法了,某些计算相当耗时,但其自变量的值域是比较有限的,这样的情况可以预先计算好每个自变量对应的函数值,存在一个表格中,每次根据自变量的  值去索引对应的函数值即可。如下例:

    //直接计算
    for(int i = 0 ; i < N; i++)
    {
        double z = sin(a[i]);
    }
    
    //查表计算
    double aSinTable[360] = {0, ..., 1,...,0,...,-1,...,0};
    for(int i = 0 ; i < N; i++)
    {
        double z = aSinTable[a[i]];
    }

    后面的查表法需要额外耗一个数组double aSinTable[360]的空间,但其运行效率却快了很多很多。

    e.预分配内存

    预分配内存主要是针对需要循环处理数据的情况的。比如视频处理,每帧图像的处理都需要一定的缓存,如果每帧申请释放,则势必会降低算法效率,如下所示:

    //处理一帧
    void Process(BYTE *pimg)
    {
        malloc
        ...
        free
    }
    
    //循环处理一个视频
    for(int i = 0; i < N; i++)
    {
        BYTE *pimg = readimage();
        Process(pimg);
    }
    //处理一帧
    void Process(BYTE *pimg, BYTE *pBuffer)
    {
        ...
    }
    
    //循环处理一个视频
    malloc pBuffer
    for(int i = 0; i < N; i++)
    {
        BYTE *pimg = readimage();
        Process(pimg, pBuffer);
    }
    free

    前一段代码在每帧处理都malloc和free,而后一段代码则是有上层传入缓存,这样内部就不需每次申请和释放了。当然上面只是一个简单说明,实际情况会比这复杂得多,但整体思想是一致的。

    2.算法优化

    算法上的优化是必须首要考虑的,也是最重要的一步。一般我们需要分析算法的时间复杂度,即处理时间与输入数据规模的一个量级关系,一个优秀的算法可以将算法复杂度降低若干量级,那么同样的实现,其平均耗时一般会比其他复杂度高的算法少(这里不代表任意输入都更快)。

    比如说排序算法,快速排序的时间复杂度为O(nlogn),而插入排序的时间复杂度为O(n*n),那么在统计意义下,快速排序会比插入排序快,而且随着输入序列长度n的增加,两者耗时相差会越来越大。但是,假如输入数据本身就已经是升序(或降序),那么实际运行下来,快速排序会更慢。

    3.指令优化

    对于经过前面算法和代码优化的程序,一般其效率已经比较不错了。对于某些特殊要求,还需要进一步降低程序耗时,那么指令优化就该上场了。指令优化一般是使用特定的指令集,可快速实现某些运算,同时指令优化的另一个核心思想是打包运算。目前PC上intel指令集有MMX,SSE和SSE2/3/4等,DSP则需要跟具体的型号相关,不同型号支持不同的指令集。intel指令集需要intel编译器才能编译,安装icc后,其中有帮助文档,有所有指令的详细说明。

    例如MMX里的指令 __m64 _mm_add_pi8(__m64 m1, __m64 m2),是将m1和m2中8个8bit的数对应相加,结果就存在返回值对应的比特段中。假设2个N数组相加,一般需要执行N个加法指令,但使用上述指令只需执行N/8个指令,因为其1个指令能处理8个数据。

    实现求2个BYTE数组的均值,即z[i]=(x[i]+y[i])/2,直接求均值和使用MMX指令实现2种方法如下程序所示:

    #define N 800
    BYTE x[N],Y[N], Z[N];
    inital x,y;...
    //直接求均值
    for(int i = 0; i < N; i++)
    {
        z[i] = (x[i] + y[i]) >> 1;
    }
    
    //使用MMX指令求均值,这里N为8的整数倍,不考虑剩余数据处理
    __m64 m64X, m64Y, m64Z;
    for(int i = 0; i < N; i+=8)
    {
        m64X = *(__m64 *)(x + i);
        m64Y = *(__m64 *)(y + i);
        m64Z = _mm_avg_pu8(m64X, m64Y);
        *(__m64 *)(x + i) = m64Z;
    }

    使用指令优化需要注意的问题有:

    • 关于值域,比如2个8bit数相加,其值可能会溢出;若能保证其不溢出,则可使用一次处理8个数据,否则,必须降低性能,使用其他指令一次处理4个数据了;
    • 剩余数据,使用打包处理的数据一般都是4、8或16的整数倍,若待处理数据长度不是其单次处理数据个数的整数倍,剩余数据需单独处理
    展开全文
  • 但对于同一个计算任务,不同计算方法得到结果过程复杂程度是不一样,这对实际任务处理效率就有了非常大影响。 复杂度是衡量代码运行效率重要度量因素。在实际衡量时,我们通常会围绕以下2 个维度进行。 ...

    复杂度是什么?

    计算机通过一个个程序去执行计算任务,也就是对输入数据进行加工处理,并最终得到结果的过程。每个程序都是由代码构成的。可见,编写代码的核心就是要完成计算。但对于同一个计算任务,不同计算方法得到结果的过程复杂程度是不一样的,这对实际的任务处理效率就有了非常大的影响。

    复杂度是衡量代码运行效率的重要的度量因素。在实际衡量时,我们通常会围绕以下2 个维度进行。

    • 首先,这段代码消耗的资源是什么。一般而言,代码执行过程中会消耗计算时间和计算空间,那需要衡量的就是时间复杂度和空间复杂度。
    • 其次,这段代码对于资源的消耗是多少。我们不会关注这段代码对于资源消耗的绝对量,因为不管是时间还是空间,它们的消耗程度都与输入的数据量高度相关,输入数据少时,消耗自然就少。因此,为了更客观地衡量消耗程度,我们通常会关注时间或者空间消耗量与输入数据量之间的关系。

    从本质来看,时间复杂度与代码的结构有着非常紧密的关系;而空间复杂度与数据结构的设计有关

    如何计算复杂度?

    复杂度是一个关于输入数据量 n 的函数。例如,O(n) 表示的是,复杂度与计算实例的个数 n 线性相关;O(logn) 表示的是,复杂度与计算实例的个数 n 对数相关。

    通常,复杂度的计算方法遵循以下几个原则:

    • 首先,复杂度与具体的常系数无关,例如 O(n) 和 O(2n) 表示的是同样的复杂度。详细分析下,O(2n) 等于 O(n+n),也等于 O(n) + O(n)。也就是说,一段 O(n) 复杂度的代码只是先后执行两遍 O(n),其复杂度是一致的。
    • 其次,多项式级的复杂度相加的时候,选择高者作为结果,例如 O(n²)+O(n) 和 O(n²) 表示的是同样的复杂度。具体分析一下就是,O(n²)+O(n) = O(n²+n)。随着 n 越来越大,二阶多项式的变化率是要比一阶多项式更大的。因此,只需要通过更大变化率的二阶多项式来表征复杂度就可以了。
    • 此外,O(1) 表示一个特殊复杂度,含义为某个任务通过有限可数的资源即可完成。此处有限可数的具体意义是,与输入数据量 n 无关

    时间复杂度与代码结构的关系

    一些经验性的结论:

    • 一个顺序结构(即没有循环,一句句顺序执行一遍)的代码,时间复杂度是 O(1)。
    • 二分查找,或者更通用地说,采用分而治之的二分策略,时间复杂度都是 O(logn)。
    • 一个简单的 for 循环,时间复杂度是 O(n)。
    • 两个顺序执行的 for 循环,时间复杂度是 O(n)+O(n)=O(2n),其实也是 O(n)。
    • 两个嵌套的 for 循环,时间复杂度是 O(n²)。

    降低复杂度的核心方法论

    代码效率的瓶颈可能发生在时间或者空间两个方面。如果是缺少计算空间,花钱买服务器就可以了。这是个花钱就能解决的问题。相反,如果是缺少计算时间,只能投入宝贵的人生时间去跑程序。即使你有再多的钱、再多的服务器,也是毫无用处。因此,相比于空间复杂度,时间复杂度的降低就显得更加重要了。可以发现这样的结论:空间是廉价的,最不济也是可以通过购买更高性能的计算机进行解决的。而时间是昂贵的,如果无法降低时间复杂度,那系统的效率就永远无法得到提高。

    无论什么难题,降低复杂度的方法都可以总结为以下三个步骤:

    1. 暴力解法。在没有任何时间、空间约束下,完成代码任务的开发。
    2. 无效操作处理。将代码中的无效计算、无效存储剔除,降低时间或空间复杂度。
    3. 时空转换。设计合理数据结构,完成时间复杂度向空间复杂度的转移。

    暴力解法

    假定在不限制时间、也不限制空间的情况下,完成某个任务的代码开发。这就是通常我们所说的暴力解法,也是程序优化的起点。

    如果当前暴力解法的复杂度比较低或者可以接受,那自然万事大吉。可如果暴力解法复杂度比较高的话,那就要考虑采用程序优化的方法去降低复杂度了。

    无效操作处理

    一个直观的思路是:梳理程序,看其流程中是否有无效的计算或者无效的存储。需要从时间复杂度和空间复杂度两个维度来考虑:

    • 常用的降低时间复杂度的方法有递归、二分法、排序算法、动态规划等,
    • 而降低空间复杂度的方法,就要围绕数据结构做文章了,核心思路就是能用低复杂度的数据结构能解决问题,就千万不要用高复杂度的数据结构

    举个例子,假设有任意多张面额为 2 元、3 元、7 元的货币,现要用它们凑出 100 元,求总共有多少种可能性。

    暴力解法如下:

    public void case1_1() {
    	int count = 0;
    	for (int i = 0; i < (100 / 7); i++) {
    		for (int j = 0; j < (100 / 3); j++) {
    			for (int k = 0; k < (100 / 2); k++) {
    				if (i * 7 + j * 3 + k * 2 == 100) {
    					count += 1;
    				}
    			}
    		}
    	}
    	System.out.println(count);
    }
    

    在这段代码中,使用了 3 层的 for 循环。从结构上来看,是很显然的 O( n³ ) 的时间复杂度。然而,仔细观察就会发现,代码中最内层的 for 循环是多余的。因为,当你确定了要用 i 张 7 元和 j 张 3 元时,只需要判断用有限个 2 元能否凑出 100 - 7* i - 3* j 元就可以了。

    代码改写如下:

    public void case1_2() {
    	int count = 0;
    	for (int i = 0; i < (100 / 7); i++) {
    		for (int j = 0; j < (100 / 3); j++) {
    			if ((100 - i * 7 - j * 3) % 2 == 0) {
    				count += 1;
    			}
    		}
    	}
    	System.out.println(count);
    }
    

    经过改造后,代码的结构由 3 层 for 循环,变成了 2 层 for 循环,时间复杂度就变成了O(n²) 。

    空间换时间的优化思路

    经过了前面剔除无效计算和存储的处理之后,如果程序在时间和空间等方面的性能依然还有瓶颈,又该怎么办呢?如果可以通过某种方式,把时间复杂度转移到空间复杂度的话,就可以把无价的东西变成有价了,实现了用空间换取时间。

    在程序开发中,连接时间和空间的桥梁就是数据结构。对于一个开发任务,如果你能找到一种高效的数据组织方式,采用合理的数据结构的话,那就可以实现时间复杂度的再次降低。同样的,这通常会增加数据的存储量,也就是增加了空间复杂度。

    举个例子,要查找出一个数组中,出现次数最多的那个元素的数值。

    暴力解法如下:

    public void case2_1() {
    	int a[] = { 1, 2, 3, 4, 5, 5, 5, 6, 6 };
    	int val_max = -1;
    	int time_max = 0;
    	int time_tmp = 0;
    	for (int i = 0; i < a.length; i++) {
    		time_tmp = 0;
    		for (int j = 0; j < a.length; j++) {
    			if (a[i] == a[j]) {
    				time_tmp += 1;
    			}
    			if (time_tmp > time_max) {
    				time_max = time_tmp;
    				val_max = a[i];
    			}
    		}
    	}
    	System.out.println(val_max);
    }
    

    采用两层的 for 循环完成计算。第一层循环,对数组每个元素遍历。第二层循环,则是对第一层遍历的数字,去遍历计算其出现的次数。同时,全局再缓存一个出现次数最多的元素及其次数就可以了。

    很显然,这份代码的时间复杂度就是 O(n²)。而且代码中,几乎没有冗余的无效计算。如果还需要再去优化,就要考虑采用一些数据结构方面的手段,来把时间复杂度转移到空间复杂度了。

    不妨思考一下,这个问题能否通过一次 for 循环就找到答案呢?一个直观的想法是,一次循环的过程中,我们同步记录下每个元素出现的次数。最后,再通过查找次数最大的元素,就得到了结果。

    针对这个思路,具体可以定义一个 k-v 结构的字典,用来存放元素和其出现次数。那么首先通过一次循环,将数组转变为元素-出现次数的一个字典。接下来,再去遍历一遍这个字典,找到出现次数最多的那个元素,就能找到最后的结果了。具体代码如下:

    public void case2_2() {
    	int a[] = { 1, 2, 3, 4, 5, 5, 5, 6, 6 };
    	Map<Integer, Integer> d = new HashMap<>();
    	for (int i = 0; i < a.length; i++) {
    		if (d.containsKey(a[i])) {
    			d.put(a[i], d.get(a[i]) + 1);
    		} else {
    			d.put(a[i], 1);
    		}
    	}
    	Collection<Integer> count = d.values();
        // 找出d中value中最大的数字,也就是数组中数字出现最多的次数
        int maxCount = Collections.max(count);
        int maxNumber = 0;
        for (Map.Entry<Integer, Integer> entry : d.entrySet()) {
            // 找到d中value为maxCount对应的key,也就是数组中出现次数最多的数字
            if (maxCount == entry.getValue()) {
                maxNumber = entry.getKey();
            }
        }
        System.out.println(maxNumber);
    }
    

    代码结构上,有两个 for 循环。不过,这两个循环不是嵌套关系,而是顺序执行关系。其中,第一个循环实现了数组转字典的过程,是 O(n) 的复杂度。第二个循环再次遍历字典找到出现次数最多的那个元素,也是一个 O(n) 的时间复杂度。因此,总体的时间复杂度为 O(n) + O(n),即 O(2n),根据复杂度与具体的常系数无关的原则,也就是O(n) 的复杂度。空间方面,由于定义了 k-v 字典,其字典元素的个数取决于输入数组元素的个数,空间复杂度增加为 O(n)。因此,这段代码通过采用更复杂、高效的数据结构,完成了时空转移,提高了空间复杂度,让时间复杂度再次降低。

    展开全文
  • 程序的优化方法

    2010-02-07 01:42:00
    首先提醒大家一句,再好语句上的优化也比不上算法上的优化所带来巨大效益,所以我觉得对这方面不太熟悉人都应该买本讲数据结构与算法书来看看。 下面就转入正题,讲一讲一般的优化技巧吧: (1) 使用内联...

        首先提醒大家一句,再好的语句上的优化也比不上算法上的优化所带来的巨大效益,所以我觉得对这方面不太熟悉的人都应该买本讲数据结构与算法的书来看看。

        下面就转入正题,讲一讲一般的优化技巧吧:

        (1)  使用内联函数。

        (2)  展开循环。

        for(i=0; i<100; i++)

        {

            do_stuff(i);

        }

        可以展开成: 

        for(i=0; i<100; i++)

        {

            do_stuff(i);  i++;

            do_stuff(i);  i++;

            do_stuff(i);  i++;

            do_stuff(i);  i++;

            do_stuff(i);  i++;

        }

        (3)  运算强度减弱

        例如如果有这样一段程序:

        int x = w % 8;

        int y = x * 33;

        float z = x / 5;

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

        {

            h = 14*i;

            cout<<h;

        }

        上面的程序这样改动可以大大加快速度:

        int x = w & 7;

        int y = (x << 5) + x; //比+的运算优先级低!

        float z = x * 0.2;

        for(int i=h=0;  i<100;  i++)

        {

            cout<<h;

            h += 14;

        }

        4.  查表

        这种方法挺有用。比如说我们定义了一个函数f(x)可以返回x*x*x, 其中x的范围是0~1,精度为0.001,那么我们可以建立一个数组a[1000], a[t*1000]存储的是预先计算好的t*t*t的值,以后调用函数就可以用查找。

    文章出处:http://blog.csdn.net/manplus/archive/2006/04/12/660105.aspx

    展开全文
  • 关于c程序中多层嵌套结构的优化方法,在百度中找来找去,发现写这方面的文章不多。下面就我个人总结出来的几个方法,写出来,与大家分享。也希望看到这篇文章的人,要是有更好的方法,也在底下评论留言。您的一点...

    关于c程序中多层嵌套结构的优化方法,在网上找来找去,发现写这方面的文章并不多。下面就个人总结出来的几个方法,写出来,与大家分享。也希望看到这篇文章的人,要是有更好的方法,也在底下评论留言。你的一点贡献,也许会帮到困扰中的程序员^_^。有什么不足,也麻烦指出来下,共同进步。打字不易,希望转发的人,注明下原出处,谢谢!

    方法一:并列法。

    示例:

    【优化前】:

    void func(void)

    {

        if( status1() ){

            if( status2() ){

                if( status3() ){

                    do_function();

                }

            }

        }

    }

    这种类型的,该怎么优化呢?注意到这个结构的特点,1.都没有else;2.三个条件嵌套只做一件事情“do_function();”。那可以把这些条件并列起来,即三个条件同时成立时,做“do_function();”。具体如下:

    【优化】:

    void func(void)

    {

        if( status1() \

        && status2() \

        && status3() ){

            do_function();

        }

    }

    就这样,三个if的嵌套结构,变成了1个if的普通条件判断。


    方法二:if-else倒置法。

    示例1:

    【优化前】:

    void func(void)

    {

        if( status1() ){

    do_function1();

            if( status2() ){

    do_function2();

                if( status3() ){

                    do_function3();

                }

                else{

                    do_unfunction3();

                }

            }

            else{

                do_unfunction2();

            }

        }

        else{

                do_unfunction1();

        }

    }

    再来看下这个结构,可以发现:1.第二个if在第一个if条件里面,第三个if在第二个if条件里面,也就是说,if都是堆积在一块地方的;2.做完else的事情(do_unfunction1()或do_unfunction2()或do_unfunction3())就结束该函数,退出去了。那么,可以把else的条件改作if的条件,每次去除一层if嵌套结构。什么意思呢?看下面的过程,一步一步解开:

    【中间过程优化1】:

    void func(void)
    {

        if( !status1() ){
            do_unfunction1();

            return ;
        }
    //这里是为了便于看清结构
        do_function1();
        if( status2() ){
            do_function2();
            if( status3() ){
                do_function3();
            }
            else{
                do_unfunction3();
            }
        }
        else{
            do_unfunction2();
        }
    //这里是为了便于看清结构
    }

    【中间过程优化2】:

    void func(void)

    {

        if( !status1() ){
            do_unfunction1();
            return ;
        }
        do_function1();
        if( !status2() ){
            do_unfunction2();
            return ;
        }
    //这里是为了便于看清结构
        do_function2();
        if( status3() ){
            do_function3();
        }
        else{
            do_unfunction3();
        }
    //这里是为了便于看清结构
    }

    【中间过程优化3】:

    void func(void)
    {
        if( !status1() ){
            do_unfunction1();
            return ;
        }
        do_function1();
        if( !status2() ){
            do_unfunction2();
            return ;
        }
        do_function2();
        if( !status3() ){
            do_function3();
            return ;
        }
    //这里是为了便于看清结构
        do_function3();
    //这里是为了便于看清结构
    }

    就是这么解开的。

    【优化】:

    void func(void)
    {
        if( !status1() ){
            do_unfunction1();
            return ;
        }
        do_function1();
        if( !status2() ){
            do_unfunction2();
            return ;
        }
        do_function2();
        if( !status3() ){
            do_function3();
            return ;
        }
        do_function3();
    }


    【杂乱条件的规整】

    示例2:

    【优化前】:

    void func(void)

    {

        if( status1() ){

            do_function1();

            if( status2() ){

                do_function2();

                if( status3() ){

                    do_function3();

                }

                else{

                    if( status4() ){

                        do_function4();

                    }

                    else{

                        do_unfunction4();

                    }

                    do_unfunction3();

                }

            }

            else{

                do_unfunction2();

            }

        }

        else{

            do_unfunction1();

        }

    }

    【优化后】:

    void func(void)

    {

        if( status1() ){

            do_function1();

            if( status2() ){

                do_function2();

                if( !status3() ){

                    if( status4() ){

                        do_function4();

                    }

                    else{

                        do_unfunction4();

                    }

                    do_unfunction3();

                }

                else{

                    do_unfunction3();

                }

            }

            else{

                do_unfunction2();

            }

        }

        else{

            do_unfunction1();

        }

    }

    又回到了 方法二【示例1】的那种“if都堆积在一块地方”的结构去了,就可以使用方法二来解套。没错,就是这样!
    这种方法的核心思想就是:
    1.先把if-else嵌套结构中的if归到一块去(if1嵌套if2,if2嵌套if3,if3嵌套if4。。。);
    2.else语句里面整到最后只能有简单的顺序执行语句或者函数调用。然后,就可以放心的使用方法二【if-else倒置法】。



    方法三:查表法(这方法的一个好处是:看懂了,结构很清晰)。
    拿方法二的【示例2】【优化前】例子来作为示例:

    【示例】:

    【优化前】

    void func(void)

    {

        if( status1() ){

            do_function1();

            if( status2() ){

                do_function2();

                if( status3() ){

                    do_function3();

                }

                else{

                    if( status4() ){

                        do_function4();

                    }

                    else{

                        do_unfunction4();

                    }

                    do_unfunction3();

                }

            }

            else{

                do_unfunction2();

            }

        }

        else{

            do_unfunction1();

        }

    }

    使用这种方法有一个前提,func函数中各个if条件里面的判断得都是独立的。即:status1() 结果不受status2()、status3()、status4()的影响,status2()结果也不受其他3个影响,status3()、status4()道理一样;

    同时,status1() 、status2()、status3()、status4()也不能受“void func(void)”里面其他语句/函数(do_function1()do_unfunction3()。。。)的影响。

    下面的过程,要是看不懂,就慢慢去领悟吧,不多说,抱歉!

    【优化后】

    struct {

        unsigned int s;

    //这里有4个do_func的函数参数,原因是对应着4个if-else嵌套条件,并且抹掉每个if/else内部if-else的条件后,上下部只有一个函数。在设计do_func函数时,也只要有4个函数参数就够了

        void (*do_func_arg1)(void);

        void (*do_func_arg2)(void);

        void (*do_func_arg3)(void);

        void (*do_func_arg4)(void);

    }handle_tbl[ ]={ //穷举

        {0,do_unfunction1,NULL,NULL,NULL}, //这里的数字0,最好用宏表示,来表达一个含义。不然也要在这里注释:0表示:AAA

        {1,do_unfunction1,NULL,NULL,NULL}, // 1:BBB

        {2,do_unfunction1,NULL,NULL,NULL}, // 2:CCC ,不注释,谁看得懂啊~,是吧!

        {3,do_unfunction1,NULL,NULL,NULL},

        {4,do_unfunction1,NULL,NULL,NULL},

        {5,do_unfunction1,NULL,NULL,NULL},

        {6,do_unfunction1,NULL,NULL,NULL},

        {7,do_unfunction1,NULL,NULL,NULL},

        {8,do_function1,do_unfunction2,NULL,NULL},

        {9,do_function1,do_unfunction2,NULL,NULL},

        {10,do_function1,do_unfunction2,NULL,NULL},

        {11,do_function1,do_unfunction2,NULL,NULL},

        {12,do_function1,do_function2,NULL,do_unfunction4},

        {13,do_function1,do_function2,NULL,do_function4},

        {14,do_function1,do_function2,do_function3,NULL},

        {15,do_function1,do_function2,do_function3,NULL}

    };

    void do_func(void (*func1)(void), void (*func2)(void), void (*func3)(void), void (*func4)(void))

    {

        if(NULL != func1)

            func1();

        if(NULL != func2)

            func2();

        if(NULL != func3)

            func3();

        if(NULL != func4)

            func4();

    }

    void func(void)

    {

        unsignedint i;

        unsigned int s=0;


        s = (s<<1) + (status1()?1:0);

        s = (s<<1) + (status2()?1:0);

        s = (s<<1) + (status3()?1:0);

        s = (s<<1) + (status4()?1:0);

        for(i=0;i<sizeof(handle_tbl)/sizeof(handle_tbl[0]);i++){

            if(i==s) { // s其实是可以自由发挥的,可以拿这里的条件换个方式来表示

                do_func(handle_tbl[ i].do_func_arg1,handle_tbl[ i].do_func_arg2,handle_tbl[ i].do_func_arg3,handle_tbl[ i].do_func_arg4);

            }

        }

    }


    以上的这几个“解套”方法,个人的一点经验总结。希望多多少少能有点用处,那我写这篇就值得了。

    展开全文
  • 我认为一个好的用于科学计算的程序代码应该:算法漂亮精妙,程序简洁易懂,运算快速,节省内存。这里有的地方是矛盾的,比如简洁vs易懂,时间... 好的方法、算法是程序优化的根本,选择最好的算法永远是王道。 二...
  • 目的为提出一种高效输电塔结构拓扑优化方法和简单实用用户操作界面.方法在蚁群优化思想基础上,采用...结论笔者提出基于蚁群算法输电塔结构拓扑优化数值模拟结果,明显优于其他拓扑优化方法程序实现了输入
  • 1、选择合适算法和数据结构  选择一种合适数据结构很重要,如果在一堆随机存放数中使用了大量插入和删除指令,那使用链表要快得多。数组与指针语句具有十分密切关系,一般来说,指针比较灵活简洁,而...
  • 程序优化的方法(C/C++)

    千次阅读 2013-02-18 08:42:28
    对程序进行优化, 通常是指优化程序代码或程序执行速度。优化代码和优化速度实际上是一...一、程序结构的优化 1 、程序的书写结构 虽然书写格式并不会影响生成的代码质量, 但是在实际编写程序时还是应该尊循一定的书
  • 优化程序方法

    2006-04-12 10:49:00
    首先提醒大家一句,再好语句上的优化也比不上算法上的优化所带来巨大效益,所以我觉得对这方面不太熟悉人都应该买本讲数据结构与算法书来看看。在第八章讲述了几种常用算法,如果你感兴趣可以看看。下面就...
  • 2、如果能将类的方法定义成 static,就尽量定义成 static,它的速度会提升将近 4 倍。 3、$row[‘id’] 的速度是$row[id]的 7 倍。4、echo 比 print 快,并且使用 echo 的多重参数(译注:指用逗号而不是句点)代替...
  • 代码优化是编译器重要阶段,是编译技术研究重点。优化算法复杂度高,需要有效地测试用例生成方法对其进行充分...重点介绍了该方法的基础、程序控制结构生成算法,并介绍了基于本方法实现一个编译器自动测试工具。
  • 本文几个优化程序性能的方法出自CSAPP第五章,通过不断修改源代码,试图欺骗编译器产生有效的代码 我们先引入度量标准每元素的周期数(CPE),表示程序性能。 我们先定义一个数据结构 data_t 代表数据类型 1 ...
  • C程序优化方法

    千次阅读 2010-12-29 01:01:00
    一、程序结构的优化 1、程序的书写结构 虽然书写格式并不会影响生成的代码质量, 但是在实际编写程序时还是应该尊循一定的书写规则, 一个书写清晰、明了的程序, 有利于以后的维护。在书写程序时,
  • 2. 学习使用SIMD Intrinsic函数指令优化程序性能。 实验要求: 1. 学习基本SIMD Intrinsic函数使用,并利用这些函数实现矩阵乘法。 2. 计算前两步加速比。 a) 为了更好体现加速比,要求适当增加矩阵规模;...
  • 根据PCB板结构的特点,利用自由度凝聚技术给出了元器件模型的自由度凝聚方法,并在此基础上利用子结构 安装技术给出了PCB板支撑布局优化建模方法。该方法大大缩减了结构优化分析自由度的数量,并便于实现元器件组件计算...
  • 50个php程序性能优化的方法1、 用单引号代替双引号来包含字符串,这样做会更快一些。因为 PHP 会在双引号包围的 字符串中搜寻变量,单引号则不会,注意:只有 echo 能这么做,它是一种可以把多个字符 串当作参数的...
  • 提出了一种轻权的大程序优化方法...结果表明,所提出的方法可以提高整个程序的性能,可将一个高维的优化空间转换为多个低维优化空间而降低迭代编译的优化开销,是一种易于实现且适合通用代码迭代编译的大程序优化方法。
  • 提出的布局优化方法是将桁架结构的截面变量、拓扑变量及形状变量统一为离散变量。将离散变量转化为适应于蚁群算法求解TSP问题的离散变量,应用MATLAB语言编写求解桁架结构布局优化程序,最终实现对问题的分析与求解。...
  • 为了提高结构耐撞性优化...用Ls-dyna软件为结构碰撞分析求解器,采用Matlab优化工具箱进行优化模型求解,实现了结构耐撞性优化程序。数值算例表明,基于响应面方法的2种优化模型都能高效地解决结构耐撞性优化问题。
  • DSP程序优化方法

    2019-11-09 10:23:31
    1、选择合适算法和数据结构 选择一种合适数据结构很重要,如果在一堆随机存放数中使用了大量插入和删除指令,那使用链表要快得多。数组与指针语句具有十分密切关系,一般来说,指针比较灵活简洁,而数组...
  • 用单引号代替双引号来包含字符串,这样做会更快一些。因为 PHP 会在双引号包围的 字符串中搜寻变量,单引号则不会,...如果能将类的方法定义成 static,就尽量定义成 static,它的速度会提升将近 4 倍。 $row[‘i...
  • 以平面杆件的每个杆段和结点为研究对象,以结点位移和结点力为设计变量,以每个杆段位移与内力关系以及结点力需要满足平衡条件形成目标函数,建立了杆件结构的未知位移和结点力的动态设计变量优化方法,编制通用程序完成...
  • [转载] C程序优化方法

    2019-07-31 02:57:12
    对程序进行优化,通常是指优化程序代码或程序执行速度。...一、程序结构的优化 1、程序的书写结构 虽然书写格式并不会影响生成的代码质量,但是在实际编写程序时还是应该尊循一定的书写规则,一个书...
  • 为实现连续体结构动态形状优化设计,运用连续统敏度分析方法,得到了结构体积、固有频率物质导数。在此基础上,采用控制点虚拟位移为设计变量,运用一阶泰勒展开建立优化模型,设置设计变量运动极限保证了优化...
  • 程序优化一般方法

    2020-03-10 14:33:33
    2.数据通信性能与数据量正相关,因而如果有一些数据字段不在界面中展示且数据结构比较复杂或包含长字符串,则不应使用setData来设置这些数据; 3.与界面渲染无关数据最好不要设置在data中,可以考虑设置在page...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,177
精华内容 1,270
关键字:

优化程序结构的方法