十大经典排序算法(Java实现)

article/2025/10/24 15:58:07

排序算法的重要性不言而喻,为了加深对这十种算法的理解,固写此文。

目录

  • 1、冒泡排序(Bubble Sort)
  • 2、选择排序(Selection Sort)
  • 3、插入排序(Insertion Sort)
  • 4、希尔排序(Shell Sort)
  • 5、归并排序(Merge Sort)
  • 6、快速排序(Quick Sort)
  • 7、堆排序(Heap Sort)
  • 8、计数排序(Counting Sort)
  • 9、桶排序(Bucket Sort)
  • 10、基数排序(Radix Sort)
  • 11、总结

首先排序算法可以分为内部排序算法和外部排序算法:在内存中进行的称为内部排序算法,也就是这里所说的这十种算法;相应的,当数据量很大时无法全部拷贝到内存需要使用外存,称为外部排序算法。接下来我们可用如下表来简单概括这十种算法:

十大经典排序算法平均时间复杂度最好时间复杂度最坏时间复杂度空间复杂度排序方式稳定性
冒泡排序 O \Omicron O(n2) O \Omicron O(n) O \Omicron O(n2) O \Omicron O(1)In-place稳定
选择排序 O \Omicron O(n2) O \Omicron O(n2) O \Omicron O(n2) O \Omicron O(1)In-place不稳定
插入排序 O \Omicron O(n2) O \Omicron O(n) O \Omicron O(n2) O \Omicron O(1)In-place稳定
希尔排序 O \Omicron O(n1.3) O \Omicron O(n) O \Omicron O(n2) O \Omicron O(1)In-place不稳定
归并排序 O \Omicron O(n log ⁡ \log log2n) O \Omicron O(n log ⁡ \log log2n) O \Omicron O(n log ⁡ \log log2n) O \Omicron O(n)Out-place稳定
快速排序 O \Omicron O(n log ⁡ \log log2n) O \Omicron O(n log ⁡ \log log2n) O \Omicron O(n2) O \Omicron O( log ⁡ \log log2n)In-place不稳定
堆排序 O \Omicron O(n log ⁡ \log log2n) O \Omicron O(n log ⁡ \log log2n) O \Omicron O(n log ⁡ \log log2n) O \Omicron O(1)In-place不稳定
计数排序 O \Omicron O(n+k) O \Omicron O(n+k) O \Omicron O(n+k) O \Omicron O(k)Out-place稳定
桶排序 O \Omicron O(n+k) O \Omicron O(n+k) O \Omicron O(n2) O \Omicron O(n+k)Out-place稳定
基数排序 O \Omicron O(n*k) O \Omicron O(n*k) O \Omicron O(n*k) O \Omicron O(n+k)Out-place稳定
表中数据说明:
  • 稳定:如果A原本在B前面,而A=B,排序之后A仍然在B的前面;
  • 不稳定:如果A原本在B的前面,而A=B,排序之后A可能会出现在B的后面;
  • 时间复杂度: 描述一个算法执行所耗费的时间;
  • 空间复杂度:描述一个算法执行所需内存的大小;
  • n:数据规模;
  • k:“桶”的个数;
  • In-place:占用常数内存,不占用额外内存;
  • Out-place:占用额外内存。

该十种排序算法可分为如下所示的两大类

  • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(n log ⁡ \log logn),因此也称为非线性时间比较类排序。
  • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。
    在这里插入图片描述

1、冒泡排序(Bubble Sort)

算法步驟

  1. 比较相邻的元素,如果第一个比第二个大,就交换它们两个;
  2. 对每一对相邻元素作同样的比价,从开始第一对到结尾的最后一对,这样在最后的元素就是最大的数;
  3. 针对所有的元素重复以上的步骤,除了数组最后已经排好序的数组;
  4. 重复步骤1~3,直到排序完成。
    在这里插入图片描述

代码实现

