排序算法的时间复杂度和空间复杂度:
选择排序、插入排序、冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1);
堆排序的时间复杂度为O(nlogn),空间复杂度为O(1);
希尔排序的时间复杂度为O(n^2)~O(n),平均O(n^1.5);空间复杂度为O(1);
注意快速排序,时间复杂度最优是O(nlogn),最优情况是每次选取的分界值都恰好平分数组
T[n] =2T[n/2] + f(n);T[n/2];
最差情况时间复杂度是O(n^2),即每次选取的分界值都是数组的最小值或者最大值,于是快速排序退化为冒泡排序:T[n] = n * (n-1) = n^2 + n;
对于空间复杂度注意:额外的数据结构会占用空间复杂度,例如使用辅助的数组,栈,集合会占用空间复杂度,此外使用递归也会占用空间复杂度,希尔排序中对于步长feet的调整可以使用递归,但是递归次数很小,将其忽略;对于快速排序,没有使用额外的数据结构,都是进行就地排序来进行就地快速排序,使用的空间复杂度是O(1),此外真正消耗空间的是递归的调用,因为每次递归都要保存一些数据,于是快速排序的空间复杂度也与递归调用相关,最优情况下:每次分界值都平分数组,递归抵用的次数是logn,于是最优空间复杂度是O(logn);最差情况是分界值每次都在最大或者最小元素,于是退化为冒泡排序,每次递归都只排列一个元素,于是递归调用次数是n次,于是空间复杂度是O(n).
详见http://blog.csdn.net/yuzhihui_no1/article/details/44198701
对于不基于比较的排序算法:奇数排序和基数排序,时间复杂度为O(n),空间复杂度为O(m),其中m是通排序中通的数目。(桶可以通过哈希表数组来实现)
排序算法的稳定性:
何为算法稳定性,所谓的稳定性是对序列中相同的元素而言的,待排序数组中如果存在相同的元素,在排序之前这些相同的元素有一个相对的顺序(不要认为相同的元素没有区别,排序只是对元素的关键字进行进行排序,其实关键字所对应的元素对象是不同的,例如对员工按照年龄进行排序,通为20岁的员工,如果算法不稳定,那么有时可能顺序是小明、小红;有时可能是小红、小明),如果排序后这些相同的元素之间的相对位置发生了变化,那么说明这个算法是不稳定的,如果不发生变化就是稳定的。即如果一个算法是稳定的,那么不管排序多少次,这些相同元素之间的相对顺序都是不变的,如果不稳定那么排序时顺序可能会每次都不一样。即研究稳定性只需要研究相同元素之间顺序是否稳定即可。
快速排序:不稳定。因为在对45331进行分界时,中间元素时3,于是第二个3会被调整到左边部分,显然2个3的相对顺序发生了变化。
堆排序:不稳定。对大根堆的调整会交换相同的2个值,于是造成相同元素相对位置的变化。
归并排序:稳定。对于2个子数组进行合并时,如果有相同的元素,总是先将左边数组元素放入辅助数组,再将右边数组放入辅助元素,于是这些相同的元素之间不会错位。
希尔排序:不稳定。对于每一个步长的插入排序其实是稳定的,但是在不同步长之间,是不稳定的,例如745633,步长为2时,第一个3和5交换,第二个3和6交换得到743356,33顺序不变,当步长为3时,第一个3不变,第二个3与7交换到了第二个3的前面,于是2个3的相对顺序发生了变化。或者5115当步长为2时第二个1与第一个5进行交换,于是第二个1换到了第二个1的前面。
即在高效的算法中,只有归并排序是稳定的。
选择排序:不稳定。总是选择当前数组的最小值交换到前面有序序列的最后一个值。例如对于2221,此时最小的是1,其要与第一个2进行交换,得到于是第一个2调到了最后,显然3个2之间的顺序发生了变化。
插入排序:稳定。总是将当前元素与前面的每一个元素逐步比较逐个进行交换,于是相同元素之间的相对顺序也是不变的。
冒泡排序:稳定。因为每次都是从头开始对相邻的元素进行比较,将较大的元素逐步向后面交换移动,即总是对相邻的2个元素进行交换,于是不会改变相同元素的相对顺序。
对于时间复杂度为O(n^2)的排序算法,选择排序是不稳定的,插入排序和冒泡排序是稳定的。
即进行大跨度交换的算法,例如选择排序是不稳定的,进行逐步相邻元素交换的算法是稳定的,例如插入排序和冒泡排序。
对于不基于比较的排序算法,桶排序(基数排序、计数排序),时间复杂度是O(n),空间复杂度是O(n),他们都是稳定的算法。
补充说明一:排序算法无绝对优劣
通常不能随便说那种排序算法好。这个和排序的元素相关。对于排序元素数据范围较小,且不是均匀分布的情况,例如年龄,身高,数据范围都是有限的狭窄的,此时桶不需要很多,可以考虑使用计数排序。对于均匀分布的整数,由于同需要很多,且每个桶中只有1个元素,例如收入排序的分布很广,因此需要很多桶,于是计数排序就不合适了。一般认为数据范围都是均匀分布的,于是一般其实都不采用桶排序,除非面试时特殊要求。
补充说明二:为什么叫快速排序
快速排序的时间复杂度是O(nlogn)~O(n^2),并不比堆排序O(nlogn)和归并排序O(nlogn)更优,在快排最优情况下,他的渐进复杂度和堆排序和归并排序是相同的。只是最优情况下,快排的常量系数比堆排序和归并排序更加小而已。
补充说明三:工程上的排序
例如对于Java类库中的排序算法(Arrays.sort()使用的实现时快速排序),他并不是一种算法而是多种算法的综合体,即是综合排序。当数组较小时,选择常量系数较小的插入排序可以更快,因为数量不大,因此系数小优势比复杂度小更有效。当数组较大时,选择复杂度较低的快速排序或者其他O(nlogn)的排序。