今天分享的是三种排序算法,在面试、实际编程中经常会碰到和使用到的,我会带领大家从分析排序算法技巧上以及代码实现上全面理解这一知识点的掌握。

一、如何分析一个「排序算法」

1. 执行效率

① 最好、最坏、平均时间复杂度

在分析算法的好坏时,要分别说出最好、最坏、平均时间复杂度的同时,也要说出最好、最坏时间复杂度对应排序的原始数据是什么样的。

② 复杂度系数、常数、低阶

时间复杂度反应的是数据规模 n 很大的时候的一个增长趋势,它表示的时候会忽略系数、常数、低阶 ,小规模数据除外。

③ 比较次数和移动次数

基于比较的排序算法,在分析算法效率时,我们要考虑到元素的比较和元素的移动。

2. 内存消耗

算法的内存消耗可以通过空间复杂度来衡量,排序算法也不例外。我们引用一个名词叫做「原地排序」,就是指特定空间复杂度是 O(1) 的排序算法。

3. 稳定性

如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变,就叫做「稳定排序」。

二、冒泡排序

1、算法思想

每次冒泡对相邻的两个元素进行比较,看是否满足大小关系,不满足就进行互换,一次冒泡会让至少一个元素移动到它应该在的位置。有 n 个数据,需要重复 n 次。

2、算法优化

当某次冒泡过程已经没有数据交换时,说明已经达到完全有序,不用再执行后续的冒泡操作。

3、代码实现


1// 冒泡排序,a 表示数组,n 表示数组大小
2public void bubbleSort(int[] a, int n) {
3 if (n <= 1) return;
4
5 for (int i = 0; i < n; ++i) {
6 // 提前退出冒泡循环的标志位
7 boolean flag = false;
8 for (int j = 0; j < n - i - 1; ++j) {
9 if (a[j] > a[j+1]) { // 交换
10 int tmp = a[j];
11 a[j] = a[j+1];
12 a[j+1] = tmp;
13 flag = true; // 表示有数据交换
14 }
15 }
16 if (!flag) break; // 没有数据交换,提前退出
17 }
18}

4、问题思考

①是否为原地排序

冒泡的过程只涉及相邻数据的交换操作,只需要常量级的临时空间,所以它的空间复杂度为 O(1),是一个原地排序算法。

②是否为稳定排序

在冒泡排序中,只有交换才可以改变两个元素的前后顺序。为了保证冒泡排序算法的稳定性,当有相邻的两个元素大小相等的时候,我们不做交换,相同大小的数据在排序前后不会改变顺序,所以冒泡排序是稳定的排序算法。

③最好、最坏以及平均时间复杂度

最好的情况是数据已经排好序,我们只进行一次冒泡排序就可以了,最好时间复杂度为 O(n) 。最坏的情况是,要排序的数据刚好是倒序排列的,我们只进行 n 此冒泡操作,所以最坏的时间复杂度为 O(n²),平均时间复杂度为 O(n²)。

三、插入排序(Insertion Sort)

1、算法思想

