排序算法分为一般排序和高级排序,高级排序算法往往效率超高,除此之外,排序算法的稳定性也是可参考的一个指标之一。

一般排序算法

一、冒泡排序
  • 算法代码实现
#include "stdio.h"#define MAXSIZE 13void change(int nums[], int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;
}int main() {int nums[] = {10, 31, 22, 7, 83, 69, 112, 12, 53, 29, 88, 200, 1};//冒泡排序,外层循环每次是数组的长度减1for (int i = MAXSIZE - 1; i > 0; i--) {//内层循环,每次是从0到i处的元素进行排序for (int j = 0; j < i; ++j) {int d1 = nums[j];int d2 = nums[j + 1];if (d1 > d2) {change(nums, j, j + 1);}}}for (int i = 0; i < MAXSIZE; ++i) {printf(" %d , ", nums[i]);}return 0;
}

冒泡排序每一轮都需要将当前元素与下一个元素相比较,如果大于,则交换位置,在一轮排序完成后,可以保证最大数已经排在最后面了,n个数,进行n-1轮排序即可把全部元素排序完成。

  • 复杂度

冒泡排序的算法时间复杂度为 o(n2)

  • 稳定性

冒泡排序是稳定的

二、插入排序
  • 算法代码实现
public class InsertSort extends BaseSort{public static void main(String[] args) {int[] nums = InitData.getInitData();//外层循环依次递增,每进行一次外层循环,前i个数就是默认排好序的for (int i = 1; i < nums.length; i++) {//内层循环从i开始,依次与见面的数进行比较,一直比较到第一个大于当前元素为止for (int j = i; j > 0 ; j--) {int d1 = nums[j - 1];int d2 = nums[j];if (d2 < d1){change(nums,j,j-1);}else break;}}System.out.println(Arrays.toString(nums));}}

插入排序默认待插入元素为止之前的元素是已经排好序的,所以只要遇到比待插入元素小的元素即可跳出循环。

  • 复杂度

插入排序的算法最好时间复杂度是o(n),这种情况下是所有元素本来就是有序的,无需进行排序。

最坏时间复杂度为 o(n2),所有元素是逆序时。

平均时间复杂度为 o(n2)。

  • 稳定性

插入排序算法也是稳定的。

三、选择排序
  • 选择排序的代码实现
/**选择排序:选择排序的时间复杂度是o(n2),且是一种不稳定的排序算法, 7 19 28 19 16 23*/
public class SelectionSort extends BaseSort{public static void main(String[] args) {int[] initData = InitData.getInitData();//外层循环每一次遍历,都把当前下标处的元素当成是最小的,然后依次往后比较,查看是否还有比当前下标元素小的for (int i = 0; i < initData.length; i++) {int minIndex = i;for (int j = i + 1; j < initData.length; j++) {//比较j处是否大于minIndex处,如果小于则交换if (initData[j] < initData[minIndex]){minIndex = j;}}if (minIndex != i){//交换位置change(initData,minIndex,i);}}System.out.println(Arrays.toString(initData));}}

选择排序是每次把待排序的元素看作是最小元素,依次往后遍历,如果有小于当前元素的,则交换下标。

  • 复杂度

选择排序的时间复杂度是o(n2)

