排序算法 | 平均时间 | 最差时间 | 稳定性 | 空间复杂度 | 备注 |
---|---|---|---|---|---|
冒泡排序 | O(n2) | O(n2) | 稳定 | O(1) | n较小时好 |
交换排序 | O(n2) | O(n2) | 不稳定 | O(1) n | 较小时好 |
选择排序 | O(n2) | O(n2) | 不稳定 | O(1) n | 较小时好 |
插入排序 | O(n2) | O(n2) | 稳定 | O(1) | 大部分已有序时好 |
基数排序 | O(n*k) | O(n*k) | 稳定 | O(n) | 二维数组(桶)、一维数组(桶中首元素的位置) |
希尔排序 | O(nlogn) | O(ns)(1不稳定 | O(1) | s是所选分组 | |
快速排序 | O(nlogn) | O(n2) | 不稳定 | O(logn) | n较大时好 |
归并排序 | O(nlogn) | O(nlogn) | 稳定 | O(1) | n较大时好 |
堆排序 | O(nlogn) | O(nlogn) | 不稳定 | O(1) | n较大时好 |
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
结束循环
/**
* 冒泡排序
* @author 尹稳健~
* @version 1.0
* @time 2022/9/7
*/
public class Bubbling {
public static void main(String[] args) {
int[] arr = {3,9,-1,7,21};
// 外层循环次数为数组的长度-1
for (int i = 0; i < arr.length - 1; i++) {
// 内层循环次数,每次都会减少
for (int j = 0; j < arr.length - 1 - i; j++) {
// 交换位置
if (arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
// 打印
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
优化:如果在某次外层循环结束后发现数组元素位置没有发生改变,那么循环结束,已经是有序的数组了
代码:
/**
* 冒泡排序
* @author 尹稳健~
* @version 1.0
* @time 2022/9/7
*/
public class Bubbling {
public static void main(String[] args) {
int[] arr = {3,9,-1,7,21};
// 外层循环次数为数组的长度-1
for (int i = 0; i < arr.length - 1; i++) {
// 如果内层循环没有交换位置,那么已经是有序数组,结束循环
boolean flag = true;
// 内层循环次数,每次都会减少
for (int j = 0; j < arr.length - 1 - i; j++) {
// 交换位置
if (arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = false;
}
}
if (flag){
break;
}
}
// 打印
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
/**
* @author 尹稳健~
* @version 1.0
* @time 2022/9/7
*/
public class Deduction {
public static void main(String[] args) {
int[] arr = {8,3,2,1,7,4,6,5};
// 记录最小数的下标
int min;
// 假设min=0开始
min = 0;
// 既然我们都假设下标为0的是最小,那么就从他后面开始比较
for (int i = 1; i < arr.length; i++) {
// 如果后面的元素中有小于的元素,记住的他下标
if (arr[min] > arr[i]){
min = i;
}
}
// 交换
int temp = arr[0];
arr[0] = arr[min];
arr[min] = temp;
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
// 打印获取到 1 3 2 8 7 4 6 5
}
}
/**
* @author 尹稳健~
* @version 1.0
* @time 2022/9/7
*/
public class Deduction {
public static void main(String[] args) {
// int[] arr = {8,3,2,1,7,4,6,5};
int[] arr = {1,3,2,8,7,4,6,5};
// 记录最小数的下标
int min;
// 假设min=1开始
min = 1;
// 既然我们都假设下标为1的是最小,那么就从他后面开始比较
for (int i = 2; i < arr.length; i++) {
// 如果后面的元素中有小于的元素,记住的他下标
if (arr[min] > arr[i]){
min = i;
}
}
// 交换
int temp = arr[1];
arr[1] = arr[min];
arr[min] = temp;
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
// 打印获取到 1 2 3 8 7 4 6 5
}
}
以此类推
/**
* 选择排序
* @author 尹稳健~
* @version 1.0
* @time 2022/9/7
*/
public class Choice {
public static void main(String[] args) {
int[] arr = {8,3,2,1,7,4,6,5};
// 记录最小数的下标
int min;
// 外层循环次数为数组长度 - 1
for (int i = 0; i < arr.length - 1; i++) {
min = i;
// 内层循环每次都是从i+1开始
for (int j = i+1; j < arr.length; j++) {
// 找出最小数的下标
if (arr[min] > arr[j]){
min = j;
}
}
// 如果不是同一个数,那么就交换位置
if (min != i){
int temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}
插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法 。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。
注意这里红色的数组代表已经是有序列表元素
/**
* 插入排序
* @author 尹稳健~
* @version 1.0
* @time 2022/9/9
*/
public class InsertSorted {
public static void main(String[] args) {
int[] arr = {3, 1, 6, 10, 2};
for (int i = 1; i < arr.length; i++) {
// 保留即将插入元素的值
int insertValue = arr[i];
// 当前索引
int index = i;
// 1.如果索引大于0,说明还没遍历完
// 2.如果插入的值小于有序列表中的值,那么久有序列表中大于插入元素的元素,就要后移
while (index > 0 && insertValue < arr[index-1]){
arr[index] = arr[index-1];
index --;
}
// 直到找到插入元素不大于有序列表中元素的位置
arr[index] = insertValue;
}
// 打印
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个数据恰被分成一组,算法便终止。
增量为3,直接从arr[3]开始进行比对,发现arr[3] > arr[0],不需要换位置,arr[4] < arr[1]需要换位置
交换位置后,继续进行比较
直到arr[6]
然后我们发现 arr[3] 还能再和 arr[0] 进行比较 因为 index-gap >= 0 就能继续比较
从arr[1]开始进行比较,依次往后比较,直到 arr[6] < arr[5]
交换位置后,arr[5] 与 arr[4] 进行比较,交换位置
结束
/**
* 希尔排序
* @author 尹稳健~
* @version 1.0
* @time 2022/9/9
*/
public class ShellInsert {
public static void main(String[] args) {
int[] arr = {23,34,21,31,18,98,10};
// 增量
int gap = arr.length/2;
// 只要增量大于等于1就继续分组
while (gap >= 1){
// 从索引=增量开始,依次往后
for (int i = gap; i < arr.length; i++) {
// 定义一个变量,防止下面代码影响原 i 的值
int j = i;
// 只有 arr[j] < arr[j-gap] 交换位置 ,而且可能一次不一定能比较完,需要多次比较 j-gap >= 0
while (j-gap >= 0 && arr[j] < arr[j-gap]){
// 交换
int temp = arr[j];
arr[j] = arr[j-gap];
arr[j-gap] = temp;
// 假设 j = 6 时,可以多次执行
j -= gap;
}
}
// 控制增量
gap /= 2;
}
// 打印
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
}
}