public class BubbleSort {public static void bubbleSort(int[] arr) {int len = arr.length;for (int i = 0; i < len - 1; i++) {boolean flag = true;for (int j = 0; j < len - i - 1; j++) {if (arr[j] > arr[j + 1]) {int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;flag = false;}}if (flag) {break;}}}
}

2、选择排序(Selection Sort)

算法步驟

  1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置;
  2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾;
  3. 重复第2步,直到所有元素均排序完毕。
    在这里插入图片描述

代码实现

public class SelectionSort {public static void selectionSort(int[] arr) {int len = arr.length;for (int i = 0; i < len - 1; i++) {int minVal = i;for (int j = i + 1; j < len; j++) {if (arr[minVal] > arr[j]) {minVal = j;}}if (minVal != i) {int tmp = arr[i];arr[i] = arr[minVal];arr[minVal] = tmp;}}}
}

3、插入排序(Insertion Sort)

算法步驟

  1. 首先从第一个元素开始,该元素被认为是有序的;
  2. 取出下一个元素,在已经排序的元素序列中从后往前进行扫描;
  3. 如果该已排好序的元素大于新元素,则将该元素移到下一位置;
  4. 重复步骤3一直往前进行扫描比较,直到找到已排序的元素小于或者等于新元素的位置;
  5. 将新元素插入到该位置后;
  6. 重复步骤2~5。
    在这里插入图片描述

代码实现

public class InsertionSort {public static void insertionSort(int[] arr) {for (int i = 1; i < arr.length; i++) {int val = arr[i], j = i;while (j > 0 && val < arr[j - 1]) {arr[j] = arr[j - 1];j--;}arr[j] = val;}}
}

4、希尔排序(Shell Sort)

算法步驟

  1. 选择一个增量序列{t1, t2, …, tk};
  2. 按增量序列个数k,对序列进行k趟排序;
  3. 每趟排序,根据对应的增量t,将待排序列分割成若干长度为m的子序列,分别对各子表进行直接插入排序。仅增量因子为1时,整个序列作为一个表来处理,表长度即为整个序列的长度。

其中,增量gap=length/2,缩小增量继续以gap = gap/2的方式,这种增量选择我们可以用一个序列来表示,{n/2, (n/2)/2, …, 1},称为增量序列。一般的增量序列都选择以上说明的这个,但不一定是最优的。
在这里插入图片描述
代码实现

public class ShellSort {public static void shellSort(int[] arr) {int len = arr.length, tmp, j;for (int gap = len / 2; gap >= 1; gap = gap / 2) {for (int i = gap; i < len; i++) {tmp = arr[i];j = i - gap;while (j >= 0 && arr[j] > tmp) {arr[j + gap] = arr[j];j -= gap;}arr[j + gap] = tmp;}}}
}

5、归并排序(Merge Sort)

算法步驟

  1. 如果待排序列只有一个元素,则直接返回,否则将长度为n的待排序列分成两个长度为n/2的子序列,递归进行调用进行分割知道每个子序列中只有一个元素;
  2. 此时的每个子序列被认为是有序的,然后递归调用的返回子序列进行两两合并;
  3. 合并过程中完成排序操作,具体操作为设定两个指针,分别指向两个已经排序子序列的起始位置;
  4. 比较两个指针所指向的元素,选择相对小的元素放入到合并返回的数组,并移动指针到下一位置;
  5. 重复步骤3~4直到某一指针达到序列尾;
  6. 将另一序列剩下的所有元素直接复制到合并序列尾,最终得到的新序列就是有序序列。
    在这里插入图片描述
    在这里插入图片描述

代码实现