  • 稳定性

选择排序不是一种稳定排序算法。

高级排序

一、希尔排序
  • 希尔排序算法代码实现
/**希尔排序:高级排序希尔排序是一种高级排序,也可以看作是插入排序的升级版*/
public class ShellSort extends BaseSort{public static void main(String[] args) {int[] nums = InitData.getInitData();/*希尔排序先将待排序的数组通过增量使得变成一个比较优的插入排序,即大部分元素是有序的。希尔排序中提出了增量的概念,增量可以理解把待排序的数组分为增量个组,每组内的元素进行排序每一次增量变化,都会把所有元素排序一遍*///1.确定增量,默认是值是数组长度 / 2int step = nums.length / 2;//step为1时,所有元素都在一个组里了,无需再继续排序while (step > 0){for (int i = step; i < nums.length; i++) {//最多比较到当前组整数第1个元素即可for (int j = i ; j >= step ; j = j - step) {//与该组内前一个元素比较int d1 = nums[j - step];int d2 = nums[j];//如果待插入的元素比前一个元素大,则跳出循环,否则交换位置if (d2 < d1){change(nums,j,j - step);}else break;}}step = step / 2;}System.out.println(Arrays.toString(nums));}}

希尔排序的目的就是最终构建出一个比较优的插入排序,也就是说当数组中大部分元素都是有序的时候,此时只需要移动少量元素即可完成整个数组的排序。如何让一个数组变成比较优的待插入排序数组?希尔排序中引入了增量的概念,每次插入都需要根据当前增量来排序,增量把待排序的数据分为多少组,若增量为6,那么就分为了6个组,然后每个组内的元素进行排序,元素每次都是和 减增量个元素进行比较,当增量变为1时,其实就是一个纯粹的插入排序了,只不过由于前面的分组排序,此时已经被优化成一个比较优的插入排序数组了,希尔排序就是一个插入排序,只不过插入排序中,初始时从第1个开始比较,然后内存循环依次与前 1 个元素进行比较,比较后 减 1 ,我们把1的位置换成当前的增量,每做一个插入排序,增量就 / 2,一直到1。

  • 复杂度

希尔排序的算法复杂度证明过程极为复杂,最好时的复杂度为 o(n)。

  • 稳定性

希尔排序不是一种稳定排序算法。

二、归并排序
  • 归并排序算法代码实现
/*归并排序:分治思想,将数组的每个元素依次拆分到只有一个时,再进行合并,合并时排序
*/
public class MergeSort extends BaseSort{//辅助数组private static int[] assists;public static void sort(int[] nums){assists = new int[nums.length];int lo = 0;int hi = nums.length - 1;sort(nums,lo,hi);}//对nums数组进行拆分,每次都拆分成一半,如果hi <= lo 了,则不进行拆分private static void sort(int[] nums, int lo, int hi) {if (hi <= lo){return;}int mid = (lo + hi) / 2;sort(nums,lo,mid);sort(nums,mid + 1,hi);//执行到这里开始合并merge(nums,lo,mid,hi);}//将数据分为两组 lo-mid为一组,mid+1-hi为一组,对两组数据进行合并,合并时排序private static void merge(int[] nums, int lo, int mid, int hi) {int i = lo;//辅助数组的起始指针int p1 = lo;//第一组的起始指针int p2 = mid + 1;//第二组的起始指针while (p1 <= mid && p2 <= hi){//分别对比p1与p2哪个大if (nums[p1] > nums[p2]){assists[i++] = nums[p2++];}else {assists[i++] = nums[p1++];}}//如果其中一个数组填充完成,则只需把另一个复制即可while (p1 <= mid){assists[i++] = nums[p1++];}while (p2 <= hi){assists[i++] = nums[p2++];}//拷贝到原数组for (int j = lo; j <= hi; j++) {nums[j] = assists[j];}}public static void main(String[] args) {int[] initData = InitData.getInitData();sort(initData);System.out.println(Arrays.toString(initData));}}

归并排序是一种分治思想,将待排序的数组两两拆分,一直拆分到每组只剩一个元素后开始合并,在合并的时候排序,归并排序的实现需要用到一个辅助数组。

  • 复杂度

归并排序的算法时间复杂度是o(nlog2n);

  • 稳定性

归并排序是一种稳定排序算法。

三、快速排序
  • 快速排序算法代码实现
/**快速排序:快速排序也是一种分治思想,每次都选定一个数,且把大于这个数的移动到右边,小于这个数的移动到左边直到每组剩余一个数*/
public class QuickSort extends BaseSort{public static void sort(int [] nums){int lo = 0;int hi = nums.length - 1;//快速排序sort(nums,lo,hi);}private static void sort(int[] nums, int lo, int hi) {if (hi <= lo){return;}//计算分区int partition = partition(nums,lo,hi);//得到分区下标后,继续拆分sort(nums,lo,partition);sort(nums,partition+1,hi);}private static int partition(int[] nums, int lo, int hi) {//选取一个元素int element = nums[lo]; //比element大的往右排,比element小的往左排while (lo < hi){//移动右指针,直到遇到比element小的while (lo < hi && nums[hi] >= element){hi--;}//lo处的元素等于hi处的元素nums[lo] = nums[hi];//移动左指针,直到遇到比element大的while (lo < hi && nums[lo] <= element){lo++;}nums[hi] = nums[lo];}nums[lo] = element;return lo; //此时element的左侧是比自己小的,右侧是比自己大的}public static void main(String[] args) {int[] initData = InitData.getInitData();sort(initData);System.out.println(Arrays.toString(initData));}}

快速排序也是一种分治思想,从待排序的数组中选出一个值,然后定义两个指针,依次从数组开始与末尾进行扫描,将比选出的值大的元素移动到右边,比选中的值小的移动到左边,依次递归,直到每组元素都剩余1个为止。

