三种排序算法详解
本文档解释了三种基本的排序算法及其Java实现。所有实现都将相同的数组[1, 6, 8, 2, 3]按升序排列。
1. 选择排序 (choose.java)
选择排序通过重复从未排序部分找到最小元素并将其放置在开头来工作。
工作原理:
- 在整个数组中找到最小元素并与第一个元素交换
- 在剩余未排序部分找到最小元素并与第二个元素交换
- 重复此过程直到整个数组有序
实现代码:
java
public static void main(String[] args) {
int[] a = {1, 6, 8, 2, 3};
for (int i = 0; i < a.length; i++) {
int index = i;
for (int j = i; j < a.length; j++) {
if (a[index] > a[j]) {
index = j;
}
}
int temp = a[i];
a[i] = a[index];
a[index] = temp;
}
System.out.println(Arrays.toString(a));
}
特点:
- 时间复杂度:O(n²)
- 空间复杂度:O(1)
- 不稳定(可能会改变相等元素的相对顺序)
- 在小数据集上表现良好
2. 冒泡排序 (effervescence.java)
冒泡排序通过重复遍历列表,比较相邻元素并在顺序错误时交换它们来工作。每一轮遍历后,最大的元素会"冒泡"到数组的末尾。
工作原理:
- 比较相邻元素,如果左边的大于右边的则交换它们
- 每次完整遍历后,未排序元素中的最大值会移动到正确位置
- 重复直到不需要交换为止
实现代码:
java
public static void main(String[] args) {
int[] a = {1, 6, 8, 2, 3};
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1 - i; j++) {
if (a[j] > a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
System.out.println(Arrays.toString(a));
}
特点:
- 时间复杂度:O(n²)
- 空间复杂度:O(1)
- 稳定排序算法
- 自适应 - 可以检测列表是否已经排序
3. 插入排序 (insert.java)
插入排序通过逐个构建最终的排序数组来工作。它的工作方式类似于人们如何整理手中的扑克牌。
工作原理:
- 从第二个元素(索引1)开始
- 将其与前面的元素比较并插入到正确位置
- 移动到下一个元素并重复直到整个数组有序
实现代码:
java
public static void main(String[] args) {
int[] a = {1, 6, 8, 2, 3};
for (int i = 0; i < a.length; i++) {
int j = i;
for (; j > 0; j--) {
if (a[j] < a[j - 1]) {
int temp = a[j];
a[j] = a[j - 1];
a[j - 1] = temp;
} else
break;
}
}
System.out.println(Arrays.toString(a));
}
特点:
- 时间复杂度:O(n²)
- 空间复杂度:O(1)
- 稳定排序算法
- 对小数据集高效
- 自适应 - 对已基本排序的数据集很高效
总结
这三种算法都具有O(n²)的时间复杂度,使得它们对于大数据集来说效率不高。但它们对教育目的和小数组排序很有价值。每种算法都有自己的优势:
- 插入排序是其中最有价值的,一句话,假设一侧是有序的,新元素去寻找有序列表的位置
- 选择排序最小化交换次数,一句话,假设一侧是有序的,去剩下的选择一个最大或者最小然后放入末尾
- 冒泡排序简单易懂且易于实现 ,一句话,假设一侧是有序的,从开头或者结尾,不断就近比较,把最大最小拱到一侧
- 插入排序对于近似排序的数组很高效,并且是稳定的
对于较大的数据集,更高级的算法如快速排序、归并排序或堆排序将是更合适的选择。