import java.util.Arrays;public class MergeSort {public static int[] mergeSort(int[] arr) {int len = arr.length;if (len < 2) {return arr;}int mIdx = len / 2;return merge(mergeSort(Arrays.copyOfRange(arr, 0, mIdx)), mergeSort(Arrays.copyOfRange(arr, mIdx, len)));}private static int[] merge(int[] arrLeft, int[] arrRight) {int leftLen = arrLeft.length, rightLen = arrRight.length, leftIdx = 0, rightIdx = 0, idx = 0;int[] result = new int[leftLen + rightLen];while (leftIdx < leftLen && rightIdx < rightLen) {if (arrLeft[leftIdx] < arrRight[rightIdx]) {result[idx++] = arrLeft[leftIdx++];} else {result[idx++] = arrRight[rightIdx++];}}while (leftIdx < leftLen) {result[idx++] = arrLeft[leftIdx++];}while (rightIdx < rightLen) {result[idx++] = arrRight[rightIdx++];}return result;}
}

6、快速排序(Quick Sort)

算法步驟

  1. 从序列中随机挑出一个元素,做为基准(pivot,这里选择序列的最左边元素作为基准);
  2. 重新排列序列,将所有比基准值小的元素摆放在基准前面,所有比基准值大的摆在基准的后面。该操作结束之后,该基准就处于数列的中间位置。这个操作称为分区(partition);
  3. 递归地把小于基准值元素的子序列和大于基准值元素的子序列进行上述操作即可。
    在这里插入图片描述

代码实现

public class QuickSort {public static void quickSort(int[] arr) {sort(arr, 0, arr.length - 1);}private static void sort(int[] arr, int left, int right) {if (left < right) {int pivotIdx = partition(arr, left, right);sort(arr, 0, pivotIdx - 1);sort(arr, pivotIdx + 1, right);}}private static int partition(int[] arr, int left, int right) {int idx = left + 1;for (int i = idx; i <= right; i++) {if (arr[left] > arr[i]) {swap(arr, i, idx++);}}swap(arr, left, idx - 1);return idx - 1;}private static void swap(int[] arr, int idx1, int idx2) {int tmp = arr[idx1];arr[idx1] = arr[idx2];arr[idx2] = tmp;}
}

7、堆排序(Heap Sort)

算法步驟

  1. 将待排序列(R0, R1, ……, Rn)构建成最大堆(最小堆);
  2. 将堆顶元素R[0]与最后一个元素R[n]进行交换,此时得到新的无序区(R0, R1, ……, Rn-1)和新的有序区(Rn),且满足R[0, 1, ……, n-1]<=R[n](>=R[n]);
  3. 由于调整后的新堆可能违反堆的性质,因此需要对当前无序区(R0, R1, ……, Rn-1)进行调整;
  4. 重复步骤2~3直到有序区的元素个数为n。
    在这里插入图片描述

代码实现

public class HeapSort {private static int heapLen;public static void heapSort(int[] arr) {heapLen = arr.length;for (int i = heapLen - 1; i >= 0; i--) {heapify(arr, i);}for (int i = heapLen - 1; i > 0; i--) {swap(arr, 0, heapLen - 1);heapLen--;heapify(arr, 0);}}private static void heapify(int[] arr, int idx) {int left = idx * 2 + 1, right = idx * 2 + 2, largest = idx;if (left < heapLen && arr[left] > arr[largest]) {largest = left;}if (right < heapLen && arr[right] > arr[largest]) {largest = right;}if (largest != idx) {swap(arr, largest, idx);heapify(arr, largest);}}private static void swap(int[] arr, int idx1, int idx2) {int tmp = arr[idx1];arr[idx1] = arr[idx2];arr[idx2] = tmp;}
}

8、计数排序(Counting Sort)

算法步驟

  1. 找出数组中的最大值maxVal和最小值minVal;
  2. 创建一个计数数组countArr,其长度是maxVal-minVal+1,元素默认值都为0;
  3. 遍历原数组arr中的元素arr[i],以arr[i]-minVal作为countArr数组的索引,以arr[i]的值在arr中元素出现次数作为countArr[a[i]-min]的值;
  4. 遍历countArr数组,只要该数组的某一下标的值不为0则循环将下标值+minVal输出返回到原数组即可。
    在这里插入图片描述