  • 复杂度

快速排序的时间复杂度是 o(nlog2n)

  • 稳定性

快速排序不是一种稳定的排序算法

四、堆排序
  • 堆排序算法代码实现
/**堆排序:首先将一个数组构建成一个堆,然后依次将堆的第一个元素与最后一个元素交换位置,length--然后在将下标为1的元素下沉,此时继续执行以上操作,直到length为1*/
public class HeapSort extends BaseSort {public static void sort(int[] nums){int[] data = new int[nums.length + 1];for (int i = 0; i < nums.length; i++) {data[i + 1] = nums[i];}int mid = nums.length / 2;int length = nums.length;for (int i = mid; i > 0 ; i--) {sinkElement(data,i,length);}for (int i = length; i > 0; i--) {change(data,1,length);length--;//将下标1处的元素下沉sinkElement(data,1,length);}//拷贝回原数组for (int i = 0; i < nums.length; i++) {nums[i] = data[i + 1];}}private static void sinkElement(int[] nums, int index, int length) {//判断index处是否有子节点while (index * 2 <= length){int maxIndex = index * 2;if (maxIndex + 1 <= length){//如果index * 2 + 1也小于等于length,说明还有右节点,此时需要比较左节点和右节点的大小if (nums[maxIndex + 1] > nums[maxIndex] ){maxIndex = maxIndex + 1;}}//判断是否比最大的那个子节点大,如果小于则交换,如果大于,则不用交换if (nums[index] < nums[maxIndex]){change(nums,index,maxIndex);}else break;index = maxIndex;//index等于较大子节点那个位置,如果还有子节点,继续比较}}public static void main(String[] args) {int[] initData = InitData.getInitData();sort(initData);System.out.println(Arrays.toString(initData));}}

使用堆排序要理解堆数据结构,和二叉树相似,只不过根节点是大于等于左右节点,或者是根节点小于等于左右节点,在排序时先将待排序数组转换为堆,再依次删除堆的第一个元素。

  • 复杂度

堆排序的算法时间复杂度为o(nlog2n)

  • 稳定性

堆排序不是一种稳定的排序算法 。

五、基数排序

上述排序算法主要是比较的关键字,而基数排序是将每个关键字分组,然后依次比较。例如有10000个学生,出生年月在1991-2005之前,按照出生年月排序。此时可以将关键字分组,分为3组(年,月,日) (d),年的取值范围是1991-2005,月的取值范围是 01-12 ,而日的取值范围是 01-31,取最大的范围就是31,31就是r的取值范围。

  • 复杂度

基数排序的算法时间复杂度是o(d(n+r)),以上述为例,n=10000,d是每个关键字的分组的个数,d = 3,r就是每个分组的取值范围
r = 31 ,o(d(n+r)) = 3(10000+31) 。

  • 稳定性

基数排序是一种稳定的排序算法(基你太稳)。

稳定的排序算法

基数排序、归并排序、冒泡排序、插入排序

不稳定的排序算法

堆排序、快速排序、希尔排序、选择排序

常用的排序算法的时间复杂度以及稳定性相关推荐

  1. 常用的排序算法的时间复杂度和空间复杂度

    常用的排序算法的时间复杂度和空间复杂度                                           1.时间复杂度 (1)时间频度 一个算法执行所耗费的时间,从理论上是不能算出 ...

  2. 常用的排序算法的时间复杂度和空间复杂度 .

    常用的排序算法的时间复杂度和空间复杂度 排序法 最差时间分析 平均时间复杂度 稳定度 空间复杂度 冒泡排序 O(n2) O(n2) 稳定 O(1) 快速排序 O(n2) O(n*log2n) 不稳定 ...

