- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 563349 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174228
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
动画:面试官问我插入排序和冒泡排序哪个更牛逼?
# g* ?) h! d: e& f) Y" A, V; L9 f5 Z4 W" {+ N
写在前边0 M9 ]# p: u; ~0 }- _+ o* e$ l
, h0 }6 A/ x( g) Y$ J) ` q
* C% M# s- n/ Y8 i6 B% y排序对于每个开发者来讲,都多多少少知道几个经典的排序算法,比如我们之前以动画形式分享的冒泡排序,也包括今天要分享的插入排序。还有一些其他经典的排序,小鹿整理的共有十种是面试常问到的,冒泡排序、插入排序、希尔排序、选择排序、归并排序、快速排序、堆排序、桶排序、计数排序、基数排序。9 N% y+ z% h) f% e/ g
7 r/ {: u3 N# L2 M/ B" ~( G
虽然我们基本知道了这些排序算法,但是在实际项目开发以及面试中往往出乎我们所料。在面试中,经常会被问到各种排序之间的比较;在实际项目中,往往排序的数据不是我们所练习的整数。( P- Q9 {1 @- {; ?6 ~
% Q$ }+ E N+ P, R0 x. V那么今天我们来学习一下,插入排序比我们之前讲的冒泡排序有什么区别呢?面试官问我们,我们如何回答完整呢? x. z( v! Y2 H, B9 x
* ?5 E0 I) f a/ l
思维导图9 i: ?6 e) g, f, n2 R7 [
1 I2 e: _/ O9 g
7 g8 K& G1 Z2 l/ h9 l. ]# r" p
' L0 t" d/ X! h' k- {2 V1
, p9 t I. H: ?1 p6 w) b1 H; z) }0 O4 P) w. \7 r2 T" u
如何分析一个排序算法?$ z! P- F5 a" i
7 } R. q4 j7 A4 p) G
之前写的一篇很详细的文章。 r: X1 H7 a2 S% l8 {. v- ~8 Z
1 O) G0 {( m8 i+ k4 O5 t; h
佩奇学编程 | 复杂度分析原来这么简单
3 y! C: F- ~4 p+ Q
- W! @1 F2 l- g- M6 h分析排序算法已经成为我们衡量一个算法优良的重要标准,从以下三个方面入手。/ i" X/ R7 ]1 D+ M) i. ?2 F+ M
+ X* C3 G7 M+ S! p1.1 时间效率9 [1 k, _ Z3 r! m
, j8 ~; }% x0 r' S
这里所谓的实践效率就是时间复杂度,相信大家对于时间复杂度并不陌生。4 K1 u+ h) V* s3 [( x: F) c& U
; g- W" x6 b$ U$ f, G& U( P6 o复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系。, u0 r0 q. n a9 \$ Q/ X0 e
( _+ ?8 j5 W" P" g( t- R! h对于时间复杂度的分析,要把最好时间复杂度、最坏时间复杂度、平均时间复杂度分析出来,分别对应了排序算法的最好排序情况、最坏排序情况以及平均排序效率。" r% ^! n( }1 p# D0 P
& Z! C! C5 K! b( f( e
1.2 空间消耗 k2 j% Q+ n; E3 @
9 w+ x0 o- b. d1 a0 V& S
所谓的空间消耗对应的是空间复杂度,在排序算法中需要开辟的额外内存空间是多少。如果空间复杂度为 O(1),此时该排序叫做原地排序。
% {, a' h% X& _
0 _7 h: ]: `5 {7 d) t) h, w注意:是额外的内存空间,存储排序数据消耗的空间不计。
% b4 s( n4 h7 @6 f: b) M: C; G6 J$ F( q. j' f, s& }6 L
1.3 稳定性
! c: W! T( t/ R# |5 Y2 m" }+ Q
9 T) i$ X$ G+ T# ]. n算法的稳定性虽然我们之前接触的很少,但是稳定性也是衡量一个排序算法的重要标准。什么是稳定排序呢?比如有一组有重复待排序的数据,排序前后,重复的数据顺序不变,此时该排序为稳定排序。否则,叫做不稳定排序。它在实际应用中非常重要的,今天我们就不多说,以后会慢慢分享到。: e. f( N# X1 X s! P
6 v1 q$ G; H4 F' A
2
/ |$ i, Y' }% {' }# R+ \. V6 R' G
( N9 H# ]; r: R! i, G' H什么是插入排序?
+ K6 s& Y+ Z& a, S" }0 |* ^5 b* J" e7 I* a0 ~" C: E7 O9 w
顾名思义,插入排序就是通过插入的方式来排序呗,最经典的就是打斗地主,可以将打乱的扑克牌作为未排序区间,手中已经排好序的作为排序区间。每次我们摸牌的过程,就是从未排序区间,通过插入的方式,插入到已排序区间。那么这个过程就称为插入排序。
! {; z% _( B, v3 ] o2 ~: t
& y3 t& J a- J' M% Q$ l6 ?" r$ l7 `6 Y' {8 W2 S
9 y- T) [% g. C& \$ c- v w0 T. D1 `
3
. v) c2 z$ {( f1 S
% A5 u9 L3 Z9 B" ^% ~如何实现插入排序?2 e3 S' |" S! }, F
& c1 h! X- A1 y' {; K上述插入排序的概念我们已经理解了,那么给你一组数据,如何来进行插入排序呢?5 z3 F. Q* k: |. Q- @
$ V Y( ~3 B8 {( `# \" K& s
$ U. j: @; r3 J9 `% E
. c* S9 o* p7 a! o; L
首先我们要将数据划分为两个区间,已排序区间和未排序区间。2 r6 g$ ~) r$ P% c- b0 I* Y, i
* P: C5 v e f) ?% z$ V) h- n
, O7 q4 u+ T3 I) X
: X2 [* s: Y; y+ B4 {5 X: t4 J# ^* c( H. l6 U2 a0 \
6 M- |4 n: p) S- d. [
我们从未排序区间取出数据和已排序区间的数据进行比较,如果小于已排序区间的数据,那我们就交换数据。( s5 c0 D4 |3 C! X8 p5 Q$ p$ D( z
. B# s8 ]: P6 a! y, w7 @' V* Y
2 O, ~9 D4 T# ?5 ]( U2 f1 s
7 [! r# U6 p( c
/ i: M5 a# P# t: V% r
: P9 R. a" F+ F2 }. V9 Z
如果交换到已排序区间数据不在大于插入的数据,然后将元素插入进去。6 E' f( Q! q' ~5 ~) N3 C
+ V! c7 s( O h! X5 a4 e! ~' s
$ |8 k `- n; p4 G* y1 D
( b/ U& R3 E l% N/ F* ~
, i+ [4 o( V2 W \6 f W! N7 X. d4 }
最后我们看一下总的插入排序动画和代码实现。9 O- o$ m+ c/ J/ U/ } E2 x( |; D3 c
) A8 e. |& q( t
: V0 A \7 Z7 M/ k: X$ x u: b# M5 n Z- [/ t0 H
49 H- q& _! e( R; g% U
6 G8 X' L" o+ F2 ~1 n0 a
插入排序的性能& T5 G4 @/ u: U: g) f1 S3 J* B! H* u5 I
- \5 p, C" ]( i- K0 R+ J, e: s4 L
我们通过上边的对插入排序的拆分讲解和动画以及代码实现,想必面试官让你手写一个插入排序可以轻轻松松写出。但是我们掌握的插入排序知识还往往不够,我们在实际项目中,还要考虑插入排序的性能怎么样?因为才能更好的选择适当排序应用到项目中去。* R3 r6 t3 ], M
9 P% V: k& N* P& u y" E a# f7 i
4.1 插入排序的稳定性
: T; g* V" e7 J( n. _$ e; \3 u8 [. }# |9 D* U& l* r
再插入排序中,如果存在重复数据的话,前边的元素再插入的过程永远在第二个重复数据的前边,所以插入排序后的重复数据前后顺序不变,所以插入排序是稳定排序算法。
' B/ ]* M4 B' ?; r% X, I0 v* j( v3 s
4.2 插入排序的空间消耗
8 f7 i. q' c t* i9 I$ M& n, o( `( D( Y
2 d7 _1 ^7 Y/ i6 W# Z" B6 L我们可以发现,插入排序的移动方式,需要消耗常量级的额外内存空间存储,也就是代码中的 temp,所以时间复杂度为 O(1),我们上边讲到,空间复杂度为O(1)的是原地排序算法。5 Q0 J q" D* p1 q* s$ Q
/ r @0 Z; p1 \* H, @; U3 e4.3 插入排序的时间效率/ ~* t) y( h' ~- g$ t1 l/ d
4 D! _5 V7 X( C+ H插入排序的最好情况就是不需要搬移任何数据,从头到尾寻找插入数据,每次只比较一次即可,即一组有序数据,所以最好时间复杂度为O(n)。
9 s9 M- c3 W0 H) `8 d
. E+ L# x9 X& P2 m" g3 Z, A如果一组数据正好是倒序输出,那么每次都需要比较移动所有数据,每次移动时 n,n 个数据时间复杂度为O(n2)。7 A8 J# d% _3 |- g$ j$ c( l: _
" W8 u- u, T% h对于插入排序的平均时间复杂度,每次插入都要移动数据,插入 n 次,所以平均时间复杂度为 O(n2)。- b7 G( S2 t7 v: S" v
6 A3 X# g: }, Y- _
51 @+ x2 S1 z9 L+ p* M; S
+ M% u) T4 y; @小结
; S3 \0 k" B$ ?5 P0 _+ t: T1 l2 b% d% [' F ~
我们学完了今天的插入排序之后,我们回到最初的面试官问题上。插入排序和冒泡排序哪个更好呢?
3 H& p G& j5 G7 n& f6 q( g% y% g8 T; }3 _3 `4 K0 a4 j$ p
我们现在元素移动次数上进行分析,如果一组无序的数据通过冒泡排序排好序之后,它的交换次数是这种数据的逆序度;对于插入排序来说也是一样的,移动次数上都是原本数据的逆序度。
6 I- f. C. E9 l
9 ?: W1 r6 O( g元素的移动次数是相同的,那我们接下来看看元素的交换次数。从代码上分析可以明显看出,冒泡排序的一次交换需要三行代码,而插入排序的交换却需要一行,所以总的交换次数冒泡排序大于插入排序。
7 V2 x, x1 ~) d7 p* \3 \) x/ r2 J. O, d: S5 a6 J! {: c9 @
有小伙伴会问,这两行的差别有那么大吗?移动一次,我们可以不计较,如果数据很多,想想下,两者的效率差别很轻易的就比较出来了。
7 x' x( {8 f7 T! K, n) o7 j9 u0 b) X, c) @' R
虽然冒泡排序的时间复杂度和插入排序的时间复杂度是相同的,但是我们实际使用中还是优先选择插入排序。
. b; k( A6 Q5 v5 l+ g( }/ E* D" D. Z/ k. j% A# s4 V4 S' ?
对于插入排序还是可以优化的,对了,没错,就是希尔排序,我们在这不多分开写,后期会继续更新。0 v5 [ e1 x4 E( [9 |
————————————————! d5 j& } _' I% P/ \+ g) ~
版权声明:本文为CSDN博主「胡鹏程的博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。" s, U/ s) b& D6 p" _- c$ l1 R
原文链接:https://blog.csdn.net/lyshark_lyshark/article/details/126792708
) y5 P! Z( W# g9 V; |0 u W
2 ]% }9 C% S) c5 ~+ p) S) g5 i
0 [& p* x7 y3 ^+ Y! _$ [ |
zan
|