在线时间 1630 小时 最后登录 2024-1-29 注册时间 2017-5-16 听众数 82 收听数 1 能力 120 分 体力 563333 点 威望 12 点 阅读权限 255 积分 174223 相册 1 日志 0 记录 0 帖子 5313 主题 5273 精华 3 分享 0 好友 163
TA的每日心情 开心 2021-8-11 17:59
签到天数: 17 天
[LV.4]偶尔看看III
网络挑战赛参赛者
网络挑战赛参赛者
自我介绍 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
群组 : 2018美赛大象算法课程
群组 : 2018美赛护航培训课程
群组 : 2019年 数学中国站长建
群组 : 2019年数据分析师课程
群组 : 2018年大象老师国赛优
动画:面试官问我插入排序和冒泡排序哪个更牛逼? , v J2 s- h1 h+ I+ |7 n, G6 R
# _/ B) A& \ j D7 a% y
写在前边
# R, c3 o4 Y' D; ^* z( V) F- a+ X5 Y
% U4 R3 k) l* ^$ m6 _" h0 Z % G/ |% O3 w% h7 ?7 b: S* {8 G
排序对于每个开发者来讲,都多多少少知道几个经典的排序算法,比如我们之前以动画形式分享的冒泡排序,也包括今天要分享的插入排序。还有一些其他经典的排序,小鹿整理的共有十种是面试常问到的,冒泡排序、插入排序、希尔排序、选择排序、归并排序、快速排序、堆排序、桶排序、计数排序、基数排序。& N* t) T; ^: U0 a7 b1 h
- d; X3 |9 a- W S7 x2 f
虽然我们基本知道了这些排序算法,但是在实际项目开发以及面试中往往出乎我们所料。在面试中,经常会被问到各种排序之间的比较;在实际项目中,往往排序的数据不是我们所练习的整数。
& D9 z9 W6 ^' k: e ' r3 g5 @1 D5 \8 N
那么今天我们来学习一下,插入排序比我们之前讲的冒泡排序有什么区别呢?面试官问我们,我们如何回答完整呢?
0 W+ v1 ?4 s2 v 4 K j0 v$ C: g9 j) D0 [9 I
思维导图- d8 v1 R# U& s, g
6 h1 z1 [0 q" {# G
$ @4 u& L3 M( r( e/ A4 J& U( F: E7 T. t
3 G. q8 H2 m A. A
( Z- B7 J9 |( z- y# R 16 b% V" k. L& R/ A& C. W
/ e; R" K% k7 L y6 E 如何分析一个排序算法?. w; d' q0 i/ b2 r
' D- Q' q1 ] i j" R
之前写的一篇很详细的文章。
) N4 g. _6 y& J/ E
& g& C1 C, U8 D. D 佩奇学编程 | 复杂度分析原来这么简单9 ?2 s- t7 J! I8 [' O0 h
" G9 b0 }3 N! M) N 分析排序算法已经成为我们衡量一个算法优良的重要标准,从以下三个方面入手。% k2 I- W- D' y ?
( N# b2 g3 R8 U. s$ ~4 s 1.1 时间效率
( u Q3 ]( \3 F' [0 U
C; ^4 W4 [5 d" Z 这里所谓的实践效率就是时间复杂度,相信大家对于时间复杂度并不陌生。
$ {: F0 O) Q# Y5 I0 ^! c( C! S
2 c% V! k/ R f @/ T0 H 复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系。2 X6 I. g4 U2 h
1 W9 A6 d6 \# ? q3 j
对于时间复杂度的分析,要把最好时间复杂度、最坏时间复杂度、平均时间复杂度分析出来,分别对应了排序算法的最好排序情况、最坏排序情况以及平均排序效率。; g! ~; r2 W7 f, v$ r6 W
5 M o# N# b& a) E* J
1.2 空间消耗% l# \5 `6 R- K7 k0 T' Q% }
) Z2 a( {4 Q7 T; U; j
所谓的空间消耗对应的是空间复杂度,在排序算法中需要开辟的额外内存空间是多少。如果空间复杂度为 O(1),此时该排序叫做原地排序。3 Z4 f- V/ L) T; ^4 {$ B& e1 f
& h6 P" H b4 ?4 c8 ~4 b
注意:是额外的内存空间,存储排序数据消耗的空间不计。6 v9 T; U0 p y/ D( S
& E& d+ D6 q2 h# f0 C 1.3 稳定性
% Z6 g+ h& U' R2 W8 x! @: ^
- H) G9 d/ c) m. J p8 N8 \ 算法的稳定性虽然我们之前接触的很少,但是稳定性也是衡量一个排序算法的重要标准。什么是稳定排序呢?比如有一组有重复待排序的数据,排序前后,重复的数据顺序不变,此时该排序为稳定排序。否则,叫做不稳定排序。它在实际应用中非常重要的,今天我们就不多说,以后会慢慢分享到。1 R& C2 ^/ x% _& y O$ X
d0 [4 Y( n# W, d 2& O9 z' J3 _, [ h/ ?
( c3 }" C" I7 M4 [- v2 d 什么是插入排序?
% b; R8 Z+ \& w/ V" h ! E, I& }3 f9 g) u, J6 [
顾名思义,插入排序就是通过插入的方式来排序呗,最经典的就是打斗地主,可以将打乱的扑克牌作为未排序区间,手中已经排好序的作为排序区间。每次我们摸牌的过程,就是从未排序区间,通过插入的方式,插入到已排序区间。那么这个过程就称为插入排序。
( Z, i1 g g R1 q: ~6 } , m: g, h% w" Z4 S& N
8 N! Z! x8 f! ]) n - U' e1 _8 k. N" Y# }8 k0 k/ B4 a
3* y4 ~/ H) x! b( B/ k* ]
4 ^. i* U( Y R 如何实现插入排序?4 {( l& f9 M2 I" ~5 H; g- P2 b* ]
+ R! m! `& K/ o; ~6 y4 Z 上述插入排序的概念我们已经理解了,那么给你一组数据,如何来进行插入排序呢?
5 Q- u2 y- I6 V ! `7 \" X" x6 m) t% B2 x/ L$ ~
6 f r0 w( [* m0 U+ m0 O
7 ~3 p4 u( W$ Q% p( G& x2 k6 |0 u2 f
首先我们要将数据划分为两个区间,已排序区间和未排序区间。2 i: r" N. W2 L' a5 s9 J
) m1 [3 W5 r4 k0 T2 P' t2 h ( g: W4 K9 c6 h, `$ P! i
4 ^) m. U" a; w8 ]) n/ C8 r6 x
/ k g0 F- D: k5 n
, u& Z- M0 w k$ e! ^ y; y. L 我们从未排序区间取出数据和已排序区间的数据进行比较,如果小于已排序区间的数据,那我们就交换数据。
. p# x+ U% r5 ]! b
$ F+ q9 x. {' R4 P" v + [ d- E# @6 W6 i
" V6 R: j( \; ^. A
. s! t# n& {/ i: K9 f( g
& i9 K6 G1 C( O$ n5 Z0 t0 w/ |
如果交换到已排序区间数据不在大于插入的数据,然后将元素插入进去。
2 c5 b9 R8 Q- |( | 6 k3 S3 m/ K, r+ P- f/ L
) }' U' j0 [" B8 D. ]7 M0 Q
3 {! t4 K& _" b: t( x0 {
) u& r/ W& U3 t: e ( q$ }, e$ J. L/ k5 m
最后我们看一下总的插入排序动画和代码实现。
+ l. V6 l) J5 }) w- G
* z0 e" l: f, G8 E1 `6 H
6 n& `$ M+ |$ J+ s 8 E- y7 b' @( K' ]* c8 O
4
1 Z- I/ O- D' z& g- J6 D4 l C . j, r( A' @& q* U
插入排序的性能
2 X c; @; h* x T$ t
" k9 n, F; f+ n7 K' Y/ O p( s1 L 我们通过上边的对插入排序的拆分讲解和动画以及代码实现,想必面试官让你手写一个插入排序可以轻轻松松写出。但是我们掌握的插入排序知识还往往不够,我们在实际项目中,还要考虑插入排序的性能怎么样?因为才能更好的选择适当排序应用到项目中去。% O5 j4 `, c! [0 I8 U+ l6 t
. c( c. T# `. G8 k& ?2 z 4.1 插入排序的稳定性9 \# x( f2 Z- ? ]2 J: h; G7 y
* W# c# ^" e& B9 [ q! E 再插入排序中,如果存在重复数据的话,前边的元素再插入的过程永远在第二个重复数据的前边,所以插入排序后的重复数据前后顺序不变,所以插入排序是稳定排序算法。
* c1 U# c1 t# `9 M8 H0 x1 [2 J ( o/ j5 [6 w4 W( Z- `' F" P
4.2 插入排序的空间消耗
" M& r- }4 ]( o/ k6 g( p6 F ) b6 f* Q, Y+ }( @( _+ R
我们可以发现,插入排序的移动方式,需要消耗常量级的额外内存空间存储,也就是代码中的 temp,所以时间复杂度为 O(1),我们上边讲到,空间复杂度为O(1)的是原地排序算法。6 [: n [* M+ a' u+ a
0 t6 b1 L* X$ H6 D6 W/ A 4.3 插入排序的时间效率: }9 `* W1 }3 J6 T' M" k( `
& H; ]6 z# a9 r3 C
插入排序的最好情况就是不需要搬移任何数据,从头到尾寻找插入数据,每次只比较一次即可,即一组有序数据,所以最好时间复杂度为O(n)。8 Y3 S' |$ e" z0 ^, M
$ v: P2 y3 {5 ~: s 如果一组数据正好是倒序输出,那么每次都需要比较移动所有数据,每次移动时 n,n 个数据时间复杂度为O(n2)。: P# v% U0 O; ?" T3 F2 e
5 B8 d* a" K0 n4 a- v5 Z 对于插入排序的平均时间复杂度,每次插入都要移动数据,插入 n 次,所以平均时间复杂度为 O(n2)。9 N- Z9 p4 `% M+ Q8 U
( n/ ?* l/ b" Z" N. ?
5
" y" L4 W5 A# x) C+ p: ~6 [! n
5 I! f" } W! l2 X$ n8 m: @ 小结1 {8 y& I3 z. p& i, X
* X N# C2 X% s8 @ 我们学完了今天的插入排序之后,我们回到最初的面试官问题上。插入排序和冒泡排序哪个更好呢?
0 Z, A4 _$ M7 b; O$ I% @ ) y8 W9 e i |, ]0 Y: B" C
我们现在元素移动次数上进行分析,如果一组无序的数据通过冒泡排序排好序之后,它的交换次数是这种数据的逆序度;对于插入排序来说也是一样的,移动次数上都是原本数据的逆序度。6 }) ^( a1 i* b5 I4 A& g4 d
- ^! c8 y5 h+ e9 { 元素的移动次数是相同的,那我们接下来看看元素的交换次数。从代码上分析可以明显看出,冒泡排序的一次交换需要三行代码,而插入排序的交换却需要一行,所以总的交换次数冒泡排序大于插入排序。
( @/ D; G& S8 B$ ?" L # G. O. s% X- \2 ?9 p; H
有小伙伴会问,这两行的差别有那么大吗?移动一次,我们可以不计较,如果数据很多,想想下,两者的效率差别很轻易的就比较出来了。- s; [2 G. k2 N) N
& w" F5 i2 \7 z: t: Q( s" C
虽然冒泡排序的时间复杂度和插入排序的时间复杂度是相同的,但是我们实际使用中还是优先选择插入排序。
+ d: }! T4 s( S. \, s * a, j" t0 K: g& z. b0 h: X+ y
对于插入排序还是可以优化的,对了,没错,就是希尔排序,我们在这不多分开写,后期会继续更新。
5 G4 J- ]+ C, F8 o7 w ————————————————0 i" y4 T4 P, y s- e5 \5 h$ s' [
版权声明:本文为CSDN博主「胡鹏程的博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
) F4 @8 t2 |$ P: M# W 原文链接:https://blog.csdn.net/lyshark_lyshark/article/details/126792708
0 ]8 _" [( O9 o
3 P+ u- d9 O2 J8 A) a4 ~ 8 s3 E4 l: w( B! I
zan