  3. 各个排序算法的时间复杂度、稳定性、快排的原理以及图解

    目录 一.数据结构的八大排序算法总结笔记: 1.常见的数据结构排序算法如下图所示: 2.常见数据结构排序算法的时间复杂度.空间复杂度.稳定性介绍如下图所示: 二.排序算法逐一介绍: 1.直接插入排序: ...

  4. 常用排序算法的时间复杂度和稳定性

    如题,见图 名词解释: 1)稳定:如果 a原本在 b前面,而 a=b,排序之后 a仍然在 b的前面: 2)不稳定:如果 a原本在 b的前面,而 a=b,排序之后 a可能会出现在 b的后面: 3)内排序 ...

  5. 各个排序算法的时间复杂度和稳定性,快排的原理

                         //联系人:石虎 QQ:1224614774 昵称:嗡嘛呢叭咪哄                                QQ群:807236138  ...

  6. 各种常用排序算法的时间复杂度和空间复杂度

    https://blog.csdn.net/jiajing_guo/article/details/69388331 一.常用排序算法的时间复杂度和空间复杂度表格 二.特点 1.归并排序: (1)n大 ...

  7. c语言验证完成排序算法的时间,排序算法的时间复杂度和空间复杂度

    常用的内部排序方法有:交换排序(冒泡排序.快速排序).选择排序(简单选择排序.堆排序).插入排序(直接插入排序.希尔排序).归并排序.基数排序(一关键字.多关键字). 一.冒泡排序: 1.基本思想: ...

  8. 各个排序算法及其时间复杂度

    各个排序算法及其时间复杂度 一.内部排序: 1.稳定的排序算法 1.1 冒泡排序 1.1.1 冒泡排序流程 1.1.2 冒泡排序的实现 1.2 插入排序 1.2.1 插入排序流程 1.2.2 插入排序 ...

  9. 各种排序算法的时间复杂度对比

    各种排序算法的时间复杂度对比 排序算法 最坏时间复杂度 平均时间复杂度 最优时间复杂度 空间复杂度 稳定性 冒泡排序 O(n^2) O(n^2) O(n) O(1) 稳定 插入排序 O(n^2) O( ...

最新文章

  1. 2019第十届蓝桥杯C/C++ B组省赛 —— 第三题:数列求值
  2. linux生成固定大小的文件夹的实现
  3. azure不支持哪些语句 sql_排查 Azure SQL 数据库的常见连接问题 - Azure SQL Database | Microsoft Docs...
  4. 好用到爆!轻松获取PNG透明图片!
  5. 用友加密狗显示停止服务器,插上加密狗打开用友,显示下图,请问如何解决问题...
  6. HUT-XXXX Strange display 容斥定理,线性规划
  7. clr错误 8004005程序将立即终止_微软公开发布更多Surface驱动程序 固件支持终止日期...
  8. Gym - 102163M
  9. Oracle表连接方式总结
  10. 来自吉普赛人祖传的神奇读心术.它能测算出你的内心感应
  11. 超级漂亮炫酷的HTML菜单栏导航栏+网站+独特二级列表
  12. 医学图像分割之肝脏分割(2D)
  13. R语言中创建股票走势图
  14. RAD Studio 10.4 for delphi XE Assigned和Nil的联系与区别
  15. 淘宝爬虫实战(附代码和数据集)——今天你脱发了吗?
  16. $.each()的理解
  17. Java实现蓝桥杯模拟约数的个数
  18. Elasticsearch快速检索之倒排索引算法
  19. python一只青蛙一次可以_python算法题 python123网站单元四题目
  20. eCharts 自定义y轴数据

热门文章

  1. 传说,倾尽天下,往事回首
  2. 一点一点学习C++之笔记004
  3. sublime 3 编辑器
  4. 牛叉的装饰器,带参数语法糖
  5. 总结了一下如何使用gitbook生成本地 静态HTML电子书
  6. Android 8.0 PictureInPicture 画中画模式分析与使用
  7. 编译原理学习笔记:字母表上的运算(乘积、n次幂、正闭包、克林闭包)、串上的运算(连接、幂)
  8. PHP 和java 的 对比
  9. 在自己的服务器上部署 GitLab 社区版
  10. 计算机网络的课程ppt,ppt课件-计算机网络课程.ppt