1. 冒泡排序
比较相邻的元素,如果前一个比后一个大,就把它们两个调换位置。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会 是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
1 |
|
2. 选择排序
工作原理:
- 在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
- 第二次遍历n-2个数,找到最小的数值与第二个元素交换;
- 第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。3.第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。
与冒泡排序的区别:
冒泡排序通过依次交换相邻两个顺序不合法的元素位置,从而将当前最小元素放到合适的位置;而选择排序每遍历一次都记住了当前最小元素的位置,最后仅需一次交换操作即可将其放到合适的位置。
1 |
|
3. 插入排序
工作原理:
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
1 |
|
4. 归并排序
步骤:
- 把长度为n的输入序列分为两个长度为n/2的子序列
- 对这两个子序列分别采用归并排序对这两个子序列分别采用归并排序
- 将两个排序好的子序列合并成一个最终的排序序列将两个排序好的子序列合并成一个最终的排序序列
1 |
|
5. 快速排序
使用分治策略(Divide and Conquer)来把一个序列分为两个子序列。
步骤:
- 从序列中挑出一个元素,作为”基准”(pivot).
- 把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作。
- 对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。
1 |
|
6. 堆排序
步骤:
- 由输入的无序数组构造一个最大堆,作为初始的无序区
- 把堆顶元素(最大值)和堆尾元素互换,将最大元素”沉”到数组末端
- 重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整 +交换步骤,直到整个序列有序。
1 |
|
7. 计数排序
计数排序不是基于比较的排序算法
其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。
作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
算法描述:
- 统计数组A中每个值A[i]出现的次数,存入C[A[i]]
- 从前向后,使数组C中的每个值等于其与前一项相加,这样数组C[A[i]]就变成了代表数组A中小于等于A[i]的元素个数
- 反向填充目标数组B:将数组元素A[i]放在数组B的第C[A[i]]个位置(下标为C[A[i]] - 1),每放一个元素就将C[A[i]]递减
1 |
|
8. 基数排序
将所有待比较正整数统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始进行基数为10的计数排序,一直到最高位计数排序完后,数列就变成一个有序序列(利用了计数排序的稳定性)。
基数排序的时间复杂度是O(n * d),其中n是待排序元素个数,d是数字位数。这个时间复杂度不一定优于O(n log n),d 的大小取决于数字位的选择和待排序数据所属数据类型的全集的大小;
d 决定了进行多少轮处理,而n是每轮处理的操作数目。
如果考虑和比较排序进行对照,基数排序的形式复杂度虽然不一定更小,但由于不进行比较,因此其基本操作的代价较小,而且如果适当的选择基数,d 一般不大于log n,所以基数排序一般要快过基于比较的排序,比如快速排序。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序并不是只能用于整数排序。
1 |
|
9. 桶排序
原理:
假设输入数据服从均匀分布,将数据分到有限数量的桶里,利用计数排序可以定位桶的边界,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。
算法描述:
- 设置一个定量的数组当作空桶;
- 遍历输入数据,并且把数据一个一个放到对应的桶里去;
- 对每个不是空的桶进行排序;
- 从不是空的桶里把排好序的数据拼接起来。
1 |
|