i=1; while (i <= n) { i = i * 2; }
实际效果:java
2^{0} * 2^{1} * 2^{2} ··· 2^{k} ··· 2^{x}= n
经过 2x=n 求解 x 。
x=log2n,因此,这段代码的时间复杂度就是O (log2n)。数组
无论底数是几,全部对数阶的时间复杂度都记为
O (logn)。由于
O (log3n) = O(C * log2n),使用大O标记复杂度的时候,能够忽略系数,因此赞成表示为O (logn)。数据结构
好比,归并排序、快速排序的时间复杂度都是 O (nlogn)。code
int cal(int m, int n) { int sum_1 = 0; int i = 1; for (; i < m; ++i) { sum_1 = sum_1 + i; } int sum_2 = 0; int j = 1; for (; j < n; ++j) { sum_2 = sum_2 + j; } return sum_1 + sum_2; }
其中m和n是表示两个数据规模,没法事先评估m和n哪一个大,因此不能随意省略,故,上面代码的时间复杂度就是 O (m+n)。排序
void print(int n) { int i = 0; int [ ] a = new int[n]; for (i; i <n; ++i) { a[i] = i * i; } for (i = n-1; i >= 0; --i) { print out a[i] } }
第2行申请一个空间存储变量i,能够忽略,和n无关。
第三行申请了大小为n的int类型数组,除此以外,无更多空间占用。故复杂度为O(n)。class
大部分状况下,没必要区分最好、最坏、平均状况时间复杂度三种状况。变量
// array 表示一个长度为 n 的数组 // 代码中的 array.length 就等于 n //这段代码仅仅是王争给的例子,没什么特殊实际意义。 int[] array = new int[n]; int count = 0; void insert(int val) { if (count == array.length) { int sum = 0; for (int i = 0; i < array.length; ++i) { sum = sum + array[i]; } array[0] = sum; count = 1; } array[count] = val; ++count; }
咱们仍是继续看在数组中插入数据的这个例子。每一次 O (n) 的插入操做,都会跟着 n-1 次 O (1) 的插入操做,因此把耗时多的那次操做均摊到接下来的 n-1 次耗时少的操做上,均摊下来,这一组连续的操做的均摊时间复杂度就是 O (1)。这就是均摊分析的大体思路。方法
对一个数据结构进行一组连续操做中,大部分状况下时间复杂度都很低,只有个别状况下时间复杂度比较高,并且这些操做之间存在先后连贯的时序关系,这个时候,咱们就能够将这一组操做放在一起分析,看是否能将较高时间复杂度那次操做的耗时,平摊到其余那些时间复杂度比较低的操做上。并且,在可以应用均摊时间复杂度分析的场合,通常均摊时间复杂度就等于最好状况时间复杂度。数据
均摊时间复杂度就是一种特殊的平均时间复杂度,不必花太多精力去区分它们。最应该掌握的是它的分析方法,摊还分析。至于分析出来的结果是叫平均仍是叫均摊,这只是个说法,并不重要。时间
对于可反复读写的存储空间,认为它空即为空。清空数组有时候并不须要置为0,或某个值。把下标指到第一个位置就能够。
留言体会:平均和平摊基本就是一个概念,平摊是特殊的平均。在分析时间复杂度是 O (1) 仍是 O (n) 的时候最简单就是凭感受,,,,,,,,出现 O (1) 的次数远大于出现 O (n) 出现的次数,那么平均平摊时间复杂度就是 O (1)。。。。