我开始学习数据结构和算法,但是遇到了一个问题。这是我正在测试的功能:
def create_list_with_concat(n):
l = []
for i in range(n):
l = l + [i]
这是我的思考过程:
我知道concat运算符是O(k)
,其中k
是要添加到原始列表中的列表的大小。由于在这种情况下k
的大小始终为1
,因为我们一次添加了一个字符列表,因此concat操作需要执行1
步骤。由于循环迭代n
次,因此该算法将执行n
个步骤-每次迭代执行1
个步骤。因此,该算法的时间复杂度为O(n)
。该算法的实际执行时间类似于T(n) = dn
,其中d
是执行级联所花费的时间。对于这样的功能,我希望以下内容是正确的:当您将输入大小增加10倍时,由于以下原因,输出(执行时间)将增加10倍:
(x, dx) --> (10x, 10dx) --> 10dx/dx = 10
但是,当我实际测试算法的实际值并计时执行时间时,这似乎没有发生。相反,当我将输入大小增加10倍时,输出(执行时间)将增加100倍,而当我将输入大小增加100倍时,输出将增加10000倍。这些输出建议一个二次时间函数和O(n squared)
。
这是我的完整代码:
import timeit
def create_list_with_concat(n):
l = []
for i in range(n):
l = l + [i]
t1 = timeit.Timer("create_list_with_concat(100)", "from __main__ import
create_list_with_concat")
print("concat ",t1.timeit(number=1)*1000, "milliseconds")
t1 = timeit.Timer("create_list_with_concat(1000)", "from __main__
import create_list_with_concat")
print("concat ",t1.timeit(number=1)*1000, "milliseconds")
# OUTPUT
# concat 0.05283101927489042 milliseconds
# concat 2.8588240093085915 milliseconds
非常感谢您的帮助。
答案 0 :(得分:5)
时间复杂度不是O(N)
两个列表A和B的concat操作的时间复杂度为O(A + B)
。这是因为您不是要添加到一个列表中,而是要创建一个全新的列表,并使用A和B中的元素填充它,这需要您遍历两个列表。
因此,进行l = l + [i]
的操作是O(len(l))
,而您需要进行N
的操作N
的步骤,导致总体复杂度为O(N^2)
您将concat与append
或extend
函数混淆了,该函数不会创建新列表而是将其添加到原始列表中。如果使用这些功能,则时间复杂度的确为O(N)
附加说明:
符号l = l + [i]
可能会造成混淆,因为从直观上看,[i]
似乎只是被添加到现有的l
中。这不是真的!
l + [i]
建立一个全新的列表,然后l
指向该列表。
另一方面,l += [i]
修改了原始列表,其行为类似于extend
答案 1 :(得分:3)
这是我的思考过程:我知道concat运算符是 O(k),其中 k 是要添加到原始列表中的列表的大小。由于在这种情况下 k 的大小始终为1,因为我们一次添加了一个字符列表,所以concat操作需要1步。
此假设为不正确。如果您写:
l + [i]
您构造了一个新列表,该列表将包含 m + 1 个元素,其中{em> m 是l
中元素的数量,前提是已实现列表像数组一样,我们知道构造这样的列表将花费 O(m)时间。然后,将 new 列表分配给l
。
所以这意味着步骤总数为:
n
---
\ 2
/ O(m) = O(n )
---
m=0
所以时间复杂度是 O(n 2 )。
不过,对于l += [i]
和{{1,您都可以使用l.append(i)
或什至更快的l += [i]
来提高性能,其中摊销成本是}} O(1),因此算法为 O(n),但是l.append(i)
可能会更快一些,因为我们节省了构造一个新列表等。
答案 2 :(得分:2)
Void My_func(Some_struct*** array)
{ //Code}
使列表变异和创建新列表之间的复杂度有所不同。