选择排序法
对数组 arr[n]进行排序
arr[0...i]已排序, arr[i...n]未排序, 循环不变量
复杂度:
/**
* 复杂度为 O(n^2)
*
* (1 + n) * n n^2 n
* ----------- = --- + ---
* 2 2 2
*/
插入排序法
对于有序数组,插入排序的复杂度是O(n)
整体而言,插入排序的复杂度依然是O(n^2)
待排序的数组越有序,复杂度越低
选择排序的复杂度永远是O(n^2)
动态数组的复杂度分析
| 添加操作 | O(n) | 最坏情况 |
|---|---|---|
| addLast(e) | O(1) | O(1) |
| addFirst(e) | O(n) | |
| add(index, e) | O(n) | |
| resize() | O(n) |
resize()的复杂度分析:(因为resize()操作不会每次都会出现)
首先执行n次addLast操作,在执行扩容操作,执行n次addLast操作,在执行一次addLast(n + 1),
出发resize操作,总共执行了2n + 1次操作,所以平均每次addLast操作 执行了2次基本操作。
addLast的均摊复杂度为O(1)
这种计算方式称为: 均摊复杂度 amortized time complexity
复杂度震荡
在某些极特殊情况下,当add第n个元素会出现扩容操作,当delete第n个元素会出现缩容操作,使得每次操作的复杂度都为O(n),这种情况称为复杂度震荡。
合理设计算法可以避免复杂度震荡的出现,比如当size == capacity时,执行扩容操作,但是当size《= capacity/4时,在执行缩容操作。
栈的复杂度分析:
| ArrayStack | 复杂度 | 复杂度类型 |
|---|---|---|
| void push(E) | O(1) | 均摊 |
| E pop() | O(1) | 均摊 |
| E peek() | O(1) | |
| int getSize() | O(1) | |
| boolean isEmpty() | O(1) |
数组队列的复杂度分析
| ArrayQueue | 复杂度 | 复杂度类型 |
|---|---|---|
| void enqueue(E) | O(1) | 均摊 |
| E dequeue() | O(n) | |
| E getFront() | O(1) | |
| int getSize() | O(1) | |
| boolean isEmpty() | O(1) |
循环队列的复杂度分析
| LoopQueue | 复杂度 | 复杂度类型 |
|---|---|---|
| void enqueue(E) | O(1) | 均摊 |
| E dequeue() | O(1) | 均摊 |
| E getFront() | O(1) | |
| int getSize() | O(1) | |
| boolean isEmpty() | O(1) |