嵌套For循环性能优化

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。
1 案例描述
某日,在JavaEye上看到一道面试题,题目是这样的:请对以下的代码进行优化
Java代码 复制代码 收藏代码
  1. for (int i = 0; i < 1000; i++)  
  2.     for (int j = 0; j < 100; j++)  
  3.         for (int k = 0; k < 10; k++)  
  4.             testFunction (i, j, k);  
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);

(注:为了同后面的内容一致,这里对原题目进行了部分修改)

2 案例分析
从给出的代码可知,不论如何优化,testFunction执行的次数都是相同的,该部分不存在优化的可能。那么,代码的优化只能从循环变量i、j、k的实例化、初始化、比较、自增等方面的耗时上进行分析。
首先,我们先分析原题代码循环变量在实例化、初始化、比较、自增等方面的耗时情况:
变量实例化(次数)初始化(次数)比较(次数)自增(次数)
i1110001000
j100010001000 * 1001000 * 100
k1000 * 1001000 * 1001000 * 100 * 101000 * 100 * 10

(注:由于单次耗时视不同机器配置而不同,上表相关耗时采用处理的次数进行说明)
该代码的性能优化就是尽可能减少循环变量i、j、k的实例化、初始化、比较、自增的次数,同时,不能引进其它可能的运算耗时。

3 解决过程
从案例分析,对于原题代码,我们提出有两种优化方案:
3.1 优化方案一
代码如下:
Java代码 复制代码 收藏代码
  1. for (int i = 0; i < 10; i++)  
  2.     for (int j = 0; j < 100; j++)  
  3.         for (int k = 0; k < 1000; k++)  
  4.             testFunction (k, j, i);  
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);

该方案主要是将循环次数最少的放到外面,循环次数最多的放里面,这样可以最大程度的(注:3个不同次数的循环变量共有6种排列组合情况,此种组合为最优)减少相关循环变量的实例化次数、初始化次数、比较次数、自增次数,方案耗时情况如下:
变量实例化(次数)初始化(次数)比较(次数)自增(次数)
i111010
j101010 * 10010 * 100
k10 * 10010 * 10010 * 100 * 100010 * 100 * 1000


3.2 优化方案二
代码如下:
Java代码 复制代码 收藏代码
  1. int i, j, k;  
  2. for (i = 0; i < 10; i++)  
  3.     for (j = 0; j < 100; j++)  
  4.         for (k = 0; k < 1000; k++)  
  5.             testFunction (k, j, i);  
int i, j, k;
for (i = 0; i < 10; i++)for (j = 0; j < 100; j++)for (k = 0; k < 1000; k++)testFunction (k, j, i);

该方案在方案一的基础上,将循环变量的实例化放到循环外,这样可以进一步减少相关循环变量的实例化次数,方案耗时情况如下:
变量实例化(次数)初始化(次数)比较(次数)自增(次数)
i111010
j11010 * 10010 * 100
k110 * 10010 * 100 * 100010 * 100 * 1000


4 解决结果
那么,提出的优化方案是否如我们分析的那样有了性能上的提升了呢?我们编写一些测试代码进行验证,数据更能说明我们的优化效果。
4.1 测试代码
Java代码 复制代码 收藏代码
  1. public static void testFunction(int i, int j, int k) {  
  2.         System.out.print("");   // 注:该方法不影响整体优化,这里只有简单输出  
  3.     }  
  4.   
  5.     public static void testA() {  
  6.         long start = System.nanoTime();  
  7.         for (int i = 0; i < 1000; i++)  
  8.             for (int j = 0; j < 100; j++)  
  9.                 for (int k = 0; k < 10; k++)  
  10.                     testFunction(i, j, k);  
  11.         System.out.println("testA time>>" + (System.nanoTime() - start));  
  12.     }  
  13.   
  14.     public static void testB() {  
  15.         long start = System.nanoTime();  
  16.         for (int i = 0; i < 10; i++)  
  17.             for (int j = 0; j < 100; j++)  
  18.                 for (int k = 0; k < 1000; k++)  
  19.                     testFunction(k, j, i);  
  20.         System.out.println("testB time>>" + (System.nanoTime() - start));  
  21.     }  
  22.   
  23.     public static void testC() {  
  24.         long start = System.nanoTime();  
  25.         int i;  
  26.         int j;  
  27.         int k;  
  28.         for (i = 0; i < 10; i++)  
  29.             for (j = 0; j < 100; j++)  
  30.                 for (k = 0; k < 1000; k++)  
  31.                     testFunction(k, j, i);  
  32.         System.out.println("testC time>>" + (System.nanoTime() - start));  
  33. }  
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组
原方案171846271173250166173910870173199875173725328
方案一168839312168466660168372616168310190168041251
方案二168001838169141906168230655169421766168240748

