Java 如何计算以下代码段的复杂性?

Java 如何计算以下代码段的复杂性?,java,algorithm,Java,Algorithm,我是一个有着大O符号和算法复杂性的初学者。我试图计算以下两个java方法的复杂性,这两个方法都做相同的事情。但是一个会稍微快一点 ArrayList<Person> filter1(Person x, ArrayList<Person> people){ ArrayList<Person> friends = new ArrayList<Person(); for (Person y: people) friends.add(y); for

我是一个有着大O符号和算法复杂性的初学者。我试图计算以下两个java方法的复杂性,这两个方法都做相同的事情。但是一个会稍微快一点

ArrayList<Person> filter1(Person x, ArrayList<Person> people){
  ArrayList<Person> friends = new ArrayList<Person();
  for (Person y: people) friends.add(y);
  for (Person y: people) if (!x.knows(y)) friends.remove(y);
  return friends;
}

ArrayList<Person> filter2(Person x, ArrayList<Person> people){
  ArrayList<Person> friends = new ArrayList<Person();
  for (Person y: people) if (x.knows(y)) friends.add(y);
  return friends;
}
ArrayList过滤器1(人员x,ArrayList人员){

ArrayList friends=new ArrayListBig-O只关心曲线的一般形状,而不关心应用于曲线的系数

因此,如果计算复杂度
O(n+n)
,则应将其简化为
O(2n)
,然后删除
O(n)
的系数

你的两个例子都是在与人数成线性关系的时间内运行的。从大O的角度来看,这两个过滤器是等价的

说filter1需要O(n+n)时间(这可以简化为O(n)吗?)而filter2需要O(n)时间是正确的吗

O(n+n)确实可以简化为O(n),但是
filter()
不是O(n)

首先,引用
ArrayList
中关于时间复杂性的一段话(重点是我的):

size、isEmpty、get、set、iterator和listIterator操作以固定时间运行。add操作以摊销固定时间运行,也就是说,添加n个元素需要O(n)个时间。所有其他操作以线性时间运行(粗略地说)

让我们分析
filter1()
的代码:

所以
filter2()
是O(n)

现在,为了澄清两个功能相同但运行时间不同的函数的混淆,考虑以下函数:

  • h1(n)=n=O(n)
  • h2(n)=1000·n=O(n)
h1(n)和h2(n)都是O(n)的事实并不意味着它们的运行速度必须一样快。事实上,h2(n)的运行时间是h1(n)的1000倍。具有O(n)时间复杂性只是意味着这两个函数都随着n值的增加而线性增加

以大O定义为例:

f(n)=O(g(n))意味着c·g(n)是f(n)的上界,因此存在一些常数c,使得f(n)总是≤ c·g(n),对于足够大的n

为了将定义应用于h1(n),考虑到f(n)=n和g(n)=n,我们需要找到一个常数c,使得对于所有足够大的n,f(n)≤ c·g(n)。在这种情况下,n≤ c·n表示任何c≥ 我们证明了h1(n)=O(n)


现在对于h2(n),考虑到f(n)=1000·n和g(n)=n,我们需要找到一个常数c,使得对于所有足够大的n,f(n)≤ c·g(n)。在这种情况下,1000·n≤ c·n表示任何c≥ 1000,所以我们证明h2(n)=O(n)。

你说得对,
O(n+n)=O(2n)
可以简化为
O(n)

对于
filter1()

每个for循环都需要
O(n)
,因此
O(n)+O(n)=O(n)
,但根据这一点,
好友。remove
也需要
O(n)
,因为它必须遍历整个列表才能找到项目并将其删除。然而,
好友.add
需要O(1)才能添加项目

所以,复杂度计算是这样的

(O(n) * O(1)) + (O(n) * O(n))
  = O(n) + O(n^2)
  = O(n^2)

对于
filter2()
它是
(O(n)*O(1))=O(n)

第一个实际上在
O(n^2)
中,因为
add
插入
y
,所以
remove
将遍历整个列表。如果你想让它成为
O(n)
,请转到
friends.remove(friends.size()-1)
。首先要做的是(n+n)是O(n)。现在,保持简单…在filter1中,您首先添加然后删除(添加和删除需要时间),但在filter2中,您是根据某些条件直接添加的,所以您不认为这会运行得更快吗?您假设两种算法都处于
O(n)中
基于一个错误的假设,即循环中的所有操作都在
O(1)
范围内。请参阅关于ArrayList.remove()的其他答案好的调用,我错过了。
List<Person> filter2(Person x, List<Person> people){
    List<Person> friends = new ArrayList<>();
    for (Person y: people) {        // O(n)
        if (x.knows(y)) {
            friends.add(y);         // amortized constant time
        }
    }
   return friends;
}
(O(n) * O(1)) + (O(n) * O(n))
  = O(n) + O(n^2)
  = O(n^2)