常见性能优化技巧总结

一、多用有序数组+折半查找
金山卫士开源后立马招来各种批判,其中有一段批评金山卫士源码说太多if else而不用表驱动使得代码可读性不高,笔者看了下大致如下:

TCHAR  szFolderPath[MAX_PATH + 1] = {0};
// MichaelPeng: if else太多,应做成表驱动
if (0 == _tcsicmp(szVariable, _T("%Desktop%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_DESKTOP, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Internet%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_INTERNET, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Programs%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_PROGRAMS, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Controls%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_CONTROLS, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Printers%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_PRINTERS, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Personal%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_PERSONAL, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Favorites%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_FAVORITES, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Startup%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_STARTUP, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Recent%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_RECENT, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Sendto%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_SENDTO, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Bitbucket%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_BITBUCKET, 0);
} else if (0 == _tcsicmp(szVariable, _T("%StartMenu%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_STARTMENU, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Mydocuments%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_MYDOCUMENTS, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Mymusic%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_MYMUSIC, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Myvideo%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_MYVIDEO, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Desktopdirectory%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_DESKTOPDIRECTORY, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Drives%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_DRIVES, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Network%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_NETWORK, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Nethood%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_NETHOOD, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Fonts%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_FONTS, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Templates%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_TEMPLATES, 0);
} else if (0 == _tcsicmp(szVariable, _T("%CommonStartMenu%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_COMMON_STARTMENU, 0);
} else if (0 == _tcsicmp(szVariable, _T("%CommonPrograms%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_COMMON_PROGRAMS, 0);
} else if (0 == _tcsicmp(szVariable, _T("%CommonStartup%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_COMMON_STARTUP, 0);
} else if (0 == _tcsicmp(szVariable, _T("%LocalAppdate%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_LOCAL_APPDATA, 0);
} else if (0 == _tcsicmp(szVariable, _T("%CommonAppdata%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_COMMON_APPDATA, 0);
} else if (0 == _tcsicmp(szVariable, _T("%Windows%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_WINDOWS, 0);
} else if (0 == _tcsicmp(szVariable, _T("%System32%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_SYSTEM, 0);
} else if (0 == _tcsicmp(szVariable, _T("%ProgramFilesComm%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_PROGRAM_FILES_COMMON, 0);
} else if (0 == _tcsicmp(szVariable, _T("%CommonDocuments%"))) {
	::SHGetSpecialFolderPath(NULL, szFolderPath, CSIDL_COMMON_DOCUMENTS, 0);
}

代码写成这样可读性的确不高而且难看,曾经在和朋友讨论时候他们提到应该使用结构体数组做映射然后遍历查找,但是笔者认为这并非良策,同时也有人提出使用map,通过以字符串大小做key,这样查找效率会提高很多。不过笔者认为最好的方法还是结构体数组,然后通过字符串大小规则排序,然后使用折半查找法保证效率和map一致。这样做能保证查找效率的时候还能够节约内存,虽说这地方体验不出明显节约内存。

为什么数组比map更节约内存?因为map是采用红黑树数据结构,每个节点都是一个单独的堆节点,考虑到每次神奇怪内存时多余的堆数据结构和指向其他节点的指针,当节点数达到一定时候内存占用量就会表现越加明显。

其实可以做一个简单的实验,分别写两个程序测试;

void main()
{
	char *p = new char[100000];
	getchar();
}

void main()
{
	for (int i = 0;i <100000;i++)
		char *p = new char;
	getchar();
}

上面两个程序运行起来你会发现后者占内存明显比前者大,其实是一样的道理。
其实这种方法并不是什么时候都适用的,考虑到数组增加元素的麻烦性,如果元素需要不断增加删除,那么map就是更好的选择,另外如果能预先知道元素的查找频率,得知极少数元素查找频率极高而大部分元素极少查询,那么用表驱动,将查找频率最高的元素放在首位按照无序遍历也是不错的选择。

二、巧用哨兵元素

问题由来:对于一个有N个元素的无序数组a[n],判断其中是否有key这个值,写一个函数。

很多人拿到这个问题直接写出如下代码

BOOL GetIndexBkey(int a[],int nSize,int nKey)
{
	for (int i = 0; i < nSize;i++)
	{
		if (nKey == a[i])
		{
			return TRUE;
		}
	}

	return FALSE;
}

这么写其实也能达到目的,但是细细看来每一次循环的时候都会比较两次i < nSize和nKey == a[i]。事实上我们可以用一种很巧妙的方法减少一次比较,这样以来在数据量很大的时候效率就会较明显提升,如果这个函数调用相当频繁那么优化效果还是很明显,具体如下:

BOOL GetIndexBkey(int a[],int nSize,int nKey)
{
	//首先判断最后一个元素是不是关键字,如果是直接返回
	if (a[nSize-1] == nKey)
	{
		return TRUE;
	}

	//保存数组中最后一个元素,同时将最后一个元素赋值成key
	int nSavelastValue = a[nSize-1];
	a[nSize-1] = nKey;

	int i = 0;
	while (a[i]!=nKey)
	{
		i++;
	}

	//由于最后一个元素为key,所以上面的循环必定有出口
	//当循环跳出后如果此时索引指向最后一个元素,说明查找失败
	//反之成功
	a[nSize-1] = nSavelastValue;
	if (i == nSize-1)
	{
		return TRUE;
	}

	return FALSE;
}

通过以上写法可以讲比较次数降低到N+2,同时增加3次赋值操作,比起之前2N次比较工作量明显小了许多,同时CPU执行的指令也会大幅度减少,效率自然就更高了。

未完待续...

常见性能优化技巧总结

时间: 2024-08-24 08:10:28

常见性能优化技巧总结的相关文章

java性能优化技巧

一.通用篇 "通用篇"讨论的问题适合于大多数 Java应用. 1.1     new 1.1     new 11..11 不用 nneeww关键词创建类的实例 用new 关键词创建类的实例时,构造函数链中的所有构造函数都会被自动调用.但如 果一个对象实现了Cloneable 接口,我们可以调用它的clone()方法.clone()方法不会调用任 何类构造函数. 在使用设计模式(Design Pattern)的场合,如果用 Factory模式创建对象,则改用clone() 方法创建新的

Python 代码性能优化技巧(转)

原文:Python 代码性能优化技巧 Python 代码优化常见技巧 代码优化能够让程序运行更快,它是在不改变程序运行结果的情况下使得程序的运行效率更高,根据 80/20 原则,实现程序的重构.优化.扩展以及文档相关的事情通常需要消耗 80% 的工作量.优化通常包含两方面的内容:减小代码的体积,提高代码的运行效率. 改进算法,选择合适的数据结构 一个良好的算法能够对性能起到关键作用,因此性能改进的首要点是对算法的改进.在算法的时间复杂度排序上依次是: O(1) -> O(lg n) -> O(

JavaScript 性能优化技巧分享

JavaScript 作为当前最为常见的直译式脚本语言,已经广泛应用于 Web 应用开发中.为了提高Web应用的性能,从 JavaScript 的性能优化方向入手,会是一个很好的选择. 本文从加载.上下文.解析.编译.执行和捆绑等多个方面来讲解 JavaScript 的性能优化技巧,以便让更多的前端开发人员掌握这方面知识. 什么是高性能的 JavaScript 代码? 尽管目前没有高性能代码的绝对定义,但却存在一个以用户为中心的性能模型,可以用作参考:RAIL模型. 响应 如果你的应用程序能在1

JavaScript 如何工作:渲染引擎和性能优化技巧

翻译自:How JavaScript works: the rendering engine and tips to optimize its performance 这是探索 JavaScript 及其构建组件专题系列的第 11 篇.在识别和描述核心元素的过程中,我们分享了在构建 SessionStack 时使用的一些经验法则.SessionStack 是一个需要鲁棒且高性能的 JavaScript 应用程序,它帮助用户实时查看和重现它们 Web 应用程序的缺陷. 当构建 Web 应用程序时,

Java性能优化技巧及实战

Java性能优化技巧及实战 关于Java代码的性能优化,是每个javaer都渴望掌握的本领,进而晋升为大牛的必经之路,但是对java的调优需要了解整个java的运行机制及底层调用细节,需要多看多读多写多试,并非一朝一夕之功.本文是近期笔者给公司员工内部做的一个培训,主要讲述在系统压测过程中出现的性能问题,以及如何在编码过程中提升代码的运行效率,需要掌握哪些实战技巧.片子里干货较多,也很具有实操性,因此发文出来,共享给大家(部分数据做了去除公司特征信息,见谅).(PS:由于原文是ppt,因此做了导

Java代码性能优化技巧

流方面: private FileOutputStream writer; writer = new FileOoutputStream(fileName); 使用BufferedOutputStream 对写入FileOutputStream的数据进行缓存 //将writer的类型由FileOutputStream 变更为BufferedOutputStream //private FileOutputStream writer; private BufferedOutputStream wr

Java程序性能优化技巧

多线程.集合.网络编程.内存优化.缓冲..spring.设计模式.软件工程.编程思想 1.生成对象时,合理分配空间和大小new ArrayList(100); 2.优化for循环Vector vect = new Vector(1000);for( inti=0; i<vect.size(); i++){ ...}for循环部分改写成:int size = vect.size();for( int i=0; i>size; i++){ ...} 如果size=1000,就可以减少1000次si

李洪强iOS开发之性能优化技巧

李洪强iOS开发之性能优化技巧 通过静态 Analyze 工具,以及运行时 Profile 工具分析性能瓶颈,并进行性能优化.结合本人在开发中遇到的问题,可以从以下几个方面进行性能优化. 一.view优化 1.不透明的View 设置为opaque. 2.根据实际情况重用.延迟加载或预加载View. 3.减少subviews数量,定制复杂cell使用drawRect.尽量使用drawRect而不是layoutSubView. 4.不直接调用drawRect. layoutSubviews方法.万不

android App性能优化技巧浅谈

Android App性能优化,安卓App性能优化技巧,无论锤子还是茄子手机的不断冒出,Android系统的手机市场占有率目前来说还是最大的,因此基于Android开发的App数量也是很庞大的.那么,如何能开发出更高性能的Android App?相信是软件开发公司以及广大程序员们头疼的一大难题.今天,就给大家提供几个提高Android App性能的技巧. 高效地利用线程1.在后台取消一些线程中的动作 我们知道App运行过程中所有的操作都默认在主线程(UI线程)中进行的,这样App的响应速度就会受