代码实现

public class CountingSort {public static void countingSort(int[] arr) {int len = arr.length;if (len < 2) return;int minVal = arr[0], maxVal = arr[0];for (int i = 1; i < len; i++) {if (arr[i] < minVal) {minVal = arr[i];} else if (arr[i] > maxVal) {maxVal = arr[i];}}int[] countArr = new int[maxVal - minVal + 1];for (int val : arr) {countArr[val - minVal]++;}for (int arrIdx = 0, countIdx = 0; countIdx < countArr.length; countIdx++) {while (countArr[countIdx]-- > 0) {arr[arrIdx++] = minVal + countIdx;}}}
}

9、桶排序(Bucket Sort)

算法步驟

  1. 设置一个bucketSize(该数值的选择对性能至关重要,性能最好时每个桶都均匀放置所有数值,反之最差),表示每个桶最多能放置多少个数值;
  2. 遍历输入数据,并且把数据依次放到到对应的桶里去;
  3. 对每个非空的桶进行排序,可以使用其它排序方法(这里递归使用桶排序);
  4. 从非空桶里把排好序的数据拼接起来即可。
    在这里插入图片描述

代码实现

import java.util.ArrayList;
import java.util.List;public class BucketSort {private static List<Integer> bucketSort(List<Integer> arr, int bucketSize) {int len = arr.size();if (len < 2 || bucketSize == 0) {return arr;}int minVal = arr.get(0), maxVal = arr.get(0);for (int i = 1; i < len; i++) {if (arr.get(i) < minVal) {minVal = arr.get(i);} else if (arr.get(i) > maxVal) {maxVal = arr.get(i);}}int bucketNum = (maxVal - minVal) / bucketSize + 1;List<List<Integer>> bucket = new ArrayList<>();for (int i = 0; i < bucketNum; i++) {bucket.add(new ArrayList<>());}for (int val : arr) {int idx = (val - minVal) / bucketSize;bucket.get(idx).add(val);}for (int i = 0; i < bucketNum; i++) {if (bucket.get(i).size() > 1) {bucket.set(i, bucketSort(bucket.get(i), bucketSize / 2));}}List<Integer> result = new ArrayList<>();for (List<Integer> val : bucket) {result.addAll(val);}return result;}
}

10、基数排序(Radix Sort)

算法步骤

  1. 取得数组中的最大数,并取得位数,即为迭代次数n(例如:数组中最大数为123,则 n=3);
  2. arr为原始数组,从最低位(或最高位)开始根据每位的数字组成radix数组(radix数组是个二维数组,其中一维长度为10),例如123在第一轮时存放在下标为3的radix数组中;
  3. 将radix数组中的数据从0下标开始依次赋值给原数组;
  4. 重复2~3步骤n次即可。
    在这里插入图片描述
    在这里插入图片描述
    代码实现
