- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 565733 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174943
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
动画:面试官问我插入排序和冒泡排序哪个更牛逼?
: x( |" { n. O, M
. y& c4 a6 a) D写在前边
: g& Q3 `4 ?0 f8 S9 y, ~7 _3 W" g: D4 H# N3 x7 f' i
1 N: l: R! G1 c& }0 x排序对于每个开发者来讲,都多多少少知道几个经典的排序算法,比如我们之前以动画形式分享的冒泡排序,也包括今天要分享的插入排序。还有一些其他经典的排序,小鹿整理的共有十种是面试常问到的,冒泡排序、插入排序、希尔排序、选择排序、归并排序、快速排序、堆排序、桶排序、计数排序、基数排序。
5 X+ b; s Q7 d* W! F. Z. K+ A3 j( i/ n6 M2 }, |% V! w7 v+ K
虽然我们基本知道了这些排序算法,但是在实际项目开发以及面试中往往出乎我们所料。在面试中,经常会被问到各种排序之间的比较;在实际项目中,往往排序的数据不是我们所练习的整数。
& r. D0 ], T. ~2 T5 N# D# V" y$ K' L" z0 X) r" g& m$ n: a
那么今天我们来学习一下,插入排序比我们之前讲的冒泡排序有什么区别呢?面试官问我们,我们如何回答完整呢?6 R+ ^9 k$ I( d |& Q# W
* C$ @2 g$ ^2 s" Z" a) N2 {思维导图0 m4 C4 b& q5 z3 X4 ?( G
7 t+ i% [) ~7 I
) d: |) H! Z/ s/ ~; F3 c: T9 k
( s [/ B* ?% O: R1 |# e _4 ]+ D3 q( D- d! D% V4 W- a
14 s2 I7 h4 g+ d) `
, T c% [! D% g0 k( Z, t% Z1 ~如何分析一个排序算法?$ N- _. ]/ }2 e
, P v. K7 X2 W5 }之前写的一篇很详细的文章。
3 i4 j7 z3 }8 V8 e/ \: v# h7 E! B+ d( b/ \
佩奇学编程 | 复杂度分析原来这么简单
8 D2 c# C& e/ O$ I5 O$ _0 C9 Y. z$ v& i
& b) ?! _& Z/ l7 N N分析排序算法已经成为我们衡量一个算法优良的重要标准,从以下三个方面入手。
6 L& U. H' M( ?1 t- w: z
" d4 t9 C4 [8 R1.1 时间效率
" A6 w6 F; N+ F* E7 L$ M4 f( q( ?2 n s4 k9 t
这里所谓的实践效率就是时间复杂度,相信大家对于时间复杂度并不陌生。9 E) E( |: H6 K
7 V3 R8 Z6 c$ U/ ^( B复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系。1 l5 P" U$ C! F# \
2 y; `: A/ ?: y$ y$ e
对于时间复杂度的分析,要把最好时间复杂度、最坏时间复杂度、平均时间复杂度分析出来,分别对应了排序算法的最好排序情况、最坏排序情况以及平均排序效率。, S i) \4 i$ c7 i
# \. a8 E) p+ g% J; H( a2 H1.2 空间消耗* ]9 a2 j+ s; V! H: O! H% c ~ K
/ M w7 V$ t/ A D
所谓的空间消耗对应的是空间复杂度,在排序算法中需要开辟的额外内存空间是多少。如果空间复杂度为 O(1),此时该排序叫做原地排序。
" x" V$ @: b, g5 }8 e+ ?6 g6 ]9 h- ~1 ^6 s# v6 D
注意:是额外的内存空间,存储排序数据消耗的空间不计。1 ?! F. U+ V0 X0 D7 k1 J' h" f
5 i% D2 K& E! r' o m. j
1.3 稳定性7 B% V+ I! N1 v+ W# x
- {' Y& E% [5 z8 T算法的稳定性虽然我们之前接触的很少,但是稳定性也是衡量一个排序算法的重要标准。什么是稳定排序呢?比如有一组有重复待排序的数据,排序前后,重复的数据顺序不变,此时该排序为稳定排序。否则,叫做不稳定排序。它在实际应用中非常重要的,今天我们就不多说,以后会慢慢分享到。+ `8 I2 r. w+ [/ I
& d4 X% x" N% b9 L3 J
2
7 C/ g" E) p0 W) @' D
$ J7 a' [$ Y3 R, [) i什么是插入排序?
" u! ]5 ~9 s. x" r. t9 ^4 B' k4 j1 y' Z& V6 C7 G
顾名思义,插入排序就是通过插入的方式来排序呗,最经典的就是打斗地主,可以将打乱的扑克牌作为未排序区间,手中已经排好序的作为排序区间。每次我们摸牌的过程,就是从未排序区间,通过插入的方式,插入到已排序区间。那么这个过程就称为插入排序。
! y* V" a! y; {* [9 R
; Z+ p( T; s/ L j+ q% \, s& |" d! H5 m0 f4 _ p* L
3 C* ^: Y, Q+ Z% x3
( `2 \* U0 u! K+ @3 Z6 R: d% r8 o: ?3 P3 ?( y. m* K# M1 S( S& X ]
如何实现插入排序?
, \4 _8 a, Q( d' X' I8 S p% Z1 G
! p! v9 b4 k1 h7 q, O& q上述插入排序的概念我们已经理解了,那么给你一组数据,如何来进行插入排序呢?
3 \% J0 r; @1 @0 V, O) l2 R' s- ^' G c: }6 {
% W. ^# S8 }7 y5 n$ g* G
$ |2 x( _7 M/ j0 d首先我们要将数据划分为两个区间,已排序区间和未排序区间。# W6 w% x0 X. J; o8 t0 A# L% s& p. O
4 ~" S3 J. e8 a9 j U
& |* ^' e' E1 M
3 a) m+ n9 Q# D' H: r
8 |# p4 p" j' V0 x5 D8 |/ @& V
$ z+ o/ \, t5 }/ N& F我们从未排序区间取出数据和已排序区间的数据进行比较,如果小于已排序区间的数据,那我们就交换数据。* @; _2 U% a6 |
6 w+ W& f( B. {: ~% I K# X
4 j6 S1 i+ ^- D: U; }
( T4 i* h8 d @: t- z: `; l
$ n' `7 ~7 }5 W9 A$ y1 A; H4 V2 l# L: g' r& j& n
如果交换到已排序区间数据不在大于插入的数据,然后将元素插入进去。
# T$ B4 v% F; O+ n1 {) O
3 [! [' N' B- }, w! d
3 R* V: v) L- ]$ S3 |' k
2 x5 T- ~1 D7 W( v, P% F$ k1 s4 _5 |1 u2 D2 J) p. {$ p
0 Y1 y( h( M$ `9 A& J R
最后我们看一下总的插入排序动画和代码实现。5 v8 N9 L; T$ o4 A0 b
6 R+ {5 q3 D+ `6 v, P: n
+ |( C/ ]4 Q c$ {6 ~* o2 h
5 c) D# k5 B/ k, B# r! \4
& `( n5 k! c: D2 f- Z
4 n# ^; O8 Q/ }4 i+ I6 ]! N插入排序的性能
- n: ^0 N% g% j' d" C8 `
0 n v: C7 ]' m+ l+ O我们通过上边的对插入排序的拆分讲解和动画以及代码实现,想必面试官让你手写一个插入排序可以轻轻松松写出。但是我们掌握的插入排序知识还往往不够,我们在实际项目中,还要考虑插入排序的性能怎么样?因为才能更好的选择适当排序应用到项目中去。: |2 w+ ?1 j) _" o1 W- M% g8 J
5 S* U# [9 r& O7 A
4.1 插入排序的稳定性
. l! W1 \( b, R. o7 q6 Q5 C9 w+ y T& n: Q
再插入排序中,如果存在重复数据的话,前边的元素再插入的过程永远在第二个重复数据的前边,所以插入排序后的重复数据前后顺序不变,所以插入排序是稳定排序算法。 \' g T B# g6 v* _' d
! {& {: n; ]. t+ h: W1 I% F5 |7 z4.2 插入排序的空间消耗
' u) }4 c% K9 B) U. G) o, Q0 }0 Y! e" C3 e3 Y& R6 f
我们可以发现,插入排序的移动方式,需要消耗常量级的额外内存空间存储,也就是代码中的 temp,所以时间复杂度为 O(1),我们上边讲到,空间复杂度为O(1)的是原地排序算法。
3 j9 O+ P: I% t# [+ m& x
: |& U! ^4 ^6 Z e4.3 插入排序的时间效率
* M/ E3 m: i4 ~/ i
0 {. |2 o8 W1 B7 ?7 s! Z$ y+ F. ]插入排序的最好情况就是不需要搬移任何数据,从头到尾寻找插入数据,每次只比较一次即可,即一组有序数据,所以最好时间复杂度为O(n)。
- D2 u5 k$ t/ A+ p
5 X% k% G @- G; V( z$ Z如果一组数据正好是倒序输出,那么每次都需要比较移动所有数据,每次移动时 n,n 个数据时间复杂度为O(n2)。/ q- e' D6 y1 j
$ P" k4 j* H, A2 |
对于插入排序的平均时间复杂度,每次插入都要移动数据,插入 n 次,所以平均时间复杂度为 O(n2)。
( d; ~1 V. d, C4 A' J* ?1 D+ Q; D# M1 d, I4 X3 o- L% ~4 n) s, d. v
55 [' Q) A0 a5 Q' _ n6 f3 B
5 H6 T* m1 j, }7 L% _
小结7 r' G$ t1 r0 k6 x, q8 j. ?: g* G
% W/ T- x: H1 H2 \我们学完了今天的插入排序之后,我们回到最初的面试官问题上。插入排序和冒泡排序哪个更好呢?
' ]* g# L- Y/ B0 ] e# {" o+ i0 O$ p4 c; C: s
我们现在元素移动次数上进行分析,如果一组无序的数据通过冒泡排序排好序之后,它的交换次数是这种数据的逆序度;对于插入排序来说也是一样的,移动次数上都是原本数据的逆序度。
% [% Q/ ]( B' ~. w8 |4 S
/ {3 | p1 k: |元素的移动次数是相同的,那我们接下来看看元素的交换次数。从代码上分析可以明显看出,冒泡排序的一次交换需要三行代码,而插入排序的交换却需要一行,所以总的交换次数冒泡排序大于插入排序。) {8 u5 Z3 @2 k* n/ P) d: ^0 v
( F8 A% W9 {5 b' Z
有小伙伴会问,这两行的差别有那么大吗?移动一次,我们可以不计较,如果数据很多,想想下,两者的效率差别很轻易的就比较出来了。- G4 P: C2 `6 @% U, Y$ o
( E% \; z2 M( X
虽然冒泡排序的时间复杂度和插入排序的时间复杂度是相同的,但是我们实际使用中还是优先选择插入排序。( P- c- H; }8 y& Q
1 j4 \* [/ r8 Q/ F# G, `! H
对于插入排序还是可以优化的,对了,没错,就是希尔排序,我们在这不多分开写,后期会继续更新。" W0 q/ r& s, C' R3 D; I9 Y
————————————————
5 n+ ^. l `% a: A- v2 \5 ]版权声明:本文为CSDN博主「胡鹏程的博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
& V5 N" w7 d, d) g- C7 v1 ^原文链接:https://blog.csdn.net/lyshark_lyshark/article/details/1267927084 G! V z' T, R' }- l$ e% @0 K
4 V4 l9 E. j# u. O
. p' F1 E& |% p o u6 s; U
|
zan
|