前面的几篇博客中已经介绍了八大排序算法,在这里最后再进行总结一下,从算法思想、空间复杂度、时间复杂度和稳定性进行总结:
一、插入排序
1.直接插入排序
直接插入排序的过程可以分为三步:一是找到待排序元素应该插入的位置;二是移动后面的元素,为待排序元素插入腾出空间;最后是插入待排序元素。
改进后的直接插入排序是从后往前比较,这样就可以边移位边找待排序元素插入的位置。
2.希尔排序
希尔排序是在直接插入排序的基础上发展而来,只不过每次排序的元素都间隔一定的距离,而且最后一趟就是直接插入排序。
二、交换排序
1.冒泡排序
冒泡排序是最简单也是最容易理解的排序方法。N个数最多需要N-1趟排序,每一趟排序的过程中相邻两个元素进行比较,将两个元素中值较大的交换到下标大的位置,一直交换到最后一个元素,这样一趟排序过程结束后最大的元素就“冒”到最后面的位置。同理冒出其他元素即可。
对于冒泡排序有一种改进的方法,因为冒泡排序如果有相邻元素交换说明当前序列是无序的;反之如果在一趟冒泡过程中,没有发生过两个相邻元素之间的交换,则说明已经有序,此时没有必要再进行下一趟冒泡排序,这个可以通过设置一个标志变量来实现。
2.快速排序
快速排序有两种实现方法,一种是递归的,另一种是非递归的。但是两者都有一个共同的过程–划分。
先说明划分的过程是如何进行的,一般选第一个元素作为基准值进行划分,并用一个临时变量存起来,首先从右往左找第一个比基准值小的值,并交换到基准值的位置;然后从左往右找第一个比基准值大的元素,并交换到上一个比基准值小的元素的位置,就这样左右交替交换,直到前后两个指针相遇,此时一趟划分过程结束,也找到了基准值在整个序列中的位置。
递归版快速排序和非递归版快速排序的本质是一样的,非递归版快速排序只是用栈来模拟了递归的过程。
三、选择排序
1.直接选择排序
直接选择排序也好理解,每遍历一趟数组中的元素,找到数组中未排好序的元素中值最大或者值最小的元素,并将其交换到最前面或者最后面,这样N个数经过N-1趟排序以后就排好序了。
2.堆排序
堆排序感觉上是利用了二叉树,但是实际上只是利用二叉树的理论,和二叉树没有太大的关系。主要有两点要会计算:一是从子节点的序号推算父节点的序号,如果子节点序号为N,则父节点序号为(N-1)/2;二是从父节点的序号推算子节点的序号,如果父节点的序号为N,则左孩子节点序号为2*N+1, 右孩子节点序号为2 *N+2。
清楚了父节点和子节点之间序号的推算以后,下面就比较简单了。首先我们要把整个序列的所有非叶子节点进行调整为大根堆或者小根堆,调整完以后根节点要么是值最大的节点(大根堆),要么是值最小的节点(小根堆),然后将根节点和最后一个节点进行交换,交换完以后就相当于排好了一个元素。此时整棵树中除了根节点以外,其他非叶子结点都是大根堆,所以这个时候只需要将根节点调整为大根堆即可,而且需要注意的一点是之前交换过的根节点不再参与后面的调整。
四、归并排序
归并排序就是将两个有序的部分合并成一个有序的部分。只是这个有序部分的元素个数一般都是按照指数形式增长,即2^n。
五、基数排序
基数排序也称为桶排序,是唯一一种不需要比较元素而排序的算法。基数排序的过程很好理解,但是其代码实现比较复杂,主要是因为需要做很多辅助性工作。基本思想是在排序过程中,对于一个数而言,先排权值比较小的位数,如三位数字序列{195,683, 756},先按个位排序,则为{683,195,756};再按十位排序,则为{756, 683,195};最后按百位进行排序,则为{195, 683, 756}。
六、各种排序算法分析