- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 558645 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 172966
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 18
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
动画:面试官问我插入排序和冒泡排序哪个更牛逼?. v+ u u/ j( F4 u; k% ~
" M: \# l6 o0 }6 a
写在前边& C- V2 K @8 I, o
- j0 O4 T3 _# V0 k+ R
) Y, h- l( }9 W排序对于每个开发者来讲,都多多少少知道几个经典的排序算法,比如我们之前以动画形式分享的冒泡排序,也包括今天要分享的插入排序。还有一些其他经典的排序,小鹿整理的共有十种是面试常问到的,冒泡排序、插入排序、希尔排序、选择排序、归并排序、快速排序、堆排序、桶排序、计数排序、基数排序。5 g7 J" X; `8 g+ k' ?5 r
% x5 [0 Q a- W: K
虽然我们基本知道了这些排序算法,但是在实际项目开发以及面试中往往出乎我们所料。在面试中,经常会被问到各种排序之间的比较;在实际项目中,往往排序的数据不是我们所练习的整数。
- F" t0 ?5 u1 z
2 K8 c! ]7 X2 s" d那么今天我们来学习一下,插入排序比我们之前讲的冒泡排序有什么区别呢?面试官问我们,我们如何回答完整呢?
1 O* n; Q2 u6 m# U. R& _/ |' i; K% }2 }
思维导图) a% n4 _% u# G6 F
& ~0 C" X1 C+ i9 C/ }! M) `. K# q2 P3 k4 o) V9 G. \
$ \! e- G4 {; m4 G6 [! |9 K8 T( R
6 R+ W8 ]- c/ N( q( l% _1
7 g' R' Y( j0 P' h: ]
, c% x+ I+ ^: s5 j+ L如何分析一个排序算法?
F) Y. k& U5 [1 O, l8 ]; ?. d: C: m% T2 [4 N& s& d
之前写的一篇很详细的文章。
- @* A( q5 N: ^, n7 ]4 B- `. `& A& f/ Q
佩奇学编程 | 复杂度分析原来这么简单2 _1 B- m" U: D
/ E+ E) Q+ R9 a& ^9 [" [/ S
分析排序算法已经成为我们衡量一个算法优良的重要标准,从以下三个方面入手。8 r3 [$ Y m M: q7 ?! d% U
8 o7 h5 t/ p/ A" i4 j: ^# `$ T
1.1 时间效率& @4 i9 q1 g3 }: D2 c* V
: T: b6 c" E2 ^8 z# d
这里所谓的实践效率就是时间复杂度,相信大家对于时间复杂度并不陌生。
9 m# i3 F( Z/ o8 b9 q8 u5 K% C6 c# E) ]% S. o" E
复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系。
/ n# m" N9 N7 N3 `& U- F3 r: \/ E
, m! ^8 E3 p9 h7 y% {( U( ?对于时间复杂度的分析,要把最好时间复杂度、最坏时间复杂度、平均时间复杂度分析出来,分别对应了排序算法的最好排序情况、最坏排序情况以及平均排序效率。
* C' f" k$ k3 ]+ Y5 M% S- Q: ], k( B* g. _# {# t9 ^
1.2 空间消耗3 t7 }8 H7 j3 d& p
! ~6 }) F% `/ H3 F+ G- e% a0 a
所谓的空间消耗对应的是空间复杂度,在排序算法中需要开辟的额外内存空间是多少。如果空间复杂度为 O(1),此时该排序叫做原地排序。. p; c. A2 p7 G. ^# o* k& {
: d( `+ b* w k' k9 C; r( ~! D7 X9 N
注意:是额外的内存空间,存储排序数据消耗的空间不计。
! U7 z* d H; @) I: I9 C
* u" r0 O1 C6 I% p: D1.3 稳定性7 {7 O. }$ F0 J3 q
% U. t& X0 @! l' i# |; i# `% ?
算法的稳定性虽然我们之前接触的很少,但是稳定性也是衡量一个排序算法的重要标准。什么是稳定排序呢?比如有一组有重复待排序的数据,排序前后,重复的数据顺序不变,此时该排序为稳定排序。否则,叫做不稳定排序。它在实际应用中非常重要的,今天我们就不多说,以后会慢慢分享到。
; D R* l, z. {2 `, W8 M$ }2 V. Y- u5 ~3 D+ c9 d# I: ~
2) ^7 ]: P8 o% y( S- @( ?
* M. H; y1 ?6 \% k9 r3 R
什么是插入排序?
# n# |. z4 r; v/ m) V
; i8 O( d8 c H! |顾名思义,插入排序就是通过插入的方式来排序呗,最经典的就是打斗地主,可以将打乱的扑克牌作为未排序区间,手中已经排好序的作为排序区间。每次我们摸牌的过程,就是从未排序区间,通过插入的方式,插入到已排序区间。那么这个过程就称为插入排序。
" H* ?6 o; B: A: g$ z' K) f+ r, M
8 h; g; W4 ^5 j& @* W/ V% y, d: y& A5 C! f% ^7 n% b: b0 A n
3
7 }! A9 ?! T& ]6 @% ^* k2 f& f! d5 Y0 B, z; t" Q
如何实现插入排序?
# c3 `0 _6 K# `8 h d$ ]0 x, g4 o
: z8 Y# @& b! j, B& d上述插入排序的概念我们已经理解了,那么给你一组数据,如何来进行插入排序呢?
& l, ~1 F8 F+ a: \8 s8 o
: t1 N6 }' u! C: q3 F+ A# i. n& Y! q1 i3 V' T; U. W
$ f$ n. ?& b- Y4 ^8 q首先我们要将数据划分为两个区间,已排序区间和未排序区间。
9 k1 E8 X% H/ g+ W; [, u( I& O6 P' ?8 n$ C) n
$ M% L; E4 ^1 U' s5 N3 W- R' y& ]- T- c5 v3 y
7 s" z8 V0 b n% J- U" h) K) n5 q% }0 ?1 V9 d9 b
我们从未排序区间取出数据和已排序区间的数据进行比较,如果小于已排序区间的数据,那我们就交换数据。8 s3 i( i: h3 B- ^0 z
* \' W# w, Z& T8 {& I
8 e: R% f) z3 [# U0 H0 i4 a5 a
; B# U7 {" s& e! S( }( s0 o9 E( \3 Y) b1 k0 ^2 \4 X
+ z8 ~ k0 Y& z/ I( L& E
如果交换到已排序区间数据不在大于插入的数据,然后将元素插入进去。
6 u8 M% K$ h$ c- a) Y2 o" o
% W+ {/ {5 ^5 v# l# m% o% H }6 z
8 V/ o& R, V6 W% F: e: K7 _7 r c; C( Y; G+ U' E
7 Y" s# A, [; s) Q" ]: Q
; F$ Z+ t; F( h4 f2 h5 a
最后我们看一下总的插入排序动画和代码实现。
?2 z6 f7 ~$ \7 G+ k2 ~& l) k* b* {! T% H" F* `2 U" Q# P2 {% C2 a
( [# j; Z( t6 W
3 @7 {8 I4 v d& G8 n5 K7 w8 H4+ O9 f0 E+ `* x2 i$ Y6 C" _
8 m' S) V7 r" r$ B }
插入排序的性能
9 w4 E3 B+ N- c6 P. K) q+ R; h" A
我们通过上边的对插入排序的拆分讲解和动画以及代码实现,想必面试官让你手写一个插入排序可以轻轻松松写出。但是我们掌握的插入排序知识还往往不够,我们在实际项目中,还要考虑插入排序的性能怎么样?因为才能更好的选择适当排序应用到项目中去。
1 _$ E, l6 z0 [' X+ C0 b, ^9 E! o: X$ `) a: ~6 n
4.1 插入排序的稳定性# P9 t' V0 P- b' r3 X% V- z
, O$ g' M/ T$ _, k再插入排序中,如果存在重复数据的话,前边的元素再插入的过程永远在第二个重复数据的前边,所以插入排序后的重复数据前后顺序不变,所以插入排序是稳定排序算法。# R ^+ i" P& O& f8 w) V" H
U! e3 j l; I, Q
4.2 插入排序的空间消耗% D: R# f# o. }3 x
# l( o, v, B. ~& \( c: ^
我们可以发现,插入排序的移动方式,需要消耗常量级的额外内存空间存储,也就是代码中的 temp,所以时间复杂度为 O(1),我们上边讲到,空间复杂度为O(1)的是原地排序算法。
% o* h! |6 a6 I: \/ Q6 p ~7 u" }5 P, Y2 O
4.3 插入排序的时间效率! f D) @8 K3 H& C ^ r" d
5 u9 Q2 `6 U2 s7 @插入排序的最好情况就是不需要搬移任何数据,从头到尾寻找插入数据,每次只比较一次即可,即一组有序数据,所以最好时间复杂度为O(n)。
5 W/ i6 I: {6 k# s0 {+ @! H9 ~: }
7 L) i1 S/ ]4 d1 O0 U* I如果一组数据正好是倒序输出,那么每次都需要比较移动所有数据,每次移动时 n,n 个数据时间复杂度为O(n2)。
7 c* _) Q. R/ n6 ~, |" P
( f, ?* c. W. ]对于插入排序的平均时间复杂度,每次插入都要移动数据,插入 n 次,所以平均时间复杂度为 O(n2)。3 K9 l) h: g3 y: h" O. h2 _2 x
# d* b* V' G0 r2 C8 L5 _7 t
5
$ H \" R9 c( n/ \, w" b9 H' X1 A* y2 |! }4 W1 w! a% U( u
小结
+ v: D# i& _0 a3 O, n% Y4 C6 v) Y" ^' B/ l- c3 S7 ]
我们学完了今天的插入排序之后,我们回到最初的面试官问题上。插入排序和冒泡排序哪个更好呢?
: T% R; t: }7 A" a+ e" t
& y! W, S0 Q" v. l$ r6 d* c; U* ~我们现在元素移动次数上进行分析,如果一组无序的数据通过冒泡排序排好序之后,它的交换次数是这种数据的逆序度;对于插入排序来说也是一样的,移动次数上都是原本数据的逆序度。( O' }- X4 q6 f O n
5 s. h h, n% n元素的移动次数是相同的,那我们接下来看看元素的交换次数。从代码上分析可以明显看出,冒泡排序的一次交换需要三行代码,而插入排序的交换却需要一行,所以总的交换次数冒泡排序大于插入排序。
2 q1 \: n) c- a* K) x* ?: U* H- J& E% ]
有小伙伴会问,这两行的差别有那么大吗?移动一次,我们可以不计较,如果数据很多,想想下,两者的效率差别很轻易的就比较出来了。
+ l: z' q1 T/ J7 r
+ a1 ^! C h6 i' ?6 R' |虽然冒泡排序的时间复杂度和插入排序的时间复杂度是相同的,但是我们实际使用中还是优先选择插入排序。
% K5 p/ B& O6 j& q6 k7 A# V
! U. v; p6 b. C( Q3 N- ^对于插入排序还是可以优化的,对了,没错,就是希尔排序,我们在这不多分开写,后期会继续更新。- B. {/ v# ^% V, Y
———————————————— a* D" r4 V2 G- c- ?, t3 n9 X
版权声明:本文为CSDN博主「胡鹏程的博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。) _: g/ `* t9 L t! }: t( b7 e
原文链接:https://blog.csdn.net/lyshark_lyshark/article/details/1267927080 ^4 g6 y) H* k/ r* h$ k8 [* m% R% v
+ B/ P e( o7 Z$ C
& P' Y6 L$ j5 E# M r0 ]' z% ^0 ^ |
zan
|