基础排序算法

204 阅读2分钟

选择排序法

对数组 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)