Java 算法复杂度:从开始迭代数组是否与从结束迭代数组相同?
在一次采访中,我被问及以下问题:Java 算法复杂度:从开始迭代数组是否与从结束迭代数组相同?,java,algorithm,Java,Algorithm,在一次采访中,我被问及以下问题: public class Main { public static void main(String[] args) { // TODO Auto-generated method stub int [] array = new int [10000]; for (int i = 0; i < array.length; i++) { // do calculations } for (i
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
int [] array = new int [10000];
for (int i = 0; i < array.length; i++) {
// do calculations
}
for (int x = array.length-1; x >= 0; x--) {
// do calculations
}
}
公共类主{
公共静态void main(字符串[]args){
//TODO自动生成的方法存根
int[]数组=新int[10000];
for(int i=0;i=0;x--){
//计算
}
}
}
从末尾还是从开头迭代数组是一样的?根据我的理解,这是相同的,因为复杂性是恒定的,即O(1)?我说得对吗
还有人问我,与java中的其他集合(例如LinkedList)相比,ArrayList的复杂性如何
谢谢。对于一个数组,这两种情况下都是O(n),因为有n次迭代,每一步都需要O(1)(假设循环中的计算需要O(1))。特别是,获取长度或大小通常是数组或ArrayList的O(1)操作
从末尾进行迭代的一个典型用例是删除循环中的元素(否则可能需要更复杂的计算,以避免跳过元素或在末尾之外进行迭代)
对于链表,第一个循环通常是O(n²),因为确定链表的长度通常是一个O(n)操作,没有额外的缓存,并且每次检查退出条件时都会使用它但是,java.util.LinkedList显式跟踪长度,因此java中的链表的总长度为O(n)
如果使用计算中的索引访问链表中的元素,这将是一个O(n)操作,总共产生O(n²)。由于CPU预取特性,可能存在差异 根据计算理论,两个方向的循环之间没有区别。但是,根据运行代码的CPU所使用的预取器的类型,在实践中会有一些差异 例如,Sandy Bridge Intel处理器有一个仅用于数据的预取器(而指令可以在两个方向上预取)。这将有助于从一开始就进行迭代(因为将来的内存位置会预取到一级缓存中),而从最后进行迭代将导致很少甚至没有预取,因此会有更多对RAM的访问,这比访问任何CPU缓存都慢得多 这里有一个关于前向和后向预取的更详细的讨论 从末尾还是从开头迭代数组是一样的?根据我的理解,这是相同的,因为复杂性是恒定的,即O(1)?我说得对吗 从理论上讲,是的,从结尾和开始迭代数组是一样的。
时间复杂度为O(10000),该时间复杂度是恒定的,因此假设循环体具有恒定的时间复杂度。但值得一提的是,常数10000可以提升为变量,称之为
N
,然后可以说时间复杂度为O(N)
还有人问我,与java中的其他集合(例如LinkedList)相比,ArrayList的复杂性如何
在这里,您可以找到ArrayList和LinkedList时间复杂度之间的比较。有趣的方法有add
、remove
和get
。
此外,LinkedList中的数据不是连续存储的。但是,ArrayList中的数据是连续存储的,而且ArrayList使用的空间比LinkedList少
祝你好运 开始和开始之间的区别是什么?如果do计算部分是O(1),那么复杂度显然是O(n),n是数组中的元素数。访问一个数组元素需要固定的时间O(1),并且您有n个数组元素。如果您必须遍历整个列表,这并不重要。如果在您的计算中,您有很好的机会退出(通过中断),则必须选择最可能的解决方案。CPU预取特性可能会有所不同。
array.length
在第一个示例中调用10000次,在第二个示例中调用一次,至少在理论上是这样。它可能会被优化。获取LinkedList的大小是O(1)。列表有一个保持其大小的字段。它不会反复去了解它。然而,在LinkedList中,Doing list.get(i)的开销非常大,因为它需要迭代。这就是为什么应该使用迭代器遍历列表,而不是通过元素的索引访问元素。