Java常用的排序算法有以下这些:
1. 冒泡排序
每轮从后往前交换,把最小的元素通过不断地交换冒到前面
2. 插入排序
将所有元素插入到一个有序的集合中
拓展:在有序集合中查找插入位置可以用二分法减少时间复杂度
3. 选择排序
每轮把最小的元素找出来,放在最前面
4. 希尔排序
把待排序序列分成几个子序列,再分别对这几个子序列进行直接插入排序
5. 归并排序
递归方式将集合分成两组,并对分组结果做合并
由于递归最终的分组元素只剩1位,所以只需要在合并时做好排序即可
6. 快速排序
1. 以集合第一个元素为基准点,将所有小余基准点的元素放左边,所有大于的元素放右边,并返回基准点所在集合的下标
关键实现: while (start < end)
1.1 从后往前找一个小的元素,交换到start位置
1.2 从前往后找一个大的元素,交换到end位置
1.3 最终start == end 遍是基准点写入的位置
2. 以基准点为界,将两个子序列递推调用步骤1进行排序
7. 堆排序
1. 将集合构建成一个大顶堆,小顶堆其实就是一棵特殊的完全二叉树
特性:每个节点都大余他的两个子节点
在列表结构下,节点i对应的左右子节点分别是2i+1,2i+2
2. 构建大顶堆:从非叶子节点开始从后往前遍历,比较左右子节点把最大的值冒到根节点
3. 堆顶与末尾元素交换,堆的元素个数-1,调整堆结构保持堆特性
for (int i = n / 2 - 1; i >= 0; i--) {
heapify(arr, n, i);
}
for (int i = n - 1; i >= 0; i--) {
swap(arr, 0, i);
heapify(arr, i, 0);
}
8. 计数排序
1. 找到最大值和最小值,构建一个数组
2. 遍历集合,将数组中该值对应的下标+1
3. 对数组遍历得到排序结果
使用于数值较小,重复较多的集合排序
注:可以使用TreeMap代替数组
9. 桶排序
1. 遍历集合,找到最大值和最小值
2. 指定桶数量,根据数量分每个桶的范围
3. 将元素按范围放入桶内,进行排序
4. 合并桶为集合
10. 基数排序
1. 遍历集合,找到最大值,确定位数N(个十百)
2. 创建一个长度为10的嵌套列表
3. 按位数从低到高,依次对数组进行排序,个位 -> 十位 -> 百位
List<List<Integer>> buckets = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
buckets.add(new ArrayList<>());
}
int mod = 10; // 初始10,用于数据个位数取模
int div = 1; // 桶序号除数
// 按位数循环数组,个位循环1次,十位循环2次,百位循环3次,以此类推!
for (int i = 0; i < maxDigit; i++, mod *= 10, div *= 10) {
// 循环数组,将数据分别存入桶中
// 第一次循环,桶里面的个位数顺序排序完成
// 第二次循环,个位、十位都排序完成
// 第三次循环,个位、十位、百位都排序完成
for (int j = 0; j < arr.length; j++) {
// 计算当前位数的桶序号
int bucketIndex = (arr[j] % mod) / div;
buckets.get(bucketIndex).add(arr[j]);
}
// 循环桶列表,将当前位数已排序的数据放入数组中
int currentIndex = 0;
for (int j = 0; j < 10; j++) {
List<Integer> bucket = buckets.get(j);
for (int k = 0; k < bucket.size(); k++) {
arr[currentIndex++] = bucket.get(k);
}
bucket.clear();
}
}