在线时间 1630 小时 最后登录 2024-1-29 注册时间 2017-5-16 听众数 82 收听数 1 能力 120 分 体力 565654 点 威望 12 点 阅读权限 255 积分 174919 相册 1 日志 0 记录 0 帖子 5313 主题 5273 精华 3 分享 0 好友 163
TA的每日心情 开心 2021-8-11 17:59
签到天数: 17 天
[LV.4]偶尔看看III
网络挑战赛参赛者
网络挑战赛参赛者
自我介绍 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
群组 : 2018美赛大象算法课程
群组 : 2018美赛护航培训课程
群组 : 2019年 数学中国站长建
群组 : 2019年数据分析师课程
群组 : 2018年大象老师国赛优
动画:面试官问我插入排序和冒泡排序哪个更牛逼? ; g. C: W2 z/ B' G( A
" g6 N+ T5 x" P; }
写在前边
. X) \8 v+ J2 ~) G/ B' u0 k 0 L! Y! M8 g/ y. ?
/ I7 S5 F- j4 Y2 F2 F* u
排序对于每个开发者来讲,都多多少少知道几个经典的排序算法,比如我们之前以动画形式分享的冒泡排序,也包括今天要分享的插入排序。还有一些其他经典的排序,小鹿整理的共有十种是面试常问到的,冒泡排序、插入排序、希尔排序、选择排序、归并排序、快速排序、堆排序、桶排序、计数排序、基数排序。
, \& t6 c5 j. Y% _$ ?7 V4 }
4 Z) B9 k. `# k( I9 P- ^% L8 ? 虽然我们基本知道了这些排序算法,但是在实际项目开发以及面试中往往出乎我们所料。在面试中,经常会被问到各种排序之间的比较;在实际项目中,往往排序的数据不是我们所练习的整数。# r ~0 E( G ^
[* g/ ?' z; M% C# c3 S
那么今天我们来学习一下,插入排序比我们之前讲的冒泡排序有什么区别呢?面试官问我们,我们如何回答完整呢?
9 m2 O$ T3 E( T7 B) o* w
. I+ a9 S$ `+ l" v4 f2 n 思维导图6 v$ K; d0 K# @6 f/ u: \- y
4 D; K6 I. n7 `- }
4 Q$ W1 C7 U9 ^+ i! A3 Q9 d , v+ m' s1 A) w* {$ s; S
% M0 z. ]" g" A( F 1
1 L* `: t' Q& h8 @ q
3 s: O( j3 y: T1 ? 如何分析一个排序算法?! Q: C9 F+ c' R
5 ^8 G; R7 P: R5 i! H
之前写的一篇很详细的文章。
3 n2 n, y7 |/ l6 {$ M1 o * L3 \3 C. s" g$ I" X" S
佩奇学编程 | 复杂度分析原来这么简单& x6 o* S9 f( f
" c/ m; l5 u- S6 E o# b7 C; _ 分析排序算法已经成为我们衡量一个算法优良的重要标准,从以下三个方面入手。 i$ C$ y' i' i* Z2 U4 O2 ~8 }
2 G- u5 x+ ^8 J2 X: I. q
1.1 时间效率3 f- F2 z) f' W
2 T4 j$ u+ O; `' ~ v( l 这里所谓的实践效率就是时间复杂度,相信大家对于时间复杂度并不陌生。6 ?3 x& Y3 m# S& N% \! |4 G6 z
$ D" z. R9 l- a) u7 d" [ e
复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系。
' j# @ F( d+ X7 K3 _ - Z' R- J) Q8 l8 a3 m+ q
对于时间复杂度的分析,要把最好时间复杂度、最坏时间复杂度、平均时间复杂度分析出来,分别对应了排序算法的最好排序情况、最坏排序情况以及平均排序效率。1 C. {5 g1 X3 M+ a
a( w. V9 l( o+ }0 Z( F" M 1.2 空间消耗6 G/ _% _, a9 r) `7 m+ e2 D
, p/ ]( [) ]7 X7 A2 K 所谓的空间消耗对应的是空间复杂度,在排序算法中需要开辟的额外内存空间是多少。如果空间复杂度为 O(1),此时该排序叫做原地排序。2 \* c4 |2 H1 v( \6 _# g0 {
9 ?8 X* N: K" s4 `. N1 I
注意:是额外的内存空间,存储排序数据消耗的空间不计。
1 E! x- {: C. N, e4 D& e, J 3 V9 R1 I9 m7 y* n& g2 w1 p* `' W( x
1.3 稳定性5 j/ D6 t1 b9 }& L- T4 c" d, ]/ Y
/ I* g0 `0 @9 \" ~
算法的稳定性虽然我们之前接触的很少,但是稳定性也是衡量一个排序算法的重要标准。什么是稳定排序呢?比如有一组有重复待排序的数据,排序前后,重复的数据顺序不变,此时该排序为稳定排序。否则,叫做不稳定排序。它在实际应用中非常重要的,今天我们就不多说,以后会慢慢分享到。/ n* x A( H+ V
; b1 `9 w. H. j* [2 y 2 W& S6 i/ ~% w% g/ @% z9 q
+ b, I+ L6 E( Q8 G: c6 n
什么是插入排序?
" R9 m. p9 c7 B, x; N
% r5 ~$ C& m& Q! i" n 顾名思义,插入排序就是通过插入的方式来排序呗,最经典的就是打斗地主,可以将打乱的扑克牌作为未排序区间,手中已经排好序的作为排序区间。每次我们摸牌的过程,就是从未排序区间,通过插入的方式,插入到已排序区间。那么这个过程就称为插入排序。
+ K9 U( y" {, y
( h( y2 k5 X0 V * K4 G& Q# q+ I* H
0 [9 a( [* P0 \% F7 g 3
( C) a. X) }/ K8 V ( ~0 z' B) P6 S( i8 M5 D/ m* M6 V
如何实现插入排序?, J8 @: E( c$ O* \; V, _2 n$ W
+ E8 C( A: r9 w) \! g- J 上述插入排序的概念我们已经理解了,那么给你一组数据,如何来进行插入排序呢?4 d" J9 g1 ^6 G* I$ |6 J
# C, D: ~/ u: C
7 J# n! D6 l9 ?2 E$ g
; d# E5 f ?1 H) } i# \ 首先我们要将数据划分为两个区间,已排序区间和未排序区间。% A! T+ \! J5 I# a9 s; x! o
9 _( l' b4 `- _8 E g
8 R0 F. P8 t# _# f& {" H- e4 ~
" v2 h# [) r' f/ M, x; a F 3 c; i% g6 Y! }& [ g8 P; }8 z5 W
+ n/ g! V) t- N) P& a
我们从未排序区间取出数据和已排序区间的数据进行比较,如果小于已排序区间的数据,那我们就交换数据。
# h2 |9 }5 y: N4 X & O9 o( g+ [$ s+ Q7 X1 c
, h; ~" r5 i$ ?5 e$ M4 V
8 M" O- D3 d5 q' O+ x5 ? }1 b , b. k) E, |% S4 p7 k$ J
8 g2 L8 v' b0 U4 [- o 如果交换到已排序区间数据不在大于插入的数据,然后将元素插入进去。
# N O' L" J2 _8 M% V5 |1 V: e# V 1 c7 r w: a! x" q* b4 s
3 o8 x$ j1 p" p# K2 c
, L4 {" [: p$ O& c; z
) Z ]5 Z/ }8 s
1 ~: f h0 E2 F& P$ N 最后我们看一下总的插入排序动画和代码实现。
+ j6 `% _3 c# m0 Q / j! P% P' ]& g% M+ L
, x E. v( d" ]" L. a5 j2 m
/ k+ K" I6 x7 N) t. }, P8 { 48 {3 w% n# I+ O. U. u, H
+ m6 D) ?$ _% l, y6 C, [ 插入排序的性能" |+ q4 ^! Y! e4 u+ m8 r3 u
- J; `! l `2 k7 W9 a 我们通过上边的对插入排序的拆分讲解和动画以及代码实现,想必面试官让你手写一个插入排序可以轻轻松松写出。但是我们掌握的插入排序知识还往往不够,我们在实际项目中,还要考虑插入排序的性能怎么样?因为才能更好的选择适当排序应用到项目中去。* G- f# q/ P! ?' E) X" r
z- ]1 h% `6 X5 O" d3 U 4.1 插入排序的稳定性
, D- y& @, ~% Q1 \ / z; S3 E, n2 e2 R J% [
再插入排序中,如果存在重复数据的话,前边的元素再插入的过程永远在第二个重复数据的前边,所以插入排序后的重复数据前后顺序不变,所以插入排序是稳定排序算法。
1 w! y1 d" `( ]4 W, n* Q ' j; F9 C' S$ J b1 W
4.2 插入排序的空间消耗3 t3 E+ c- S( `& \! {0 t; ]) a: K& O
P( l8 e4 d j8 j# [$ W
我们可以发现,插入排序的移动方式,需要消耗常量级的额外内存空间存储,也就是代码中的 temp,所以时间复杂度为 O(1),我们上边讲到,空间复杂度为O(1)的是原地排序算法。
: b6 g8 a1 Z2 z" @7 d) ~8 s8 D
$ I, W( ]5 E& O4 K1 D 4.3 插入排序的时间效率
: J0 T9 @- h: X, ^# \+ ] ( B+ e3 x" F3 Z% K3 i
插入排序的最好情况就是不需要搬移任何数据,从头到尾寻找插入数据,每次只比较一次即可,即一组有序数据,所以最好时间复杂度为O(n)。- `; i5 P$ j6 g% g. \2 E
0 S' e3 B/ h: }4 m8 n! U
如果一组数据正好是倒序输出,那么每次都需要比较移动所有数据,每次移动时 n,n 个数据时间复杂度为O(n2)。; W3 l6 d: X( u5 V* t
. s. s. ?: @1 P1 p% x! U0 ~ 对于插入排序的平均时间复杂度,每次插入都要移动数据,插入 n 次,所以平均时间复杂度为 O(n2)。' L; ^# I7 s; x# Q# T8 m: d
* z! _8 L0 w' {6 X5 j, D 5
9 n7 J" f( q! h/ m9 h ' L: g$ h! J3 a; s
小结: k7 M: V6 P# r5 ~; q& i
& o- L$ T/ ^6 I7 W 我们学完了今天的插入排序之后,我们回到最初的面试官问题上。插入排序和冒泡排序哪个更好呢?
O2 q7 I7 e1 C9 o0 `# H- M' _- s + Z7 N- V! f' T9 L, W5 c
我们现在元素移动次数上进行分析,如果一组无序的数据通过冒泡排序排好序之后,它的交换次数是这种数据的逆序度;对于插入排序来说也是一样的,移动次数上都是原本数据的逆序度。' ^- a" c! F* V% ~" j! X( t, L3 A
' P- j9 n- q3 `0 W' @' ], ]8 X 元素的移动次数是相同的,那我们接下来看看元素的交换次数。从代码上分析可以明显看出,冒泡排序的一次交换需要三行代码,而插入排序的交换却需要一行,所以总的交换次数冒泡排序大于插入排序。
$ \* v; f) h8 g, o% j- y $ Y O- S9 f, N8 v5 |' T0 `
有小伙伴会问,这两行的差别有那么大吗?移动一次,我们可以不计较,如果数据很多,想想下,两者的效率差别很轻易的就比较出来了。
7 N- [ ~# i: j# x: W& a) n$ H
0 i' f0 |1 X: n 虽然冒泡排序的时间复杂度和插入排序的时间复杂度是相同的,但是我们实际使用中还是优先选择插入排序。
& _4 x! S# Y1 C$ m
: i# a2 m$ [, M$ @% Q- R* N, R 对于插入排序还是可以优化的,对了,没错,就是希尔排序,我们在这不多分开写,后期会继续更新。
; r9 \6 H9 I3 b7 L$ G ————————————————6 S$ U# V6 b3 A1 c+ k
版权声明:本文为CSDN博主「胡鹏程的博客」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
& O* l* T0 X- M3 s' O0 r0 P 原文链接:https://blog.csdn.net/lyshark_lyshark/article/details/126792708; x( D+ d: G& N0 d
- B1 A. G0 v- Y" ~
. s' n( n. x# D, G1 W' Y1 S
zan