目录

0 概述

1 冒泡排序

2 选择排序

3 插入排序

4 希尔排序

5 快速排序

6 归并排序

7 基数排序

下载地址


7大排序算法详解文档及java代码实现(可直接运行)下载地址:https://download.csdn.net/download/qq_39735940/19005360

0 概述

排序的分类:

  1. 内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序。
  2. 外部排序法:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。

常见的排序算法分类:

度量一个程序(算法)执行时间的两种方法:

  1. 事后统计的方法。这种方法可行, 但是有两个问题:

  2. 事前估算的方法。通过分析某个算法的时间复杂度来判断哪个算法更优。

平均时间复杂度和最坏时间复杂度

  1. 平均时间复杂度是指所有可能的输入实例均以等概率出现的情况下,该算法的运行时间。
  2. 最坏情况下的时间复杂度称最坏时间复杂度。一般讨论的时间复杂度均是最坏情况下的时间复杂度。 这样做的原因是:最坏情况下的时间复杂度是算法在任何输入实例上运行时间的界限,这就保证了算法的运行时间不会比最坏情况更长。

平均时间复杂度和最坏时间复杂度是否一致,和算法有关:

最基础的四个算法:冒泡、选择、插入、快排中,快排的时间复杂度最小O(n*log2n),其他都是O(n2)

相关术语解释:

1 冒泡排序

冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前向后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就象水底下的气泡一样逐渐向上冒。

