这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战。
二次问题
假设你正在写一个JavaScript应用,它要检查数组中是否有重复值。
首先想到的做法可能是类似下面的嵌套for循环。
function hasDuplicateValue(array){
for(var i=0; i < array.length; i++){
for(var j=0; j < array.length; j++){
if(i !== j && array[i] == array[j]){
return true
}
}
}
return false
}
此函数用var i来遍历数组元素。每当i指向下一元素时,我们又发起第二个for循环,用var j来遍历数组元素,并在这第二个循环过程中检查i和j两个位置的值是否相同。若相同,则表示数组有重复值。如果两层循环都没遇到重复值,则最终返回false,以示数组没有重复值。
虽然可以这么做,但它的效率高吗?既然我们学过一点大记法,那么就试试用大
来评价一下这个函数吧。
记住,大测量的是步数与数据量的关系。因此,我们要测的就是:给hasDuplicateValue函数传入一个含有
个元素的数组,最坏情况下需要多少步才能完成。
要回答这个问题,得先搞清楚这个函数有哪些步骤,以及其最坏情况是什么。
该函数只有一种步骤,就是比较。它重复地比较i和j所指的值,看它们是否相等,以判断数组有没有重复值。最坏的情况就是没有重复,这将使我们跑遍内外两层循环,比较完所有i、j组合,才返回false。
由此可知个元素要比较
次。因为外层循环需要
步来遍历数组,而这里的每1步,又会发起内层循环去用
步遍历数组。所以
步乘以
步等于
步,此函数为一个
算法。
想要证明的话,还可以往函数里添加一些跟踪步数的代码。
function hasDuplicateValue(array){
var steps=0;
for(var i=0; i < array.length; i++){
for(var j=0; j < array.length; j++){
steps++;
if(i !== j && array[i] == array[j]){
return true;
}
}
}
console.log(steps);
return false;
}
执行hasDuplicateValue([1,2,3])的话,你会看到Javascript console输出9,表示9次比较。3个元素需要9次比较,这个函数是的经典例子。
毫无疑问,嵌套循环算法的效率就是。一旦看到嵌套循环,你就应该马上想到
。
虽然hasDuplicateValue是我们目前唯一想到的解决方法,但在确定采用之前,应意识到它的意味着低效。当遇到低效的算法时,我们都应该花些时间思考下有没有更快的做法。特别是当数据量巨大的时候,优化不足的应用甚至可能会突然挂掉。尽管这可能已经是最佳方案,但你还是要确认一下。