从上面的测试结果来看,优化后的方案明显性能优于原方案,达到了优化的效果。但优化方案二并没有如我们预期的优于方案一,其中第2、4、5组的数据更是比方案一差,怀疑可能是循环次数太少,以及测试环境相关因素影响下出现的结果。

3、重新调整循环变量i、j、k循环次数分别为20、200、2000,进行5组测试,测试结果如下:
 第1组第2组第3组第4组第5组
原方案13553972031358978176135812828113501936821354786598
方案一13434827041348410388134397803713479191561340697793
方案二13424275281343897887134266246213421240481336266453

从上面的测试结果来看,优化后的方案基本符合我们的预期结果。

5 总结
从案例分析和解决过程中的三个表的分析可知,优化方案一和优化方案二的性能都比原代码的性能好,其中优化方案二的性能是最好的。在嵌套For循环中,将循环次数多的循环放在内侧,循环次数少的循环放在外侧,其性能会提高;减少循环变量的实例化,其性能也会提高。从测试数据可知,对于两种优化方案,如果在循环次数较少的情况下,其运行效果区别不大;但在循环次数较多的情况下,其效果就比较明显了。

6 参考资料
[1] http://www.javaeye.com/topic/762312
[2] http://www.javaeye.com/topic/632481

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/452271.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker-ce安装

1、安装 sudo yum -y install docker 2、加入开机自启systemctl enable docker转载于:https://www.cnblogs.com/runnerjack/p/8618524.html

python-study-17

复习 上节课复习1、什么是模块模块是一系列功能的集合体2、为何用模块拿来&#xff08;内置或第三方的模块&#xff09;主义&#xff0c;提升开发效率自定义模块可以让程序的各部分组件重用模块内的功能3、如何用模块大前提&#xff1a;模块是被执行文件导入使用&#xff0c;模…

面向对象方法学的优点

1.与人类习惯的思维方法一致面向对象的软件技术以对象为核心&#xff0c;用这种技术开发出的软件系统由对象组成。对象是由描述内部状态表示静态属性的数据&#xff0c;以及可以对这些数据施加的操作(对象的动态行为)&#xff0c;封装在一起所构成的统一体。面向对象的设计方法…

如何学好C语言

我相信&#xff0c;这可能是很多朋友的问题&#xff0c;我以前也有这样的感觉&#xff0c;编程编到一定的时候&#xff0c;发现能力到了瓶颈&#xff0c;既不深&#xff0c;也不扎实&#xff0c;半吊子。比如&#xff1a;你长期地使用Java和.NET &#xff0c;这些有虚拟机的语言…

学成在线--5.CMS页面管理开发(修改页面)

文章目录1.修改页面流程1&#xff09;前端逻辑2&#xff09;后端逻辑2.修改页面接口定义3.后端开发--Dao4.后端开发--Service5.后端开发--Controller1&#xff09;根据id查询页面2&#xff09;保存页面信息6.前端开发--页面处理流程7.前端开发--编写page_edit.vue8.前端开发--配…

在树莓派上播放音频

https://blog.csdn.net/qinxiandiqi/article/details/39155593转载于:https://www.cnblogs.com/Baronboy/p/9206164.html

Map四种获取key和value值的方法,以及对map中的元素排序

2019独角兽企业重金招聘Python工程师标准>>> 获取map的值主要有四种方法&#xff0c;这四种方法又分为两类: 一类是调用map.keySet()方法来获取key和value的值&#xff0c; 另一类则是通过map.entrySet()方法来取值&#xff0c; 两者的区别在于&#xff0c;前者主要…

配置Oracle Instant Client环境

1.配置Oracle Instant Client环境 到Oracle官网下载Oracle Instant Client&#xff0c;注意选择x86平台&#xff0c;Toad只认32位的Oracle Instant Client。至于版本号&#xff0c;没有特别要求&#xff0c;版本向下兼容。 桌面上&#xff0c;右键点“我的电脑”&#xff0c;选…