import java.util.ArrayList;
import java.util.List;//基数排序
public class RadixSort {public static void radixSort(int[] arr) {if (arr.length < 2) return;int maxVal = arr[0];//求出最大值for (int a : arr) {if (maxVal < a) {maxVal = a;}}int n = 1;while (maxVal / 10 != 0) {//求出最大值位数maxVal /= 10;n++;}for (int i = 0; i < n; i++) {List<List<Integer>> radix = new ArrayList<>();for (int j = 0; j < 10; j++) {radix.add(new ArrayList<>());}int index;for (int a : arr) {index = (a / (int) Math.pow(10, i)) % 10;radix.get(index).add(a);}index = 0;for (List<Integer> list : radix) {for (int a : list) {arr[index++] = a;}}}}
}

11、总结

数据量规模较小,考虑插入或选择。当元素分布有序时插入将大大减少比较和移动记录的次数,如果不要求稳定性,可以使用选择,效率略高于插入;
数据量规模中等,使用希尔排序;
数据量规模较大,考虑堆排序(元素分布接近正序或逆序)、快速排序(元素分布随机)和归并排序(稳定性);
一般来说不使用冒泡。


http://chatgpt.dhexx.cn/article/n80INJaC.shtml

相关文章

Java排序算法——插入排序(Insertion Sort)

之前总结了交换排序的冒泡排序与选择排序的简单选择排序&#xff0c;这次我们来看看插入排序的简单插入排序~ 往期传送门&#xff1a; 冒泡排序&#xff1a; Java排序算法——冒泡排序&#xff08;Bubble Sort&#xff09;https://blog.csdn.net/babbfqb93/article/details/…

Java排序算法——冒泡排序(Bubble Sort)

冒泡排序是所有排序算法中最简单的一个排序&#xff0c;也是我个人学习的第一个排序方法&#xff0c;在这里重新进行一个总结。 冒泡排序&#xff08;Bubble Sort&#xff09;就如同其名称一样&#xff0c;水中的气泡由于压强的原因所以从下到上其大小也是从小到大&#xff0c…

Java排序算法——插入排序

Java排序算法——插入排序&#xff08;Insertion Sort&#xff09; 传送门 冒泡排序选择排序 简述 插入排序&#xff08;Insertion Sort&#xff09;是一种简单直观的排序算法。它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前…

Java实现排序算法

一、常见排序算法&#xff1a; 1、插入类排序&#xff1a; (1)直接插入排序 (2)希尔排序 2、选择类排序 (1)简单选择排序 (2)堆排序 3、交换类排序 (1)冒泡排序 (2)快速排序 4、归并排序 5、基数排序 二、内部排序&#xff1a;只考虑数据量较小仅需要使用内存的排序算法 三、…

Java排序算法——选择排序

Java排序算法——选择排序&#xff08;Selection sort&#xff09; 传送门 冒泡排序插入排序 简述 选择排序&#xff08;Selection sort&#xff09;是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小&#xff08;大&#xff09;元素&#xff0c;存放…

JAVA排序:快速排序算法

Java实现快速排序算法 快速排序算法体现了—分治思想&#xff1a;将大问题划分为多个相同独立的小问题&#xff0c;每个小问题的解决合在一起解决了大问题 实现快速排序的思想&#xff1a; {2,4,1,0,3,5}是目标数组 {0,1,2,3,4,5}是结果数组 选取中心轴pivot(中心轴的值用于比较…

Java排序算法——选择排序(Selection Sort)

上次总结了一下冒泡排序&#xff0c;这次来看看同样非常简单的选择排序 上期冒泡排序传送门&#xff1a; Java排序算法——冒泡排序&#xff08;Bubble Sort&#xff09;https://blog.csdn.net/babbfqb93/article/details/123005968?spm1001.2014.3001.5501 选择排序&#…

选择排序——Java排序算法

选择排序 选择排序&#xff08;SelectSort&#xff09;选择排序是所有排序中最简单的排序算法之一&#xff0c;同时也是要求我们必须掌握的排序算法之一。 时间复杂度 选择排序的时间复杂度为(n2) 算法步骤 1.在未排序的序列中找到最小或者最大的元素&#xff0c;存放到排…

java 排序api_JAVA排序算法API

上一个类 下一个类 框架 无框架 摘要&#xff1a; 嵌套 | 字段 | 构造函数 | 方法 详细信息&#xff1a; 字段 | 构造函数 | 方法 org.luosijin.test 类 Sort java.lang.Object org.luosijin.test.Sort public class Sort extends java.lang.Object Java实现几种常见排序方…

Java排序算法

7.1 排序算法的介绍 排序也称排序算法(Sort Algorithm)&#xff0c;排序是将一组数据&#xff0c;依指定的顺序进行排列的过程。 7.2 排序的分类 内部排序: 指将需要处理的所有数据都加载到内部存储器(内存)中进行排序。外部排序法&#xff1a; 数据量过大&#xff0c;无法全…

常见几种java排序算法

常见几种java排序算法 0. 总览时间复杂度和稳定性 1.插入排序2.分治排序法,快速排序法3.冒泡排序 low版4.冒泡排序 bigger版5.选择排序6. 归并排序8. 堆排序踩坑v1.0 巨慢不能用v2.0 太慢不能用v3.0 9. 其他排序7. 比较 0. 总览 时间复杂度和稳定性 平均最好最差稳定性冒泡n2…

Java常用实现八种排序算法与代码实现

一、交换排序 所谓交换&#xff0c;就是序列中任意两个元素进行比较&#xff0c;根据比较结果来交换各自在序列中的位置&#xff0c;以此达到排序的目的。 1. 冒泡排序 冒泡排序是一种简单的交换排序算法&#xff0c;以升序排序为例&#xff0c;其核心思想是&#xff1a; 从…

十大经典排序算法——java语言

文章目录 一、冒泡排序二、选择排序三、插入排序四、希尔排序五、归并排序六、快速排序七、堆排序八、计数排序九、桶排序十、基数排序 一、冒泡排序 概述&#xff1a; 冒泡排序是一种简单直观的排序算法。它重复的走访要排序的数列&#xff0c;一次比较两个元素&#xff0c;按…

Java常见排序算法

目录 1、归并排序 2、堆排序 3、基数排序 4、冒泡排序 5、希尔排序 6、快速排序 7、插入排序 8、选择排序 1、归并排序 1、基本思想 归并排序&#xff08;MERGE-SORT&#xff09;是利用归并的思想实现的排序方法&#xff0c;该算法采用经典的分治&#xff08;divide-a…

java实现七种经典排序算法

简单算法&#xff1a;冒泡&#xff0c;简单选择&#xff0c;直接插入 改进算法&#xff1a;希尔&#xff0c;堆&#xff0c;归并&#xff0c;快速 直接插入排序&#xff1a;将一个记录插入到已经拍好的有序列表中&#xff0c;从而得到一个新的、记录数增加1的有序表。 冒泡排…

java实现10种排序算法

1.冒泡排序(Bubble Sort) import java.util.Arrays; //冒泡排序 public class BubbleSort_01 {public static void main(String[] args) {int a[]{3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};//记录比较次数int count0;//i0,第一轮比较for (int i 0; i < a.length-1; i) {…

SQL sever数据库触发器设计

SQL sever数据库触发器设计 一、目的: 能够理解触发器调用的机制。能够使用SQL命令创建DML触发器。能够完成触发器的修改、删除等管理任务。 二、触发器: 定义&#xff1a;触发器&#xff08; T rigger &#xff09;是 SQL server 提供给程序员和数据分析员来保证数据完整性…

MySQL——超详细数据库触发器教程

目录 一、触发器的概念 二、创建触发器 三、查看触发器 四、删除触发器 总结 一、触发器的概念 在实际开发中往往会碰到这样的情况&#xff1a; 当我们对一个表进行数据操作时&#xff0c;需要同步对其它的表执行相应的操作&#xff0c;正常情况下&#xff0c;如果我们使用…

关于数据库触发器(trigger)的简单使用操作

最近在做一些东西&#xff0c;用到关于数据库触发器的简单使用。比如当我们在做用户模块的表设计的时候&#xff0c;我们建了联用户信息表&#xff08;t_user&#xff09;和账号表&#xff08;t_account&#xff09;&#xff0c;账号表&#xff08;t_account&#xff09;用来进…

MySQL数据库触发器

MySQL 数据库中触发器是一个特殊的存储过程&#xff0c;不同的是执行存储过程要使用 CALL 语句来调用&#xff0c;而触发器的 执行不需要使用 CALL 语句来调用&#xff0c;也不需要手工启动&#xff0c;只要一个预定义的事件发生就会被 MySQL自动调用 引发触发器执行的事件一般…