在线时间 1630 小时 最后登录 2024-1-29 注册时间 2017-5-16 听众数 82 收听数 1 能力 120 分 体力 560041 点 威望 12 点 阅读权限 255 积分 173385 相册 1 日志 0 记录 0 帖子 5313 主题 5273 精华 18 分享 0 好友 163
TA的每日心情 开心 2021-8-11 17:59
签到天数: 17 天
[LV.4]偶尔看看III
网络挑战赛参赛者
网络挑战赛参赛者
自我介绍 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
群组 : 2018美赛大象算法课程
群组 : 2018美赛护航培训课程
群组 : 2019年 数学中国站长建
群组 : 2019年数据分析师课程
群组 : 2018年大象老师国赛优
动画:面试官问我插入排序和冒泡排序哪个更牛逼?
5 q. v6 _ V: g3 T
1 M' C, N$ m9 x) _& q( K* R 写在前边
2 b" Z# l7 R- F `" N ! t6 B% p& o+ N( e+ y$ m! U7 y
/ i, O: x3 w8 F' j6 ~. d 排序对于每个开发者来讲,都多多少少知道几个经典的排序算法,比如我们之前以动画形式分享的冒泡排序,也包括今天要分享的插入排序。还有一些其他经典的排序,小鹿整理的共有十种是面试常问到的,冒泡排序、插入排序、希尔排序、选择排序、归并排序、快速排序、堆排序、桶排序、计数排序、基数排序。' g- o8 D0 ~! f; N* Q# q( L
3 O* ]& R( r8 V5 C4 O, A1 s9 @ 虽然我们基本知道了这些排序算法,但是在实际项目开发以及面试中往往出乎我们所料。在面试中,经常会被问到各种排序之间的比较;在实际项目中,往往排序的数据不是我们所练习的整数。& q& V' Q0 }' M, n0 H5 ~6 x
% o" O7 B' a e% L
那么今天我们来学习一下,插入排序比我们之前讲的冒泡排序有什么区别呢?面试官问我们,我们如何回答完整呢?" O+ {6 }, S3 X6 G' t
2 U) I1 o' f5 `( I1 P 思维导图, u) G1 ]7 [# D T
" q+ J$ a& K$ W: \% ^
s, m8 v5 a1 E1 d6 @; Y; J. I7 o$ T
p2 E" j( K9 _& L U* f7 x . ~) G; U6 i1 n Y! `
1
3 y2 z( _$ Z6 r8 p" @1 v; W
% [ t1 L1 w7 w) z Q% k8 k5 ~7 G 如何分析一个排序算法?9 [9 I% Q" E L& e
5 r) C. A5 y* q8 V; S
之前写的一篇很详细的文章。- e2 s# A# R! ~
2 v( D1 E5 Z4 ~; R6 S4 X5 y 佩奇学编程 | 复杂度分析原来这么简单
0 y+ e X {3 `2 H( E0 \6 V
( B. M s9 k6 b0 C) X5 { 分析排序算法已经成为我们衡量一个算法优良的重要标准,从以下三个方面入手。! V' s0 @1 u9 J( `) i
7 C1 M# M n! l5 u. V( ~( M
1.1 时间效率
! [& i# n2 Z' I( p& ^' Y
% d/ j+ U. a' i. Q$ @1 a9 k 这里所谓的实践效率就是时间复杂度,相信大家对于时间复杂度并不陌生。
( ?1 \6 X) x1 G
8 G: |. j6 F5 l& Q# M 复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系。5 u" c7 @& p( x0 h' y1 p7 E# W
7 _7 C5 N6 D" q" n6 w5 L* ? 对于时间复杂度的分析,要把最好时间复杂度、最坏时间复杂度、平均时间复杂度分析出来,分别对应了排序算法的最好排序情况、最坏排序情况以及平均排序效率。
, h& M0 Y8 x- b% M2 n
7 J5 A: q9 `$ G$ J9 J0 u& T 1.2 空间消耗
' V- h& J( Y% D8 Y% x6 O/ Y , z" t* {# ?8 l8 h& R: U: i
所谓的空间消耗对应的是空间复杂度,在排序算法中需要开辟的额外内存空间是多少。如果空间复杂度为 O(1),此时该排序叫做原地排序。
, d$ j, N: o7 D+ i3 U& K' z7 }
! }- J y$ L$ i/ d) J5 a 注意:是额外的内存空间,存储排序数据消耗的空间不计。9 X/ G4 O- `7 [$ W& F; ]- {
; |+ V' A; S; k. z
1.3 稳定性
; H/ o8 ]7 G" Y' W2 s* x1 K $ e: {6 f! s) b1 w+ W# @- e0 n
算法的稳定性虽然我们之前接触的很少,但是稳定性也是衡量一个排序算法的重要标准。什么是稳定排序呢?比如有一组有重复待排序的数据,排序前后,重复的数据顺序不变,此时该排序为稳定排序。否则,叫做不稳定排序。它在实际应用中非常重要的,今天我们就不多说,以后会慢慢分享到。% ~8 k; D4 `2 m+ @5 y. G' O+ Y
& }( p% z( A2 v) d 2
+ q* t }0 S! {- I0 `0 K ' x: _& M4 K$ E j
什么是插入排序?7 A( D* e5 H2 J6 q
) k8 \2 V, r# d* G: K- l
顾名思义,插入排序就是通过插入的方式来排序呗,最经典的就是打斗地主,可以将打乱的扑克牌作为未排序区间,手中已经排好序的作为排序区间。每次我们摸牌的过程,就是从未排序区间,通过插入的方式,插入到已排序区间。那么这个过程就称为插入排序。3 p1 P* t8 I. g. g. ]5 E# r
V. Z: X: z. Y8 t5 n
& z! w& q$ V0 X
! {$ `/ G2 ]: X4 V' q5 N$ H 3
4 Q A' k( O G* s) y# G- P; L
+ L0 L. L& d( s7 ?) A& L' C) | 如何实现插入排序?) g! a/ d j+ m
8 n5 W5 O, j' t, ~$ h) \ 上述插入排序的概念我们已经理解了,那么给你一组数据,如何来进行插入排序呢?' |3 n8 v8 W2 k: V
) n z3 S; B7 A+ r: n
* h6 h1 ] t5 g$ _
1 }) J) L0 r1 ?, X& D9 u# D7 h 首先我们要将数据划分为两个区间,已排序区间和未排序区间。9 M/ ~/ W" _& b4 _8 ~
. }: v+ o+ D( g8 L% r. s5 X/ C
5 J# T+ w/ ~& F" ?5 l
, s2 n* q o3 u2 p9 k& s
2 I/ y, G8 r% L" R
4 a0 p, B; I' @( r v) R! q) R4 B
我们从未排序区间取出数据和已排序区间的数据进行比较,如果小于已排序区间的数据,那我们就交换数据。$ I3 X# U8 q$ U
+ k$ Y8 S4 w G& \
) b1 f$ X" C; c8 W; T 0 X" r+ Q- q2 w P7 R ~6 n
# J. i2 a8 u+ V 9 J6 F. l I; v2 j# H8 f, g2 _
如果交换到已排序区间数据不在大于插入的数据,然后将元素插入进去。9 L6 Q7 ~6 k! k5 i/ s. `
) R/ }9 {. k# X4 t" @
1 y" b$ _ t) H) p; e
! h) o2 k# I. V+ C 9 b' l% M6 T. ^5 R: r- m
( N6 J" q; ~+ o, a 最后我们看一下总的插入排序动画和代码实现。% @, r- l/ e6 A' T9 [' I* [" a- S5 D
# M8 Y4 G4 Q$ i% x0 _- g
5 W% u9 f" i! S* n3 }" x7 w' z
; w7 N6 k4 ?' Z% L 4$ }- \# Z$ _$ B/ A" M
8 ]5 ?' }* G( v3 A6 t6 } 插入排序的性能2 h5 \ F; }+ V3 Q- ^
* W% O2 G+ b2 N) |9 _& n& b2 ]6 l 我们通过上边的对插入排序的拆分讲解和动画以及代码实现,想必面试官让你手写一个插入排序可以轻轻松松写出。但是我们掌握的插入排序知识还往往不够,我们在实际项目中,还要考虑插入排序的性能怎么样?因为才能更好的选择适当排序应用到项目中去。3 ]0 ]* |4 @! G: y) |
3 w$ t5 S$ l% F9 ^& s! T 4.1 插入排序的稳定性+ A6 ~- K7 ~ L! d7 F( [' J) M
+ J( J* F& i, e: h& D) G
再插入排序中,如果存在重复数据的话,前边的元素再插入的过程永远在第二个重复数据的前边,所以插入排序后的重复数据前后顺序不变,所以插入排序是稳定排序算法。
+ C' r; X6 Q& F X# K8 C9 Q & J H6 [) v; N
4.2 插入排序的空间消耗
% Y3 D; o7 S$ g& j
0 |, }2 e3 W$ }: F# \ 我们可以发现,插入排序的移动方式,需要消耗常量级的额外内存空间存储,也就是代码中的 temp,所以时间复杂度为 O(1),我们上边讲到,空间复杂度为O(1)的是原地排序算法。
7 S( O4 C- Y$ N4 P0 {2 z
2 ~' T+ E6 l' y, ^" w9 | 4.3 插入排序的时间效率: ~" y$ i! o4 W7 {, P- W, b3 V
$ i- n$ X) S- B& X$ d; p& T
插入排序的最好情况就是不需要搬移任何数据,从头到尾寻找插入数据,每次只比较一次即可,即一组有序数据,所以最好时间复杂度为O(n)。
( W9 R+ p+ T# m4 m# h5 O 9 @5 ^* d/ M6 M% h, X/ z
如果一组数据正好是倒序输出,那么每次都需要比较移动所有数据,每次移动时 n,n 个数据时间复杂度为O(n2)。' J! f: M$ d1 B% @: V E! B I
5 C4 h# A3 t7 L$ ^ 对于插入排序的平均时间复杂度,每次插入都要移动数据,插入 n 次,所以平均时间复杂度为 O(n2)。
2 G7 \# Y5 o+ d ) m- w/ Y# j: |& t+ U) R- l" v2 T
5
' n; M, i3 R; J( M$ |7 H 2 }; `* h) E5 _
小结
, B; n5 O! h! u/ T" }1 [7 t. X K
$ A- H' E" m6 e! j 我们学完了今天的插入排序之后,我们回到最初的面试官问题上。插入排序和冒泡排序哪个更好呢?# i0 ^* W- M. F
% E8 D S. e, W5 m; ]4 u
我们现在元素移动次数上进行分析,如果一组无序的数据通过冒泡排序排好序之后,它的交换次数是这种数据的逆序度;对于插入排序来说也是一样的,移动次数上都是原本数据的逆序度。) l6 ?2 ~' Y. K/ ?7 W% }, i9 g
& I, n4 k: X! u+ u$ ?* p
元素的移动次数是相同的,那我们接下来看看元素的交换次数。从代码上分析可以明显看出,冒泡排序的一次交换需要三行代码,而插入排序的交换却需要一行,所以总的交换次数冒泡排序大于插入排序。9 s9 W. F1 w9 ?) `
1 |/ R+ h- [; N, G 有小伙伴会问,这两行的差别有那么大吗?移动一次,我们可以不计较,如果数据很多,想想下,两者的效率差别很轻易的就比较出来了。/ B4 y! u$ _4 f
5 k) q4 C- k7 T( u7 ?6 l
虽然冒泡排序的时间复杂度和插入排序的时间复杂度是相同的,但是我们实际使用中还是优先选择插入排序。! \6 ]8 a3 w( {0 ^
- x5 {5 n0 t0 ~/ K, S 对于插入排序还是可以优化的,对了,没错,就是希尔排序,我们在这不多分开写,后期会继续更新。5 R- K9 k' _& c- l: A! b+ w
————————————————
- D) F, Z) z# N, m 版权声明:本文为CSDN博主「胡鹏程的博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
- d2 I% P2 H" A. U7 J" |% p 原文链接:https://blog.csdn.net/lyshark_lyshark/article/details/126792708
; P/ A. [5 a9 V# q6 l- x4 ~% w" Y # `$ Q: \/ S1 ?4 _8 E
/ Q5 F1 Z3 g6 v H6 v
zan