我们将元素分为两个区间,未排序区间和已排序区间。我们要做的就是在未排序区间取出元素与已排序区间元素进行比较插入到适当位置,以此类推,直到未排序区间元素为空为止(顺序为从后向前比较


2、代码实现


1// 插入排序,a 表示数组,n 表示数组大小(从小到大进行排序)
2public void insertionSort(int[] a, int n) {
3 //如果数组大小为 1 直接返回
4 if (n <= 1) return;
5 //否则进行插入排序
6 for (int i = 1; i < n; ++i) {
7 int value = a[i];
8 int j = i - 1;
9 // 查找插入的位置
10 for (; j >= 0; --j) {
11 if (a[j] > value) {
12 a[j+1] = a[j]; // 数据移动
13 } else {
14 break;
15 }
16 }
17 a[j+1] = value; // 插入数据
18 }
19}

3、问题思考

① 是否为原地排序?

答:插入排序的运算并不需要额外的存储空间,所以空间复杂度是 O(1),是一个原地排序算法。

② 是否为稳定排序?

答:在插入排序中,对于值相同的元素,我们会将后边出现的元素插入到前边出现的元素的后边,所以插入排序是稳定排序。

③ 最好、最坏、平均时间复杂度?

答:

最好的情况就是数据元素已经排好序,最好的时间复杂度为 O(1) ,

如果数组是倒序的,每次插入都相当于在数组的第一个位置插入新的数据,需要移动大量的数据,最坏的时间复杂度是 O(n²)。

我们在数组中插入数据的平均时间复杂度为 O(n),对于插入排序来说我们每次就相当于数组插入一个新的数据,循环执行n次插入数据,所以平均时间复杂度为 O(n²)。

四、选择排序

1、算法思想

和插入排序有点相似,将在未排序期间寻找到最小的数据,并将其放到已排好区间的元素的尾部。

2、问题思考

① 是否为原地排序

因为,数组中的两个元素需要相互交换,需要用一个变量来存储交换值,选择排序的空间复杂度为O(1),所以,是一种原地排序算法。

② 是否为稳定排序

选择排序每次都要找到剩余未排序元素的最小值,并和前边的元素交换位置,这样破坏了稳定性。所以说,选择排序是一种不稳定的排序算法。

③ 最好、最坏以及平均时间复杂度

选择排序的最好情况就是已经是一组有序数据,最好的时间复杂度为 O(1),最坏的情况就是 O(n²)。平均时间复杂度就是 O(n²)。

3、代码实现


1// 选择排序,a表示数组,n表示数组大小
2 public static void selectionSort(int[] a, int n) {
3 if (n <= 1) return;
4 for (int i = 0; i < n; ++i) {
5 // 查找最小值
6 int minIndex = i;
7 int minValue = a[i];
8 for (int j = i; j < n; ++j) {
9 if (a[j] < minValue) {
10 minValue = a[j];
11 for (int i = 0; i < n - 1; ++i) {
12 // 查找最小值
13 int minIndex = i;
14 for (int j = i + 1; j < n; ++j) {
15 if (a[j] < a[minIndex]) {
16 minIndex = j;
17 }
18 }
19 if (minIndex == i)
20 continue;
21 // 交换
22 int tmp = a[i];
23 a[i] = a[minIndex];
24 a[minIndex] = tmp;
25 }
26 }

五、实际应用中为什么插入排序应用最为广泛

冒泡排序不管怎么优化,元素交换的次数是一个固定值,是原始数据的逆序度。插入排序是同样的,不管怎么优化,元素移动的次数也等于原始数据的逆序度。

从代码实现上来看,冒泡排序的数据交换要比插入排序的数据移动要复杂,冒泡排序需要 3 个赋值操作,而插入排序只需要 1 个。


1冒泡排序中数据的交换操作:
2if (a[j] > a[j+1]) { // 交换
3 int tmp = a[j];
4 a[j] = a[j+1];
5 a[j+1] = tmp;
6 flag = true;
7}
8
9插入排序中数据的移动操作:
10if (a[j] > value) {
11 a[j+1] = a[j]; // 数据移动
12} else {
13 break;
14}

有兴趣的小伙伴可以编几个数据自己测试一下。

虽然冒泡排序和插入排序在在时间复杂度上是一样的,都是 O(n²),我们希望把性能优化做到极致,首选插入排序。

六、重点掌握

今天重点掌握的内容是三种排序的「分析方法」,不必要死记硬背。另一个方面就是实际应用中用到最多就是「插入排序」。

原文发布时间为:2018-11-14

本文作者:不甘平凡的码农

本文来自云栖社区合作伙伴“Web项目聚集地”,了解相关信息可以关注“Web项目聚集地”。

面试前你必须知道的三个排序算法相关推荐

  1. Java学习 第三章 数组(三)排序算法

    ** Java学习 第三章 数组(三)排序算法 ** 主要内容:排序算法.排序算法横向比较.Arrays工具类的使用.数组常见异常 1.数组中涉及到的常见算法:排序算法 1.1 排序算法分类:内部排序 ...

  2. c++ 不插入重复元素但也不排序_面试官爱问的 10 大经典排序算法,20+ 张图来搞定...

    (给算法爱好者加星标,修炼编程内功) 作者:技术让梦想更伟大 / 李肖遥 (本文来自作者投稿) 冒泡排序 简介 冒泡排序是因为越小的元素会经由交换以升序或降序的方式慢慢浮到数列的顶端,就如同碳酸饮料中 ...

  3. 面试官爱问的10大经典排序算法,20+张图来搞定

    冒泡排序 简介 冒泡排序是因为越小的元素会经由交换以升序或降序的方式慢慢浮到数列的顶端,就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名冒泡排序. 复杂度与稳定性 思路原理 以顺序为例 从第一 ...

  4. 死磕算法第三弹——排序算法(1)

    本文整理来源 <轻松学算法--互联网算法面试宝典>/赵烨 编著 算法基础 对于算法性能分析来说,除了时间复杂度,还是有空间复杂度.稳定性等指标.而我们平时说的算法的复杂度可以分为两个部分: ...

  5. 死磕算法第三弹——排序算法(2)

    本文整理来源 <轻松学算法--互联网算法面试宝典>/赵烨 编著 插入排序 什么是插入排序 插入排序分为两种,一种是直接插入排序,一种是二分法插入排序.这两种排序实际上都是插入排序,唯一的不 ...

  6. (面经总结)一篇文章带你整理面试过程中常考的九大排序算法

    文章目录 一.二分插入排序 1. 原理 2. 代码 二.冒泡排序 1. 原理 2. 代码 三.插入排序算法 1. 原理 2. 代码 四.快速排序算法 1. 原理 2. 代码 五.希尔排序 1. 原理 ...

  7. 【算法三】排序算法之冒泡排序

    冒泡排序(Bubble Sort):是一种简单的排序算法,也是一种稳定的排序算法.其实现原理是:依次比较两个相邻的元素,当该对元素顺序不正确时就进行交换,从左到右一轮遍历得到一个最值:重复此步骤,直到 ...

  8. 算法面试经常需要你手写的三个排序算法(Python语言)

    作者 | 程序员小吴 来源 | 五分钟学算法(ID: CXYxiaowu) 1. 归并排序 1.1 算法步骤 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列: 设定两个指针,最初 ...

  9. 面试前,一定要准备好这三件重要的事

    不知道大家在参加面试的时候是否会提前做一些面试前准备功课,我接触了很多面试者,有面试前准备的,也有没有做任何准备,看现场发挥的.根据接触的大多数人的面试情况来看,有很大一部分人的面试经验还没有丰富到可 ...

最新文章

  1. 病理分析常见数据集及常用模型方法总结
  2. 我们离得开美国的软件和硬件吗?
  3. 使用ISA Server发布具有Edge角色的Exchange Server环境
  4. Spring Autowire自动装配
  5. 自动转换开关(ATS)在数据中心配电系统中的应用
  6. OpenStack部署笔记和安装WindowsXP镜像
  7. python函数拟合不规则曲线_python曲线拟合
  8. python图片读取优化_python读取raw binary图片并提取统计信息的实例
  9. 【codeforces 103E】 Buying Sets
  10. Python3 使用requests请求,解码时出错:'utf8' codec can't decode byte 0x8b in position 1: invalid start byte...
  11. 懂分析、会预测,你见过这样的华为云DAS吗?
  12. 【转】VC动态内存分配PPT
  13. 在双屏软件中,PPT自定义动画注意事项
  14. android3种播放视频方式,Android 两种方式播放视频
  15. YACC(BISON)使用指南
  16. 大数据应用案例---用户画像与精准营销
  17. android之LitePal 3.0 的基本使用
  18. 参加电子工业出版社博文视点举办的作者高峰论坛有感
  19. Twitter OAuth1.0认证过程
  20. oracle创建用户并授权管理员,Oracle创建用户并授权【数据库】

热门文章

  1. Chrome_调试js出现Uncaught SyntaxError: Unexpected identifier
  2. Java编译那些事儿【转】
  3. 基于TCP(面向连接)的Socket编程
  4. CSS那些事笔记(一入门)
  5. visual studio 自动整理代码
  6. Python学习教程(Python学习视频_Python学些路线):Day05 总结和练习
  7. 【智力题】国际象棋问题
  8. 《编程导论(Java)#183;1.4.1 范式》
  9. 公众号24小时自动吸粉秘密!一次推广终身有客户
  10. Apache启动报错