1. 冒泡排序Bubble Sort
相邻元素进行比较,如果a(n) > a(n + 1)
则交换。
一轮交换完毕后,可以确保最后一位a(length - 1)
为最大。
第i
次比较完成后,可以确保length - 1 - i ~ length - 1
位为数组中最大数的递增排序。
由于在排序尚未结束的时候可能已经排序成功,可以使用一个变量标记之前的一轮排序是否存在交换,若没有进行任何交换则已排序完成。
最快:待排序数组是已经满足排序要求的。
最慢:待排序数组与排序要求正好相反。
/**
* @Author HE LONG CAN
* @Description 冒泡排序
* @Date 2021-08-07 20:51:41
*/
public class BubbleSort {
public static void main(String[] args) {
int[] array = new int[]{1,5,3,2,4};
// 1 3 2 4 5
// 1 2 3 4 5
// 共排序两次,实际三次,最后一次检查。
int[] sortedArray = sort(array);
System.out.println(Arrays.toString(sortedArray));
}
public static int[] sort(int[] array) {
//拷贝一个 newArray
int[] newArray = Arrays.copyOf(array, array.length);
//最外侧循环用于抛弃尾部已排序好的最大序列
for (int i = 1; i < newArray.length; i++) {
//标记是否进行了交换
boolean isSwitched = false;
for (int j = 0; j < newArray.length - i; j++) {
if (newArray[j] > newArray[j + 1]) {
isSwitched = true;
int middle = newArray[j];
newArray[j] = newArray[j + 1];
newArray[j + 1] = middle;
}
}
//若没有进行交换
if (!isSwitched) {
System.out.println("共循环了 " + i + " 轮");
break;
}
}
return newArray;
}
}
2. 选择排序Select Sort
首先找到数组[0 ~ length - 1]
位置中最小的元素,与位置0
元素交换。
再找到数组中[1 ~ length - 1]
位置中的最小元素,与位置1
元素交换。
以此类推,直到循环结束。
时间复杂度永远为O(n^2)
。
/**
* @Author HE LONG CAN
* @Description 选择排序
* @Date 2021-08-07 21:48:18
*/
public class SelectSort {
public static void main(String[] args) {
int[] array = new int[]{1,5,3,2,4};
// 1 5 3 2 4
// 1 2 3 5 4
// 1 2 3 5 4
// 1 2 3 4 5
int[] sortedArray = sort(array);
System.out.println(Arrays.toString(sortedArray));
}
public static int[] sort(int[] array) {
int[] newArray = Arrays.copyOf(array,array.length);
for (int i = 0; i < newArray.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < newArray.length; j++) {
if (newArray[minIndex] > newArray[j]) {
minIndex = j;
}
}
//如果找到的最小值并不是i,才需要交换
if (i != minIndex) {
int middle = newArray[i];
newArray[i] = newArray[minIndex];
newArray[minIndex] = middle;
}
}
return newArray;
}
}
3. 插入排序
从1
位置的元素开始向前比较,将小的数字插入到大的数字之前。如果没有没有找到更大的数字则放在原位。
类似于扑克牌游戏的手牌排序。
插入排序在对几乎已经排好序的数据进行操作时效率比较高。
但插入排序一般来说比较低效。
/**
* @Author HE LONG CAN
* @Description 插入排序
* @Date 2021-08-07 22:29:17
*/
public class InsertSort {
public static void main(String[] args) {
int[] array = new int[]{10,2,45,8,36,4,2,47,52};
int[] sortedArray = sort(array);
System.out.println(Arrays.toString(sortedArray));
}
public static int[] sort(int[] array) {
int[] newArray = Arrays.copyOf(array, array.length);
for (int i = 1; i < newArray.length; i++) {
int current = newArray[i];
int j = i - 1;
for (; j >= 0; j--) {
//小于则移动j位到j+1
if (current < newArray[j]) {
newArray[j + 1] = newArray[j];
}else {
break;
}
}
//如果上面循环正常结束,j = 1 说明都比current小,那么我们将其插入到0位,因为0位本来的元素已经被移动到了1位
//如果break结束,则j > -1,也有可能是0,也就是第一个数字大于current, 那么我们插入到j位+1之后。
newArray[j + 1] = current;
}
return newArray;
}
}
4. 希尔排序
由于插入排序对几乎已经排好序的数据进行操作时效率比较高。
所以希尔排序的思想就是通过某种方法将数组变为一个几乎有序的数列,然后使用插入排序。
排序方法:
- 设置一个增长量
m
,按照增长量m
对数组进行分组。 - 对分好组的每一组数据完成插入排序。
- 减少增长量,一般是
m = m / 2
,重复操作。直到m = 1
。
增长量选择依据:
int m = 1; //增长量
while(m < array.length / 2) {
m = m * 2 + 1;
}
/**
* @Author HE LONG CAN
* @Description 希尔排序
* @Date 2021-08-08 21:30:13
*/
public class ShellSort {
public static void main(String[] args) {
int[] array = new int[]{9,1,2,5,7,4,8,6,3,5};
int[] sortedArray = sort(array);
System.out.println(Arrays.toString(sortedArray));
}
public static int[] sort(int[] array) {
int[] newArray = Arrays.copyOf(array,array.length);
//计算增长量
int m = 1;
while (m < array.length / 2) {
m = m * 2 + 1;
}
while (m >= 1) {
for (int i = m; i < newArray.length; i++) {
int current = newArray[i];
int j = i - m;
for (; j >= 0; j -= m) {
if (current < newArray[j]) {
newArray[j + m] = newArray[j];
}else {
break;
}
}
newArray[j + m] = current;
}
m /= 2;
}
return newArray;
}
}