程序性能优化(一)

经过设计合理的数据结构和算法将一些本须要在运行期间计算的信息预先存放在内存中来提高性能,是一种空间换时间的优化,下面一些实际的例子描述了这种优化方法的使用:html

  • 在一个递增的数组中查询和待查找元素最接近的的索引

例如数组[1,2,3,4,5],待查找元素为1.1返回数组索引0,待查找元素为1.6返回数组索引1,经过计算和数组每一个元素的差值,循环遍历一遍数组能够便可获得索引值,以下代码所示:算法

const double g_searchTable[] = {1,2,3,4,5};

int getIndex(double data)
{
    int index = 0;
    double temp;

    double temp1 = fabs(g_searchTable[0]-data);

    for(int i=0;i<sizeof(g_searchTable)/sizeof(g_searchTable[0]);i++)
    {
        temp = fabs(g_searchTable[i]-data);
        if(temp < temp1)
        {
            temp1 = temp;
            index = i;
        }
    }

    return index;
}
View Code

该代码在循环内部存在浮点数计算、计算绝对值并且要遍历数组,若是数组足够大且频繁调用程序性能必然低下。咱们能够经过把非递减的数组元素当作一个连续区域中的几个位置,计算出各个位置间的中点,划分为不一样的区间,便可经过比较待待查找的元素落在什么区间中得出索引值。入下图所示若是待查找元素小于1.5返回索引0。这里就须要咱们增长一个区间数组[1.5,2.5,3.5,4.5],在代码中直接跟元素比较便可获得索引信息。数组

const double g_searchTable[] = {1,2,3,4,5};
const double g_searchDivTable[] = {1.5,2.5,3.5,4.5};

int getIndex1(double data)
{
    int index = 0;

    for(int i=0;i<sizeof(g_searchDivTable)/sizeof(g_searchDivTable[0]);i++)
    {
        if(data < g_searchDivTable[i])
        {
            return i;
        }
    }

    return sizeof(g_searchDivTable)/sizeof(g_searchDivTable[0]);
}
View Code

经过增长一个对应的区间数组空间,咱们消除了浮点运算、绝对值计算,而且在肯定待查元素的区间后便可获得结果,不用继续遍历数组。性能优化

  • switch语句的编译优化

咱们在代码中常常使用switch语句,其结构清晰,经过计算表达式的值跳转到指定的case分支中,在编译过程当中每每并非将表达式同case常量依次比较来定位到具体分支中,这样的效率每每很低下,编译器一般使用了“跳转表技术”来定位分支目标地址。跳转表能够当作一个地址数组,其中每个元素表示一个代码段的地址,经过映射表达式值为跳转表中的索引便可获取对应的目标地址。以下switch语句:数据结构

switch(n)
{
  case 5:   //ADDR1
  case 7:   //ADDR2
  deafult:  //DEFAULT_ADDR
}

编译器每每转换为以下跳转表:数据结构和算法

JumpTable = [ADDR1, DEFAULT_ADDR, ADDR1];

int index = n-5;
if index >2
    goto DEFAULT_ADDR

goto JumpTable [index]

经过使用跳转表技术,增长跳转表的空间消耗,能够直接定位到目标地址。ide

  • 字符串到系统标示符的映射

在一些系统中咱们每每须要将一系列的字符串转换为系统对应的标示符,例如编译器的分词模块对输入的“int”字符串转换为系统的TK_INT类型。系统中默认的标示符每每不少,若是对输入字符串经过代码分支依次比较将十分耗费时间。为了提高效率咱们能够考虑经过使用hash技术,选取合适的散列函数将字符串转换为一个映射数组的下标。下面代码将“add”、“sub”、“mul”、“div”转换为系统的对应类型:函数

typedef enum
{
    T_ADD,
    T_SUB,
    T_MUL,
    T_DIV,
    T_ERR
}Token;
typedef struct
{
    char* str;
    Token tk;
    char nextFlag;
}MAP_T;

MAP_T map0[] = {{"add",T_ADD,1},{"sub",T_SUB,1},{"mul",T_MUL,0}};//“add”、“sub”、“mul”经过散列函数计算出相同的数组下标0
MAP_T map1[] = {{"div",T_DIV,0}};//“div”经过散列函数计算出数组下标1
//映射信息
MAP_T* hashTable[] = {map0,map1};

Token getTk(char* str)
{
    int index = -1;
    MAP_T *pMap = NULL;

    index = getHashCode(str);
    pMap = hashTable[index];

    while(1)
    {
        if(0 == strcmp(str,pMap->str))
        {
            return pMap->tk;
        }
        if(0 == pMap->nextFlag)
        {
            break;
        }
        pMap++;
    }
    return T_ERR;
}
View Code

入上所示,咱们保存了全部字符串和系统标示符的对应关系,计算待转换字符串的hash值便可快速定位到一个小的区间中。经过选取适当散列函数能够的获得更好的效率。这里使用了链地址法来解决hash冲突。性能

 

以上实例都是基于空间换时间的优化方式,经过设计合理的数据结构,保存关键的信息,能够极大的对程序性能优化。优化

转载请注明原始出处:http://www.cnblogs.com/chencheng/p/3372945.html

相关文章
相关标签/搜索