关于对For循环嵌套优化的问题
1.案例描述
由于一次Java面试的笔试题,当时没有写出很好的解决方案,特此专门撰写一篇博客来加以记录,方便日后的查看
面试题目如下:从性能上优化如下代码并说明优化理由?
for (int i = 0; i < 1000; i++){
for (int j = 0; j < 100; j++){
for (int k = 0; k < 10; k++){
System.out.println(i+""+j+""+k);
}
}
}
2.案例分析
从给出的代码可知,不论如何优化,testFunction执行的次数都是相同的,该部分不存在优化的可能。那么,代码的优化只能从循环变量i、j、k的实例化、初始化、比较、自增等方面的耗时上进行分析。
首先,我们先分析原题代码循环变量在实例化、初始化、比较、自增等方面的耗时情况:
| 变量 | 实例化(次数) | 初始化(次数) | 比较(次数) | 自增(次数) |
| i | 1 | 1 | 1000 | 1000 |
| j | 1 | 1000 | 1000 * 100 | 1000*100 |
| k | 1 | 1000*100 | 1000 * 100 * 10 | 1000 * 100 * 10 |
(注:由于单次耗时视不同机器配置而不同,上表相关耗时采用处理的次数进行说明)
该代码的性能优化就是尽可能减少循环变量i、j、k的实例化、初始化、比较、自增的次数,同时,不能引进其它可能的运算耗时。)
3.解决过程
从案例分析,对于原题代码,我们提出有两种优化方案:
for (int i = 0; i < 10; i++){
for (int j = 0; j < 100; j++){
for (int k = 0; k < 1000; k++){
System.out.println(i+""+j+""+k);
}
}
}
该方案主要是将循环次数最少的放到外面,循环次数最多的放里面,这样可以最大程度的(注:3个不同次数的循环变量共有6种排列组合情况,此种组合为最优)减少相关循环变量的实例化次数、初始化次数、比较次数、自增次数,方案耗时情况如下:
| 变量 | 实例化(次数) | 初始化(次数) | 比较(次数) | 自增(次数) |
| i | 1 | 1 | 10 | 10 |
| j | 10 | 10 | 10*100 | 10 * 100 |
| k | 10*100 | 10*100 | 10 * 100 * 1000 | 10 * 100 * 1000 |
3.2 优化方案二
代码如下:
int i, j, k;
for (i = 0; i < 10; i++){
for (j = 0; j < 100; j++){
for (k = 0; k < 1000; k++){
System.out.println(i+" "+j+" "+k);
}
}
}
该方案在方案一的基础上,将循环变量的实例化放到循环外,这样可以进一步减少相关循环变量的实例化次数,方案耗时情况如下:
| 变量 | 实例化(次数) | 初始化(次数 | 比较(次数) | 自增(次数) |
| i | 1 | 1 | 10 | 10 |
| j | 1 | 10 | 10*100 | 10*100 |
| k | 1 | 10*100 | 10*100*1000 | 10*100*1000 |
4 解决结果
那么,提出的优化方案是否如我们分析的那样有了性能上的提升了呢?我们编写一些测试代码进行验证,数据更能说明我们的优化效果。
4.1 测试代码
public static void testFunction(int i, int j, int k) {
System.out.print(""); // 注:该方法不影响整体优化,这里只有简单输出
}
public static void testA() {
long start = System.nanoTime();
for (int i = 0; i < 1000; i++)
for (int j = 0; j < 100; j++)
for (int k = 0; k < 10; k++)
testFunction(i, j, k);
System.out.println("testA time>>" + (System.nanoTime() - start));
}
public static void testB() {
long start = System.nanoTime();
for (int i = 0; i < 10; i++)
for (int j = 0; j < 100; j++)
for (int k = 0; k < 1000; k++)
testFunction(k, j, i);
System.out.println("testB time>>" + (System.nanoTime() - start));
}
public static void testC() {
long start = System.nanoTime();
int i;
int j;
int k;
for (i = 0; i < 10; i++)
for (j = 0; j < 100; j++)
for (k = 0; k < 1000; k++)
testFunction(k, j, i);
System.out.println("testC time>>" + (System.nanoTime() - start));
}
4.2 测试结果
1、测试机器配置:Pentium(R) Dual-Core CPU E5400 @2.70GHz 2.70GHz, 2GB内存;
2、循环变量i、j、k循环次数分别为10、100、1000,进行5组测试,测试结果如下:
| 第1组 | 第2组 | 第3组 | 第4组 | 第5组 | |
| 原方案 | 171846271 | 173250166 | 173910870 | 173199875 | 173725328 |
| 方案一 | 168839312 | 168466660 | 168372616 | 168310190 | 168041251 |
| 方案二 | 168001838 | 169141906 | 168230655 | 169421766 | 168240748 |
从上面的测试结果来看,优化后的方案明显性能优于原方案,达到了优化的效果。但优化方案二并没有如我们预期的优于方案一,其中第2、4、5组的数据更是比方案一差,怀疑可能是循环次数太少,以及测试环境相关因素影响下出现的结果。
3、重新调整循环变量i、j、k循环次数分别为20、200、2000,进行5组测试,测试结果如下:
| 第1组 | 第2组 | 第3组 | 第4组 | 第5组 | |
| 原方案 | 1355397203 | 1358978176 | 1358128281 | 1350193682 | 1354786598 |
| 方案一 | 1343482704 | 1348410388 | 1343978037 | 1347919156 | 1340697793 |
| 方案二 | 1342427528 | 1343897887 | 1342662462 | 1342124048 | 1336266453 |
从上面的测试结果来看,优化后的方案基本符合我们的预期结果。
5 总结
从案例分析和解决过程中的三个表的分析可知,优化方案一和优化方案二的性能都比原代码的性能好,其中优化方案二的性能是最好的。在嵌套For循环中,将循环次数多的循环放在内侧,循环次数少的循环放在外侧,其性能会提高;减少循环变量的实例化,其性能也会提高。从测试数据可知,对于两种优化方案,如果在循环次数较少的情况下,其运行效果区别不大;但在循环次数较多的情况下,其效果就比较明显了。
关于对For循环嵌套优化的问题的更多相关文章
- Python 三级菜单与优化(一层循环嵌套)
优化的思路是使用单层循环嵌套完成三级菜单,这个优化思路我非常喜欢,我喜欢在编程的时候用最少的东西写出同样的效果,通常这样会绕来绕去,但非常有趣!!! 需求: 1.运行程序输出第一级菜单: 2.选择一级 ...
- SQL连接操作符介绍(循环嵌套, 哈希匹配和合并连接)
今天我将介绍在SQLServer 中的三种连接操作符类型,分别是:循环嵌套.哈希匹配和合并连接.主要对这三种连接的不同.复杂度用范例的形式一一介绍. 本文中使用了示例数据库AdventureWorks ...
- for循环嵌套练习题or99乘法表
//输出1-10之间的和 public static void whileTest(){ //定义变量用于存储不断变化的和 int sum = 0; //定义变量,用于记录不断变化的被加数 int x ...
- Java基础_循环嵌套_打印乘法口诀、菱形,各种图形,计算二元一次和三元一次方程组_7
循环嵌套 打印乘法口诀 for(int j=1;j<=9;j++){ for(int i=1;i<=j;i++){ System.out.print(i+"*"+j+& ...
- C#用链式方法表达循环嵌套
情节故事得有情节,不喜欢情节的朋友可看第1版代码,然后直接跳至“三.想要链式写法” 一.起缘 故事缘于一位朋友的一道题: 朋友四人玩LOL游戏.第一局,分别选择位置:中单,上单,ADC,辅助:第二局新 ...
- for循环与for循环嵌套
今天温习了下分支语句跟for循环,主要讲解了for循环嵌套,这里开始有点迷糊了,整理下思路在做练习 for循环嵌套用我自己的大白话来说就是一个外圈的for程序里面一个套着一个小的for程序,如果在范围 ...
- tonado框架的列表嵌套 (template中for循环嵌套)
学习了tonado框架,渐渐开始明白模板的转换,以后肯定还会遇到很多问题... 功能描述: 页面显示读取的数据库父导航名称,再通过嵌套列表将子导航名称和地址查询出来,返回到 ...
- php for循环嵌套
<?php //2.打印一个50*50的 'o' 的正方形方整, 使用for的嵌套 // oooooo // oooooo // oooooo //for循环嵌套 ...
- For 循环嵌套 0309
For ...
随机推荐
- ASP.NET Core中的project.json何去何从?
Shawn Wildermuth (https://wildermuth.com/2016/05/12/The-Future-of-project-json-in-ASP-NET-Core) If y ...
- .NET平台上插拔姿势的AOP
AOP概述 AOP技术的诞生并不算晚,早在1990年开始,来自Xerox Palo Alto Research Lab(即PARC)的研究人员就对面向对象思想的局限性进行了分析.他们研究出了一种新的编 ...
- 一款批量修改AE模板的工具
一.需求分析 对于视频后期剪辑及相关从业人员来说,AE(After Effects)模板效果是一个不错的开始点.在模板效果的基础上,可以很快的做出各种炫酷的后期效果.但是在网上下载的模板工程中,往往包 ...
- 如果你也会C#,那不妨了解下F#(2):数值运算和流程控制语法
本文链接:http://www.cnblogs.com/hjklin/p/fs-for-cs-dev-2.html 一些废话 一门语言火不火,与语言本身并没太大关系,主要看语言的推广. 推广得好,用的 ...
- struts2工作流程
struts2的框架结构图 工作流程 1.客户端请求一个HttpServletRequest的请求,如在浏览器中输入http://localhost: 8080/bookcode/Reg.action ...
- 精彩 JavaScript 代码片段
1. 根据给定的条件在原有的数组上,得到所需要的新数组. ——<JavaScript 王者归来> var a = [-1,-1,1,2,-2,-2,-3,-3,3,-3]; functio ...
- NginxWeb服务器安装
1. 安装编译工具和库文件 [root@bigdata-51cdh opt]# yum -y install make zlib zlib-devel gcc-c++ libtool opens ...
- Android的历史与花边
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 历史 现在的Android如日中天.每天150万部的Android设备被激活,全球 ...
- kindle型号
这篇文章为 Kindle 新手解决三个问题:怎么辨别Kindle 型号?通过 Kindle 外观判断准确吗?Kindle序列号在那里? 贴吧吧友提问的原话"在咸鱼看到一台,那哥们说也不知道K ...
- 手游录屏直播技术详解 | 直播 SDK 性能优化实践
在上期<直播推流端弱网优化策略 >中,我们介绍了直播推流端是如何优化的.本期,将介绍手游直播中录屏的实现方式. 直播经过一年左右的快速发展,衍生出越来越丰富的业务形式,也覆盖越来越广的应用 ...