学成在线--6.CMS页面管理开发(删除页面)

文章目录0.删除用户逻辑1.删除页面接口定义2.后端开发--Dao3.后端开发--Service4.后端开发--controller5.前端开发--page_list.vue添加删除按钮6.前端开发--page_list.vue编写删除事件7.后端开发--Api方法定义Api方法0.删除用户逻辑 1&#xff09;前端逻辑 &#xff08;1&…

诺基亚是“不跟随”还是跟不上?

在Android和iPhone为主流的环境下&#xff0c;诺基亚用“不跟随”的口号表明自己欲保持个性&#xff0c;但是否也意味着其固步自封&#xff0c;跟不上时代&#xff1f; 5年市值缩水超900亿欧元&#xff0c;全球业绩连续4个季度亏损&#xff0c;更为可怕的是&#xff0c;被视为…

HTTP 协议(详解)

HTTP协议简介&#xff1a;HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写&#xff0c;是用于万维网&#xff08;www.world wide web&#xff09;服务器与本地浏览器之间传输文本的传输协议。 http请求协议与相应协议HTTP协议包含浏览器发送数据到服务器需要遵循…

对象的特点

对象有如下一些基本特点。(1) 以数据为中心。操作围绕对其数据所需要做的处理来设置&#xff0c;不设置与这些数据无关的操作&#xff0c;而且操作的结果往往与当时所处的状态 (数据的值)有关。 (2) 对象是主动的。它是进行处理的主体。不能从外部直接加工它的私有数据&a…

React Native集成Redux框架讲解与应用

学过React Native的都知道&#xff0c;RN的UI是根据相应组件的state进行render的&#xff0c;而页面又是由大大小小的组件构成&#xff0c;导致每个组件都必须维护自身的一套状态&#xff0c;因此当页面复杂化的时候&#xff0c;管理state会相当吃力的。而redux提供了一套机制来…

【笔试记录】2021/3/10阿里

阿里20210310春招笔试记录-Python解题 第一题 问题描述&#xff1a; 小偷从出发点按指定方向出发&#xff0c;除非遇到墙或超出城市必须转方向&#xff0c;不然只能直走。城市大小m*n。输入描述&#xff1a; 1. 第1行&#xff0c;三个数字m n k&#xff1b;m*n表示城市大小&…

Spring mvc中@RequestMapping 6个基本用法小结

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 小结下spring mvc中的RequestMapping的用法。 1&#xff09;最基本的&#xff0c;方法级别上应用&#xff0c;例如&#xff1a; …

学成在线--7.CMS页面管理开发(异常处理)

文章目录1.异常处理的问题分析2.异常处理流程3.可预知异常处理1.自定义异常类2.异常抛出类3.异常捕获类4.异常处理测试1&#xff09;定义错误代码2&#xff09;异常处理测试4.不可预知异常处理1.定义异常捕获方法1&#xff09;异常抛出测试2&#xff09;异常捕获方法1.异常处理…

函数重载与运算符重载

有两种重载&#xff1a;函数重载是指在同一作用域内的若干个参数特征不同的函数可以使用相同的函数名字&#xff1b;运算符重载是指同一个运算符可以施加于不同类型的操作数上面。就是对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型…

Django(6)

为什么不用_set related_name和related_query_name的区别related_name将成为相关对象的属性&#xff0c;允许您使用外键对模型进行“倒退”。例如&#xff0c;如果ModelA有像下面这样的字段&#xff0c;那么model_b ForeignKeyField(ModelB, related_namemodel_as)这将使您能够…

P5 RV1126编码测试Demo

目录 前言 01 测试Demo大致流程图 02 代码分析 2.1 VI设备初始化 2.2 使能通道 —— RK_MPI_VI_EnableChn 2.3 VI 和 VENC绑定 2.4 创建 编码线程 前言 从本章开始我们将要学习嵌入式音视频的学习了 &#xff0c;使用的瑞芯微的开发板 &#x1f3ac; 个人主页&#xff1a…

MP算法和OMP算法及其思想

主要介绍MP(Matching Pursuits)算法和OMP(Orthogonal Matching Pursuit)算法[1]&#xff0c;这两个算法虽然在90年代初就提出来了&#xff0c;但作为经典的算法&#xff0c;国内文献(可能有我没有搜索到)都仅描述了算法步骤和简单的应用&#xff0c;并未对其进行详尽的分析&…