1.冒泡排序:
比较相邻的两个数,如果前一个数大于后一个数,就将这两个数换位置。每一次遍历都会将本次遍历最大的数冒泡到最后。为了将n个数排好序,需要n-1次遍历。如果某次遍历中,没有调整任何两个相邻的数的位置关系,说明此时数组已排好序,可以结束程序。
2.选择排序
第i轮遍历arr[0:n-i]选出最大的数,与arr[n-i]互换。
3.插入排序
数组的前面部分已经排好序,要把当前数字插入到前面已排好序的数组的相应位置。可能有人会有疑问为什么默认数组前面部分已排好序?是怎么排好序的?是因为当排序开始时,从第2个数字开始进行向前插入,此时当前数字索引为1,当前数字前面仅有一个数字,因此可以认为前面部分已经排好序,将这个数字插入到相应位置之后数组仍然是有序的。每次都将当前数字插入到对应的位置,因此每次插入之后前面的数组仍是排好序的。
4.shell排序
加了step的插入排序。分别以索引数为0,1,…step-1的元素为起点,将其看做不同的组,0、0+step,0+2_step,…,0+n_step为一组,1,1+step,1+2_step,…,1+n_step为一组依次分组,按照组为单位进行插入排序。各组都已经插入排序一轮过后,将step除以2向下取整,再进行分组并将各组分别进行插入排序,直到step为0。step的取值与性能直接相关,需要思考后取值。并且这里的分组仅仅是逻辑上分组,并没有开辟新的地址空间将其进行物理上的分组。
5.合并排序
举个例子:有 4312 32 29 66 78 31这个数组要用合并排序。先将相邻两数分为一组进行合并 43|1232|29 66|78 31 结果为1243 29 32 66 78 31
再将组的大小乘以二(1243|29 32) (66 78|31) 本次合并后结果为1229 32 43 31 66 78
再将组的大小乘以二1243 29 32 | 66 78 31 合并结果:1229 31 32 43 66 78
合并的过程中要开辟新的数组arr,建立两个指针i,j分别指向arr1与arr2,此时arr1与arr2都是排好序的,然后每次都将arr1[i]与arr2[j]较小的数加到arr中并将指针后移。最后哪个数组有剩余的数在追加到arr后面。
6.自然合并排序
合并排序的分组是死板的没有利用到数组中原本就是顺序的子序列。
如果数组为4356 79 12 33 90 66 将其分组为4356 79 | 12 33 90 | 66 再将相邻的,原本就是从小到大的顺序的数组进行合并,效果会更好。
7.基数排序(LSDleast significant digit first)
LSD中没有数值之间的比较。建立一个[10][]的二维数组arr。挑选出要排序数组中最大的数字,计算该数字的位数记为digitNum。将数组中的所有数字填充到digitNum位,位数不够的高位补0。然后遍历digitNum次,从低位开始。第i次遍历按照将数组中元素的第i位的数值,将元素num放到二维数组相应位置处,如果num第i位数值为n,则执行arr[n].push(num)的操作。每次遍历之后,将arr[0:9]各数组的元素依次取出,并且重新初始化二维数组。直到遍历到最高位为止,再取出的就是已经排好序的。
8.基数排序(MSDmost significant digit first)
从高位开始,依然没有数值之间的比较。将最初的元素序列按照各元素最高位的数值进行分组,将分组后,组中只有一个元素或者多个相等元素的组拼接到result数组中,而有多个不同元素的组再递归地向下分,取的位次依次减少。
9.快速排序
将数组头部的元素pivotNum作为一个基准,通过两个指针指向数组的头部和尾部,经过一次partition以后将pivotNum放在一个位置pivot,pivot前面的数小于pivotNum,后面的数大于pivotNum。为了防止最坏情况的发生,可以在数组中随机选出一个数来与数组头部元素换位置,来降低具体实例与最坏情况的关联性。
10.堆排序
将数组看做完全二叉树,因此节点i的左右子节点的索引分别为2i+1与2i+2。通过从根节点开始令小的值下沉,或者从最后的叶节点开始令大的值上浮的方法,将一个数组构造成一个大根堆。再将大根堆的头元素与尾元素换位置,这样就将当前最大值置换到了尾部。然后下次构建大根堆的时候,将刚置换过的尾部元素刨除在外不做为节点。