/*** 冒泡排序* @param arr*/
public static void bubbleSort(int[] arr) {for (int i = 0; i < arr.length - 1; i++) {for (int j = 0; j < arr.length - i - 1; j++) {if (arr[j] > arr[j + 1]) {int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}

冒泡排序的优化

因为排序的过程中,各元素不断接近自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个标志flag判断元素是否进行过交换。从而减少不必要的比较。

/*** 冒泡排序的优化* @param arr*/
public static void bubbleSortOfOptimize(int[] arr) {boolean flag = false; // 标识变量,表示是否进行过交换for (int i = 0; i < arr.length - 1; i++) {for (int j = 0; j < arr.length - i - 1; j++) {if (arr[j] > arr[j + 1]) {flag = true;int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}if(!flag){// 在一趟排序中,一次交换都没有发生过break;}else {flag = false;}}
}

2 选择排序

选择排序和冒泡排序虽然时间复杂度一样,但 选择排序比冒泡排序快。

选择式排序也属于内部排序法,是从欲排序的数据中,按指定的规则选出某一元素,再依规定交换位置后达到排序的目的。

选择排序(select sorting)也是一种简单的排序方法。

它的基本思想是:

第一次从arr[0]~arr[n-1]中选取最小值,与arr[0]交换,

第二次从arr[1]~arr[n-1]中选取最小值,与arr[1]交换,

第三次从arr[2]~arr[n-1]中选取最小值,与arr[2]交换,

…,

第i次从arr[i-1]~arr[n-1]中选取最小值,与arr[i-1]交换,…,

第n-1次从arr[n-2]~arr[n-1]中选取最小值,与arr[n-2]交换

总共通过n-1次,得到一个按排序码从小到大排列的有序序列。

/*** 选择排序(从小到大)* @param arr*/
public static void selectSort(int[] arr) {for (int i = 0; i < arr.length; i++) {int curMinIndex = i;for (int j = i + 1; j < arr.length; j++) {if (arr[j] < arr[curMinIndex]) {curMinIndex = j;}}if (curMinIndex != i) { // 一个小的优化,如果不是当前位置再进行交换int temp = arr[i];arr[i] = arr[curMinIndex];arr[curMinIndex] = temp;}}
}

3 插入排序

插入排序(Insertion Sorting)的基本思想是

把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。

/*** 插入排序(从小到大)* @param arr*/
public static void insertionSort(int[] arr) {for (int i = 1; i < arr.length; i++) {int insertVal = arr[i];// insertIndex表示插入的索引位置int insertIndex = i;for (int j = i; j > 0; j--) {// 如果当前要比较的数小于被比较的数,则被比较的数往右移动一位if (insertVal < arr[j - 1]) {arr[j] = arr[j - 1];insertIndex--;} else {break;}}arr[insertIndex] = insertVal;}
}

插入排序可能存在的问题:

数组 arr = {2,3,4,5,6,1} 这时需要插入的数 1(最小), 这样的过程是:

{2,3,4,5,6,6}

{2,3,4,5,5,6}

{2,3,4,4,5,6}

{2,3,3,4,5,6}

{2,2,3,4,5,6}

{1,2,3,4,5,6}

结论: 当需要插入的数是较小的数时,后移的次数明显增多,对效率有影响.

4 希尔排序

希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。

希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序

希尔排序法基本思想:

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;

随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止

/*** 希尔排序(从小到大)---交换法* @param arr*/
public static void shellSort(int[] arr) {for (int gap = arr.length / 2; gap > 0; gap /= 2) {for (int i = gap; i < arr.length; i++) {// 遍历各组中所有的元素,共gap组,步长gap// 此处类似冒泡排序for (int j = i - gap; j >= 0; j -= gap) {if (arr[j] > arr[j + gap]) {int temp = arr[j];arr[j] = arr[j + gap];arr[j + gap] = temp;}}}}
}

对交换法的改进

希尔排序的移动法(效率有很大提升)

/*** 希尔排序(从小到大)---移动法* @param arr*/
public static void shellSort2(int[] arr) {for (int gap = arr.length / 2; gap > 0; gap /= 2) {// 从第gap个元素,逐个对其所在的组进行直接插入排序for (int i = gap; i < arr.length; i++) {int j = i;int temp = arr[j];if (arr[j] < arr[j - gap]) {// 此处类似插入排序while (j - gap >= 0 && temp < arr[j - gap]) {// 移动arr[j] = arr[j - gap];j -= gap;}// 当退出while,就给temp找到插入的位置arr[j] = temp;}}}
}

5 快速排序

快速排序(Quick Sort)是对冒泡排序的一种改进。

基本思想是:

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

基准值可以选中间那位数,也可以选第一位或者最后一位。

/*** 快速排序,以数组最右侧一位作为基准值* @param arr* @param left* @param right*/
public static void quickSort(int[] arr, int left, int right) {if (right > left) {int pivotVal = arr[right];// 保存最开始的左右值int oriLeft = left, oriRight = right;while (right > left) {// ***以右侧为基准值,则先遍历左侧***// 从左侧开始寻找,直到找到一个比基准值pivotVal大的值为止while (right > left && arr[left] <= pivotVal) {left++;}if (right > left) {// 将这个比基准值pivotVal大的值arr[left],放到右侧arr[right] = arr[left];right--;  // 这个-1操作也可以不要,但是加上的话可以使得下面while循环少判断一次}while (right > left && arr[right] >= pivotVal) {right--;}if (right > left) {arr[left] = arr[right];left++;}}// 当left == right 时,把基准值放回right;// 由于left == right,所以下方的left 和 right表示的值都是一样的arr[right] = pivotVal;quickSort(arr, oriLeft, right - 1);quickSort(arr, left + 1, oriRight);}
}

6 归并排序

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

阶段,需要将两个已经有序的子序列合并成一个有序序列。

比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],

来看下实现步骤:

/*** 归并排序** @param arr   待排序的数组* @param left* @param right* @param temp  临时数组*/
public static void mergeSort(int[] arr, int left, int right, int[] temp) {if (left < right) {int mid = (left + right) / 2;   // 中间索引mergeSort(arr, left, mid, temp);    //向左递归进行分解mergeSort(arr, mid + 1, right, temp);   //向右递归进行分解merge(arr, left, mid, right, temp); // 合并}
}/*** 将两段有序的序列合并成一段有序的序列** @param arr   待排序的数组* @param left  左边有序序列的初始索引* @param mid   中间索引* @param right 右边索引* @param temp  临时数组*/
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {//(1) 第一步,先将左右两块内容已经有序的序列进行逐个对比,合并成一个有序的序列int i = left;   // 左边有序序列的初始索引int j = mid + 1;    // 右边有序序列的初始索引int t = 0;  // 指向temp数组的当前索引while (i <= mid && j <= right) {if (arr[i] < arr[j]) {temp[t] = arr[i];t++;i++;} else {temp[t] = arr[j];t++;j++;}}//(2)第二步,将左右两边剩余的部分放入临时数组while (i <= mid) {temp[t] = arr[i];t++;i++;}while (j <= right) {temp[t] = arr[j];t++;j++;}//(3)第三步,将临时数组temp的元素拷贝到数组arrt = 0;int tempLeft = left;while (tempLeft <= right) {arr[tempLeft] = temp[t];tempLeft++;t++;}
}

7 基数排序

  1. 基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,达到排序的作用
  2. 基数排序法是属于稳定性的排序,基数排序法的是效率高的稳定性排序法
  3. 基数排序(Radix Sort)是桶排序的扩展
  4. 基数排序是1887年赫尔曼·何乐礼发明的。它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较。

基数排序基本思想:

  1. 将所有待比较数值统一为同样的数位长度,数位较短的数前面补零。
  2. 然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

图文解释:

基数排序的说明:

  1. 基数排序是对传统桶排序的扩展,速度很快;
  2. 基数排序是经典的空间换时间的方式,占用内存很大, 当对海量数据排序时,容易造成 OutOfMemoryError
  3. 基数排序时稳定的;
  4. 有负数的数组,一般不用基数排序来进行排序;
  5. 如果要支持负数,参考: https://code.i-harness.com/zh-CN/q/e98fa9
/*** 基数排序** @param arr*/
public static void radixSort(int[] arr) {//(1)找到数组中最大的数的位数int max = arr[0];for (int i = 1; i < arr.length; i++) {if (arr[i] > max)max = arr[i];}// 得到最大数是几位数int maxLength = (max + "").length();for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {// 定义一个二维数组,表示10个桶,每个桶就是一个一位数组// 为了防止在放入数的时候,数据溢出,则每个一位数组(桶),大小定义为arr.lengthint[][] bucket = new int[10][arr.length];// 定义一个数组,用于存储每个桶中的元素数量int[] bucketElementCount = new int[10];for (int j = 0; j < arr.length; j++) {// 取每个元素对应位数的值int digitOfElement = arr[j] / n % 10;bucket[digitOfElement][bucketElementCount[digitOfElement]] = arr[j];bucketElementCount[digitOfElement]++;}// 遍历每个桶内的数据,将数据都取出放入到arr数组int index= 0;for (int j=0;j<bucket.length;j++){for(int k=0;k<bucketElementCount[j];k++){arr[index] = bucket[j][k];index ++;}// 每轮处理后,需要将每个桶中的元素数量置为0bucketElementCount[j] = 0;}}
}

下载地址

7大排序算法详解文档及java代码实现(可直接运行)下载地址:https://download.csdn.net/download/qq_39735940/19005360

7大排序算法详解+java实现相关推荐

  1. 排序算法,最全的10大排序算法详解(Sort Algorithm)

    文章目录 排序算法,最全的10大排序算法详解(Sort Algorithm) 排序算法分类 排序算法稳定性 时间复杂度(time complexity) 1#时间复杂度的意义 2#基本操作执行次数 如 ...

  2. 【Java学习笔记之十一】Java中常用的8大排序算法详解总结

    分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配排序(基数排序) 所需辅助空间最多:归并排序 所需辅助空 ...

  3. ❤️十大排序算法详解❤️——可能是你看过最全的,完整版代码

    文章目录 前言 交集排序 冒泡 简单 快速排序 插入排序 直接插入排序 希尔排序 选择排序 简单选择排序 堆排序 归并排序 二路 多路 非比较类 计数排序 桶排序 基数排序 最后 前言 兄弟们,应上篇 ...

  4. 十大排序算法详解(二)归并排序、堆排序、计数排序、桶排序、基数排序

    文章目录 一.归并排序 1.1 归并排序基础[必会知识] 1.1.1 递归实现 1.1.2 非递归实现 1.2 归并排序优化 1.2.1 小数组使用插入排序 1.2.2 避免多余比较 1.2.3 节省 ...

  5. 十大排序算法详解(一)冒泡排序、选择排序、插入排序、快速排序、希尔排序

    文章目录 一.冒泡排序 1.1 冒泡排序基础[必会知识] 1.2 冒泡排序优化 1.2.1 外循环优化 1.2.2 内循环优化 1.2.3 双向遍历 1.3 冒泡排序的稳定性.复杂度和适用场景 1.3 ...

  6. 十大经典排序算法详解(三)-堆排序,计数排序,桶排序,基数排序

    养成习惯,先赞后看!!! 你的点赞与关注真的对我非常有帮助.如果可以的话,动动手指,一键三连吧!!! 十大经典排序算法-堆排序,计数排序,桶排序,基数排序 前言 这是十大经典排序算法详解的最后一篇了. ...

  7. 十大经典排序算法-桶排序算法详解

    十大经典排序算法 十大经典排序算法-冒泡排序算法详解 十大经典排序算法-选择排序算法详解 十大经典排序算法-插入排序算法详解 十大经典排序算法-希尔排序算法详解 十大经典排序算法-快速排序算法详解 十 ...

  8. 十大经典排序算法-选择排序算法详解

    十大经典排序算法 十大经典排序算法-冒泡排序算法详解 十大经典排序算法-选择排序算法详解 十大经典排序算法-插入排序算法详解 十大经典排序算法-希尔排序算法详解 十大经典排序算法-快速排序算法详解 十 ...

  9. 十大经典排序算法详解

    本文转自 <卢明冬的博客> 文章目录 排序算法的分析和评价 2.十大排序经典算法总览 2.1 排序算法的分类 2.2 排序算法的性能 2.3 各阶复杂度性能对比 2.4 排序算法的初始状态 ...

最新文章

  1. Spring MVC与表单日期提交的问题
  2. SpringBoot之二:部署Spring Boot应用程序方式
  3. 重写StyleSheetTheme
  4. 你有一笔新订单 语音_上市即成爆款 哪吒V首日订单突破1200辆_搜狐汽车
  5. 如果你还在徘徊在程序员的门口,那就赶紧来看看!
  6. Java工作笔记-使用Maven创建Spring Boot并生成war包外部tocamt运行
  7. mac 上brew加速
  8. openstack常用运维命令_OpenStack运维指南pdf
  9. JavaScript和jQuery的DOM操作
  10. html中meta的设置
  11. 30 校准_机会难得校准实验室认可培训别再错过
  12. C# DirectX.AudioVideoPlayback音频视频播放
  13. 2018年马哥Linux
  14. linux vi 排序命令,10 个你必须掌握的超酷 VI 命令技巧
  15. MapReduce 基础案例 之 平均值 计算
  16. ANDROID_MARS学习笔记_S04_004_用HTTPCLENT发带参数的get和post请求
  17. 汽车技术管理系统c语言,[源码和文档分享]基于C语言实现的汽车牌照的快速查询...
  18. 主动学习(Active Learning)概述及最新研究
  19. (OJ)Java多线程-子弹射击
  20. Bootstrap级联下拉菜单,你肯定用得到

热门文章

  1. Python使用exec自动生成代码并执行,同时得到返回的变量
  2. 使用LDA模型对新的文档进行分类
  3. python读取一个目录下的文件名(不会递归往下读)
  4. xamppmysql访问被拒绝_XAMPP中无法开始MySQL的问题
  5. log4j 禁止类输出日志_springboot日志详解
  6. k8s kubectl生成kube-config文件
  7. 腾讯这套SpringMvc面试题你了解多少?(面试必备)
  8. java和js实现电话号码部分隐藏
  9. 修改一个CGRect的值
  10. python队列来做什么_简单介绍python的双向队列