C与C++中的常用提高程序效率的方法

25 篇文章 1 订阅

1.用a++和++a及a+=1代替a=a+1,用a--和--a及a-=1代替a=a-1

  通常使用自加、自减指令和复合赋值表达式(如a-=1及a+=1等)都能够生成高质量的程序代码,编译器通常都能够生成inc和dec之类的指令,而使用a=a+1或a=a-1之类的指令,有很多C编译器都会生成二到三个字节的指令。


2.用内联函数(inline)代替简单的函数

  若把一个函数定义为内联函数,则在程序编译阶段,编译器就会把每次调用该函数的地方都直接替换为该函数体中的代码,因此省却了函数的调用及相应的保护现场、参数传递和返回等操作,从而加快了整个程序的执行速度。总之,简单函数尽量声明为内联函数


3.函数尽量用引用传递减少非引用传递(值的传递

  引用就是把实参直接传给函数,而非引用传递则是将实参复制给形参,形参又要分配存储单元。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。所以引用传递是比非引用传递快的。

  而且引用传递可以直接改变参数的值,但是如果使用非引用传递则要将参数声明为全局变量才能改变其值。(指针为间引用)

  常引用

  常引用声明方式:const 类型标识符 &引用名=目标变量名;用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。


4.减少除法运算

  无论是整数还是浮点数的运算,出发都会比较耗时,所以最后将除法运算等效成乘法运算。例如:a/b>20可改为a>b*20,可以简化程序的运行时间。


5.推迟定义本地变量

  虽然C语言中标准是将变量统一定义在开头,但是在C++中最好放弃这种做法,因为这会带来不必要的开销,而且费时费力。

   定义一个对象变量通常需要调用一次函数(构造函数)。如果一个变量只在某些情况下需要(例如在一个if声明语句内),仅在其需要的时候定义,这样,构造函数仅在其被使用的时候调用。

  并且,推迟变量的定义会提高程序的效率,增强程序的可读性,形成更好的可视性。


6.在一大段内存进行初始化时,尽量使用memset,例如数组的多次初始化

7.goto语句的使用,虽然goto语句历来被称程序员所诟病,但是不得不说,goto的最重要的作用,跳出多重循环,这个方法可以非常好的提高程序效率。(既然goto语句隐患太多,我们只用一个跳出循环就好了大笑

//省去了使用break而必须附带的各种标志变量

<span style="font-size:12px;">/*
    目标:学习goto语句
*/
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
   int n,i,j;
   cin>>n;
   for(i=0;i<n;i++)
   {
       for(j=0;j<n;j++)
       {
           if(10==i+j)
            goto error;
       }
   }
   error:
       printf("%d %d Y\n",i,j);
    return 0;
}</span>

8.在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数。(from高质量编程指南)

9.头文件的简化

#include <bits/stdc++.h>

在codeforces中看到大牛代码,发现这个神奇的头文件,写着一个之后就可以使用各种头文件里面的东西了,包括:

#include <cstdio>
#include <iostream>
#include <vector>
#include <map>
#include <fstream>    
#include <algorithm>    
#include <cmath>    
#include <deque>    
#include <vector>    
#include <queue>    
#include <string>    
#include <cstring>    
#include <stack>    
#include <set>


大牛github讲解    翻墙才行

头文件简化也算提高效率了吧,只是国内oj貌似还不能用……

10.如何定义基本类型的最值

int 、long 10^9

long long 10^18

float         10^38

double     10^308

long double 10^4932

求最短路的时候总会定义一个无穷大,INF = 无穷大,然后将数组内都初始化为无穷大,就用循环了,多复杂啊,好方法,memset(a,0x3f,sizeof(a));

  那么这个无穷大为多少最合适呢,这个也不好说啊,啊哈算法中的作者说,通常定义INF=999 999 99合适。

  今天又看到了一篇博客(出处难寻了),定义INF=0x3f3f3f3f,理由:

如果问题中各数据的范围明确,那么无穷大的设定不是问题,在不明确的情况下,很多程序员都取0x7fffffff作为无穷大,因为这是32-bit int的最大值。如果这个无穷大只用于一般的比较(比如求最小值时min变量的初值),那么0x7fffffff确实是一个完美的选择,但是在更多的情况下,0x7fffffff并不是一个好的选择。

很多时候我们并不只是单纯拿无穷大来作比较,而是会运算后再做比较,例如在大部分最短路径算法中都会使用的松弛操作:
if (d[u]+w[u][v]<d[v]) d[v]=d[u]+w[u][v];
我们知道如果u,v之间没有边,那么w[u][v]=INF,如果我们的INF取0x7fffffff,那么d[u]+w[u][v]会溢出而变成负数,我们的松弛操作便出错了,更一般的说,0x7fffffff不能满足“无穷大加一个有穷的数依然是无穷大”,它变成了一个很小的负数。
除了要满足加上一个常数依然是无穷大之外,我们的常量还应该满足“无穷大加无穷大依然是无穷大”,至少两个无穷大相加不应该出现灾难性的错误,这一点上0x7fffffff依然不能满足我们。
所以我们需要一个更好的家伙来顶替0x7fffffff,最严谨的办法当然是对无穷大进行特别处理而不是找一个很大很大的常量来代替它(或者说模拟它),但是这样会让我们的编程过程变得很麻烦。在我读过的代码中,最精巧的无穷大常量取值是0x3f3f3f3f,我不知道是谁最先开始使用这个精妙的常量来做无穷大。

0x3f3f3f3f的十进制是1061109567,也就是10^9级别的(和0x7fffffff一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。
另一方面,由于一般的数据都不会大于10^9,所以当我们把无穷大加上一个数据时,它并不会溢出(这就满足了“无穷大加一个有穷的数依然是无穷大”),事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这非常大但却没有超过32-bit int的表示范围,所以0x3f3f3f3f还满足了我们“无穷大加无穷大还是无穷大”的需求。
最后,0x3f3f3f3f还能给我们带来一个意想不到的额外好处:如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a))这样的代码来实现(方便而高效),但是当我们想将某个数组全部赋值为无穷大时(例如解决图论问题时邻接矩阵的初始化),就不能使用memset函数而得自己写循环了(写这些不重要的代码真的很痛苦),我们知道这是因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0,现在好了,如果我们将无穷大设为0x3f3f3f3f,那么奇迹就发生了,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存全部置为无穷大,我们只需要
memset(a,0x3f,sizeof(a))

所以在通常的场合下,0x3f3f3f3f真的是一个非常棒的选择。


11.有时候全局变量比局部变量省时的多(一般不会遇到?)。

目前先更新这C++学习进一步深入时继续更新

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值