- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 565772 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174954
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序
0 c7 E2 ?( T; a# S4 m, j
: y+ W# k8 W/ a; i6 n0 L$ V前言9 d% [. R4 G( a7 L/ U# Z
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
; ?. k; _* V, @, E; } q# h3 D' k) l+ K1 g7 a; S) j; w( Y4 [
归并排序
7 ?% @" v# N7 _0 |! `3 {8 L6 @基本思想
! ^3 k. N' B2 F4 t; ~6 S 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
& _* o+ s8 R. v8 E
) k3 j) ]$ W7 z4 n3 i
; F9 ?0 y( I) P6 L0 V" ]- {" o N* t* E2 n) A4 U' G) {. s
合并的思想其实和有道题目的思想如出一辙:/ c- Q' d$ ?* ?% N% @8 H( J
& t0 c( m1 B/ K6 E8 r
' N- t, P& |+ k& D3 U
6 D6 O* H: r. r* V) J% \ 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。" f; T) k7 N7 x9 K& ]- o# X5 A
1 [4 ?- i$ e% X+ F9 I: Q$ H[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]2 B" \4 e# `) c/ i1 o1 Y
5 N3 t$ B2 g: B$ U1 N; _" qint* merge(int* nums1, int m, int* nums2, int n)
% p2 U4 j3 n: Y{
4 Y: N* R# R! j$ d+ I, S0 } int* arr = (int*)malloc((m + n));
8 X: }% X3 v) E; ~2 c/ z if(arr == NULL) [1 D: y1 \6 D$ ?7 Z* b5 _+ G
{
' J+ Y& {( Y1 n) s7 N8 k+ U, n3 }: M perror("malloc fail");9 T8 Z- e8 T" w7 Y0 ~7 [! a$ b
return;
3 L/ O, B, S& d+ f9 m: w }
5 V; r4 y4 H! s4 H9 _
: j% z9 S+ O" N; d9 w int p1 = 0;* R' ], x* v: D% b6 u
int p2 = 0;! B! t/ [( ?' \. z9 S) c2 Q$ e# E
int cnt = 0;4 d9 P. ?2 A1 f+ D# n8 _- m
while(p1 < m && p2 < n). Y- Y7 j+ d$ K6 T* K7 z: O4 d
{
4 @2 y# M7 H9 X if(nums1[p1] < nums2[p2])
i+ N, N5 A8 [5 F2 D2 b- b1 V5 u {
! A* t8 j+ M2 V' A1 z arr[cnt++] = nums1[p1++];) d3 p$ [0 j& V0 e; `% _
}8 u+ t3 L6 V4 T+ T) Q4 S9 G. ^
else
- b- ^5 d) M; L: z/ f7 S n {1 |! R$ c- g6 p. W9 ^2 o
arr[cnt++] = nums2[p2++];
1 Z: e6 F+ |' i# D( o }1 |; g- E4 p) {3 \) {2 M8 L
}& r1 `' ]' x9 T( L6 f
while(p1 < m)
6 C! _0 R- l0 m+ \1 C arr[cnt++] = nums1[p1++];
) |6 c2 d. n+ @! s# d0 L; I; ^- s3 w$ L: S7 Q
while(p2 < n)
. D. F( I/ o! s, d1 \0 j arr[cnt++] = nums2[p2++];& l5 j9 C: {" T% z2 K) ^1 Z/ W
& c# R+ o: c+ q$ ]7 F
return arr;
? U0 A0 v# K+ B}
, c6 I2 j, `# j0 w9 n+ F7 N9 v) k/ r( r. K: @
1
; l2 d9 U8 s3 x1 Q) V2
8 o: p/ |! ~5 e6 [3
& W0 P2 a" K7 O1 c1 j; |42 G1 S, I3 q& Z9 z s
5
! r5 N' w$ p, c, j9 w/ d6; c. @6 D5 P" ]/ i' ]2 |
7
, V9 Y& N/ o# Q3 C' \" ]# A G8
" L$ u/ E' ^& P8 _9. d; G: }5 M/ s3 Z" ~5 e! A
10- w* A/ f/ q+ J% a3 X {
11) e% l' c8 e7 h y
12
) A. j+ R7 S2 C N' X: d9 c6 b132 Q: }+ t/ |. S# P3 d; Z1 e9 Z+ U4 A
14
3 z/ N6 V: g- T4 g15% _% {9 Z0 ?% [& I+ x; w L
163 d/ A& X% u" ]/ T: m+ u
17
0 t7 A& |6 ~( T4 B18
) @/ f3 n2 y* I9 t. J7 M; H! D! a# Y19
" Q+ r' |0 `: s5 e! ^: Y0 \# U) ]20 Y# K, s5 N4 X4 }, P
211 M0 z# h; y7 z' V6 I+ u3 Z
222 f8 B3 O# T9 h# s
23- K/ k" V3 m4 _7 L) q
247 O: t# n. {( {* i: L
25
% v/ {" k% G& [26+ j- O b- J0 T3 G3 h
27
2 x4 w6 R, m: a! v n8 p28& B+ N- D* t9 e5 o* w, S, d; N9 O
29
% F2 t) [. x, e/ |3 l7 i30
5 R9 n2 L' t: B5 S" G31) B$ j7 Q- f3 z# ?( G* f& k
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。1 U7 r: u. b5 ?7 w' `
# [1 j6 s$ }( a- {- j0 E$ _
递归实现9 D. P+ n, S( ]; V0 z6 _( [1 U
通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
4 d. @/ |6 f3 G9 y* o3 F, K8 L* V7 n! T0 G7 V" A
h% w6 y1 b/ o' ~; p
; g) J, M' b8 ?) S1 q* f, G6 N" F( C# [" \0 y9 ]- Z r4 E2 {
/ t% r# N$ q. y2 e6 }void _MergeSort(int* arr, int* tmp, int left, int right)+ T' F2 m, @! K/ J0 d- v: G8 G
{
`' u4 ? D7 D" s4 W3 _ assert(arr);
% O6 ]4 X9 h! h g, r
# s( N8 h$ T- ^( T% X. q9 O if (left >= right)//递归结束条件不要漏了/ T- i8 L& _- Y' c5 a( q. \1 `
return;* e4 j2 R; E f3 l
$ k! Q1 |% q4 H2 N% v int mid = (right - left) / 2 + left;
) w6 B6 k% K- r1 ~& U2 U& k" B, I: d+ [) J
//划分左右子区间[left, mid]和[mid + 1, right]
z* _) t1 C& j8 \8 J a _MergeSort(arr, tmp, left, mid);
, k$ f! S: t$ Y5 I: A+ ~ _MergeSort(arr, tmp, mid + 1, right);! }* l- o3 j( G+ Z) c8 `
* k% X( Q D7 l# g* s1 [! m$ j; g //归并: g: v6 d5 X9 D& w# i
int begin1 = left, end1 = mid;
2 z6 ]! e0 b r8 @7 G# D int begin2 = mid + 1, end2 = right;& i- g/ v2 X+ d5 ~) U
int i = left;+ `) [0 N6 K% q2 P
while (begin1 <= end1 && begin2 <= end2) b, ?+ L" _' f$ \
{$ F/ c" z% R; N, X5 l0 H
if (arr[begin1] < arr[begin2])
0 T3 j. ?1 t y6 v8 c tmp[i++] = arr[begin1++];
f, h y# T. \1 n1 L else
0 i, J% p, A5 B/ b tmp[i++] = arr[begin2++];* s4 O8 U& @- F/ ]( ]1 @ V& W
}6 A0 ~/ ^) X( Y6 Z) P$ I
9 l1 s4 H$ W, A% f
while (begin1 <= end1)
/ z% G" k$ s. | tmp[i++] = arr[begin1++];
* s4 s \2 {! P while (begin2 <= end2)
, j$ f5 a8 F$ m! l- m3 Q: L tmp[i++] = arr[begin2++];* K$ I) \2 n% M4 \/ @2 f& o
' l3 s( N8 ^1 {3 h, d
//拷贝回原数组——归并哪部分就拷贝哪部分回去1 f; n0 I! l& E$ ]1 x8 Y
//而不是拷贝整个数组回去. V/ @$ G5 i! q9 z) @5 S# o, `- U
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
* Q& T7 q" J! I' Z3 M- f}
o Y6 z/ Q+ l4 E
5 V2 f$ Y4 a& v; C+ W Wvoid MergeSort(int* arr, int left, int right)% k- o! S. T1 c! @0 c
{
2 w- s7 l$ G2 j) s5 T. \ assert(arr);
, ?4 x: V4 y, d: N" N" ?& n2 t6 Z( I! f
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));# ^; ~: h7 d8 w3 R3 S. w8 K) D4 d- D5 @
if (tmp == NULL)
* q( Q( s5 A0 ~ G$ J {- ~* l n1 _0 v. Q3 \* q
perror("malloc fail");, w% L9 E2 n+ w2 M: s/ h0 C
return;
% D- A6 n2 i0 X" ?5 d }
! O' b9 |! @8 b4 G% ?0 {7 W; C& k/ V0 [ v- E
_MergeSort(arr, tmp, left, right);- |) p2 H% q- g5 C* U
, U% _9 L/ B/ _! [ free(tmp);, m$ H; R1 O8 d& M/ b/ k
tmp = NULL;# ^1 a% A( ^9 |0 h2 M
}" R) u' h( M1 v1 B& R/ m% @; K
5 k& ~! `6 z4 `- k1 R
1" R! P A6 K; j
2
/ F0 T$ C, b% N- h4 t3) V3 Q! K; `( f5 A! I
4% @( w( d0 L/ W0 i. `
5) b! D- @8 }, D
64 G: v7 T) T7 ?$ J
7& T: D b+ y% Y0 g X
8" _4 X$ _% y; p; f& W
9
: L4 D5 b2 S5 D b0 i; \2 q10, a \3 w* S f
11
2 n1 ?4 d2 @5 j0 Q/ u3 {8 d# ~12
! k$ t' v& ?2 s4 [. `! m13 I- [+ A# }$ A5 X2 W
14
) g& J* [4 O R4 S156 E# \# o6 ^6 b2 {9 v
16: T/ [0 ^* `! u! _) v
177 i) f, g) R2 f+ v
18
\1 O. B$ p$ u0 ]/ q19
- T3 P ]+ ^1 R( [0 M" H( |20
- M, _+ `1 q/ c i$ y( u4 m21% l- k. m% i$ q2 t% v. `, A, v8 g$ y
228 i) W) e) x) d# |2 B: k
23- U* B' z. ]) ?2 F/ {* M* S6 P
24
7 z& v8 v5 L p3 B$ f4 g253 E `" L( `) x+ v9 o; a
26
& C9 w! J+ r4 W7 C27. Z8 [6 X/ k* q8 p2 ]" R* X. b' v! u
28
O" _ M0 p% `29
9 B* ~6 f( w9 k2 l30: \. g* z4 ]6 b+ ]( O7 o: N
31
$ r- R& W8 W$ c32
0 ^/ P9 ~3 D) {" K. X& p33' I8 p& D, O: M! m
34
: W6 ~, o9 g- Q; r: `1 K352 @+ E, p# N D2 {( p$ f
369 w; B3 ^# g8 v
37
, S+ w: \ W0 g38
" q7 k- U. X9 [. f39+ V: i0 d/ ?, T/ z9 e& M
40
( X/ n7 n$ o$ u! v41
$ l) X3 l* [' _0 y; t42
, [0 k4 S# t7 ?/ x4 \3 G+ P0 ~! |43
* J& D" m' E, a$ b- l$ A H44
7 s: n, h+ E, t4 D7 s' N45& D( W( e7 p, v3 V
46
0 r2 a5 O! |9 v$ G& P47- x$ r& U" x' r# G; Z: e* w, z1 g K
488 y w$ d0 F$ I4 K0 j( {( I/ `' G
49
) A' x a6 ]; o50! l) A$ }5 `9 @& ^3 Y3 V. x
51* q1 q# B. M( r+ |, }+ _
非递归实现/ t! i' Z: d# u
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。+ R+ e+ L' o2 B
# ^9 d: w' G4 i8 ]6 c2 `2 F
2 G6 J4 D( F' N' r
9 C; y0 e7 J9 x: p
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。& Q( ^) C" E+ f' v) M" v
! A0 h6 t Y9 k& C5 ]7 x% ^ 还要注意区间的取值,每个区间就是一组,就有gap个元素。 v' |5 T- `; q8 t
% b/ g# X t p7 Z
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。4 F- O; | }9 u' K7 R* x
3 O, b; Q& c4 Z9 u0 P
代码实现
; N" u% L: M& T' O" B( G! y' b
7 \9 ^- u5 @ F+ Evoid MergeSortNonR(int* arr, int sz)1 t4 s# o6 i- n4 M
{
1 S" L. g! ]. J' F k8 m assert(arr);
+ v* v3 ]% f' |. e8 A
6 Q6 {1 o. q1 Q# F& J int* tmp = (int*)malloc(sz * sizeof(int));
( x9 K, p3 l0 x7 _- j3 T! o if (tmp == NULL)
' C2 d# E. x# J S {
8 U( y3 V' p5 s& p0 Q- ?- w+ \% ~ perror("malloc fail");
, Z( {" B9 r- m; ]7 i8 L' n; P3 P return;
; n7 }+ e8 @1 S& \) d/ Z }
$ K6 m) q& @: T5 @( H: s
k+ l8 ^2 [4 }2 A( d( Y$ r9 n int gap = 1;
' G3 F! [5 {( L7 i( C+ P8 m while (gap < sz)
! G( j9 l6 Y) D+ i" K {
5 R4 w5 w% ] o' p E4 g for (int i = 0; i < sz; i += 2 * gap)
$ Z& K/ H( X" I' r5 F, a {1 P' ~1 o3 m. ^( _) B7 p
int begin1 = i, end1 = begin1 + gap - 1;" j& ?# u" n9 ]' l
int begin2 = end1 + 1, end2 = begin2 + gap - 1;6 k9 N3 O7 O, s. [7 @: a
int j = begin1;
% R* m+ F4 y9 z- S6 M& B. w- \8 O; U% g$ Q- X+ `# X1 U! v/ s
//归并
% x3 h; ]$ Q- }$ v* M while (begin1 <= end1 && begin2 <= end2)2 y c2 a x z8 f8 Y+ D/ G
{
* i' }6 X# L% Z2 s if (arr[begin1] < arr[begin2])
5 y# Q* G! n- ~2 H! ]" p tmp[j++] = arr[begin1++];
4 y' {' T+ O( V! u4 z) ]2 x, V7 x else
/ u5 j E+ q( \( _ tmp[j++] = arr[begin2++];
2 a# F# J' @- Y }
) H! g) A& s! W: h9 T; C' ~% R3 T/ k9 Y/ j% K" z5 f2 E+ p
while (begin1 <= end1)4 j; U- v0 c4 L- }2 I( \$ B3 e
tmp[j++] = arr[begin1++];$ i! f6 f8 ]4 l# ~; f I0 \
while (begin2 <= end2)
5 t) H6 e9 B( N8 e3 a+ D8 H0 }# k tmp[j++] = arr[begin2++];
0 D) `- I3 e5 b$ Z3 e
3 X+ Y1 ? I* E/ O //拷贝回原数组——归并哪部分就拷贝哪部分回去
& n/ l- Y: ^4 M memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
4 Y; ]# d$ v2 { R4 U }, K# o- D" P; n
gap *= 2;. A) |$ n( { f+ m/ Y4 ?' A" O1 s! ]
}
" Y- c/ E- d, s4 m; v& v) i N' u. X. e
}
0 w9 y) v) |; E. s8 n' h! g, I4 G: Z$ H3 v3 B
1
- C" ]9 B# l N' c! ~, Z2- r/ `: w" s& A* e9 ^! K
3
2 V; Y; n5 S. D v/ T5 Q4; {& T6 y# c# ], y) G
58 y6 i6 D; C @$ A3 x' i
6; l. L7 O+ ]/ A/ C# z
7
" e0 R3 e$ T3 A+ T8; G3 w( _9 E- O7 ~) L" ?$ h9 K% R
9- l# S+ F9 C. l+ C1 p9 \. H
10
8 P( i2 s& B0 g11/ e9 c# C. [9 T/ }% A
12
/ c( u/ l0 S& A2 E7 U/ k" {& L6 g13
/ Q9 f8 u* u5 Z2 O& Q0 [ ~14
N1 L5 z9 H* l5 j; B G! m15 m/ r, y2 s% V7 D. b+ [
16! B' C5 a9 L4 h, i" g' C
17+ |" T8 N# H; Q. b9 Y+ @3 _
18
6 P+ Y( Z6 h" c19
2 M2 Q- h2 H. I2 B8 z! j20
8 H, `2 T: _* }21
) V" i6 X3 b3 } |% L228 t; I! M4 u. z- M
23
: G; R, F; e. b) X+ [+ Q242 T( L0 b3 i3 j `9 {
25$ q8 H k8 ?0 h, q9 G4 [% W: @
26% Z# x- D! s$ K! N/ D6 a
27
7 D( N* G) I! q6 c28
) k, a6 }+ G& x" M5 V. M29
9 B( `+ B5 x6 y. D30
1 D5 ?/ r6 G$ g8 N/ u31
4 {2 H4 N& S" W b32
1 f9 z7 Z% s# m33
$ [) K+ d3 j+ a( @34
1 u. Q$ B1 y% d0 y, [7 q3 o6 n35
* t! d; \3 m r361 a4 l: E; j1 S( f4 _, W
37
?# B( Y1 e/ s38
: x/ j* z: n6 T+ G39
5 c+ {8 `* u [ Q401 D5 c6 ]* S) z; t7 D3 z5 o: D
41) m# D" p7 \7 m6 E: C9 k, {
边界问题
# C' Y' Z* v$ } 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。: }7 O5 O) G" I/ A
6 G' \2 Z! z* B( j6 T T9 d) j
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:0 D) K4 P. M6 j2 k8 D% [9 }' ]
+ ]2 r& ?7 @/ m( L5 `! _+ h$ a4 B9 ~
1 H! C5 @- o: q0 Q; h: I/ e4 A% ^$ N
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
9 \8 c5 ?1 Y, Q' o6 d+ l
; y+ E5 R1 K( J0 `. @1 [1 Q第一组越界(即end1越界)# K+ \ w+ D" V$ D# `
) {- t% Y& c0 e# v应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
/ `- v) C0 n, n0 [# S( E9 h6 O) m$ Y* p- \5 d
第二组全部越界(即begin2和end2越界)
9 S8 g/ r+ F1 z! a1 h) Y$ f* _0 P, q! d5 H
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
4 Y2 E& t4 H% P' o
9 c+ r0 y, _% n0 R第二组部分越界(即end2越界)# |' |& g, g4 `+ m! f
/ q% ?% n+ ? p- o应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。: _5 r( w' M! k2 C& T3 S# \9 Z
! W% w! m+ ]9 o- N$ i: Q+ H0 Q+ X
其实第一种情况和第二种情况可以合并为一种情况,原因:$ x% J$ p8 J U1 e- f+ L' z
! s) I8 V* m( i* l% I% x( E' h* d end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。" y ~5 |6 c" K% J
$ K. l7 h' h* n; S! R& u; N; P' V3 w
拿两个数组试一下:
, r) P' p0 j3 `' |5 b9 D; |& {9 b" w. r0 A
; W% m) e. L! m/ r o# S+ M
) n" K o& x2 P2 p' E' K8 ^
) f1 G; s9 ~& U8 U1 _( e% x9 w* i3 E7 X3 k4 T5 e, q5 _& M
代码实现- H4 F+ ^: t2 D2 v
8 I! T" k; G- i% n( @
void MergeSortNonR(int* arr, int sz)# R- w% U1 Z" [& ? ]! w, u: p
{2 t8 N9 M3 f1 h U1 J
assert(arr);
4 s4 G( y H, k5 y7 y
0 y y0 X: [& a* F5 M1 m' v: E; H8 H int* tmp = (int*)malloc(sz * sizeof(int));, E: b' j3 {9 O& ?/ q0 g
if (tmp == NULL)
9 I. \0 Q. z" { M: v, T {. b+ ^) m9 c3 g# ^5 c
perror("malloc fail");
' k# c* v# W/ v k7 Q t. f return;' n: ~( @- W( g$ w# o+ M7 t+ }$ ~, O
}
' @/ K: a) y8 J- F6 W; d, u1 d2 O6 n) \; l9 P" e1 Z$ _3 s& o; G& Y
int gap = 1;
( v$ b; ?' t+ m2 j; r6 y while (gap < sz)( E( }5 H2 G8 X1 F1 S5 Y! y: C. {/ S
{
# o# z8 |0 P; E0 C5 N' [0 ^ for (int i = 0; i < sz; i += 2 * gap)& `+ a- V' u3 x; c* c/ q4 R
{9 D" W) p" I1 [" @0 U) ?, l( p
int begin1 = i, end1 = begin1 + gap - 1;) ~; @, k1 Y6 d( d/ p' u4 {+ x
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
T: l. J+ P) Y* n int j = begin1;
/ N- a( I- r- b) v+ ^7 Y //越界检测9 F4 {/ w8 {; c) b. z, c
if (begin2 >= sz && end2 >= sz)
* w1 Z* J$ l5 q- o# y' N+ | break;( i& W6 {$ ]& U1 o0 F
if (end2 >= sz)
n) }. x) W) `5 h, ?+ g end2 = sz - 1;
8 E; n- z* N; B5 U7 p //归并
! u) ]3 T9 Q* }4 @* m4 x while (begin1 <= end1 && begin2 <= end2)
, ~3 p: B, Q$ ]: Z$ a {
/ N7 W6 `/ ]: t+ C3 ? if (arr[begin1] < arr[begin2])
) q# U8 P% J% A4 Y( ?3 L) f# ~ tmp[j++] = arr[begin1++];
9 j9 a6 X0 k) q7 W9 o else [, B3 G, d; l t
tmp[j++] = arr[begin2++];" p; |" I) x$ ^ c8 c/ V! J' m
}
9 } l3 ~" H# `: V/ M3 W5 A- s. p7 M) O& U" A# y# d& t
while (begin1 <= end1)" K; d q( |/ M3 ? _5 p
tmp[j++] = arr[begin1++];
# ?: \" l0 e' K while (begin2 <= end2)" p% P. O M9 e5 H7 r4 v
tmp[j++] = arr[begin2++];7 V+ V8 Z2 O1 `( s) ?) J
1 c! o4 z. Y" n& O6 f2 h
//拷贝回原数组——归并哪部分就拷贝哪部分回去0 l7 |4 l) {' h. k# ^ y0 R9 c5 {
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
, r F& { c3 m; }6 g/ H+ N }
1 S& u( s! }: o6 |5 n gap *= 2;" D5 p: u5 B2 T5 _
}
+ v+ U! ^8 ? Q5 S! E4 Y' B/ ]9 W
z* M9 X0 \; t( T1 P5 h, ]& R}8 `+ k+ Z2 Z! A
, ~9 b( Z/ y( E& q+ y
1
. R" R) r [( C/ G2
6 r$ g5 v+ B. W: U3
5 ^# d# @+ L7 f9 c3 s4" w+ b" N) h- Z1 v
5 O0 L+ }5 C1 g0 Y- m+ [6 l. v
6
: F/ `/ ]$ Z$ [8 B y+ X8 H7
9 X2 s, m4 W: ~. f$ B8+ i" N3 {$ O6 V) c6 y
9' f2 M5 p6 n5 n* e) z* T
10% k( M; x5 Y: ]
11
; M, U) L2 p: G( P0 K# \12
1 k: n6 B: j: ?! `( `135 M2 y0 m+ c$ l4 c3 s8 |- T/ u: Y8 ~
14
n& Y4 _0 _+ x) U5 ]15
. y H6 z( g) A z168 _1 k4 }( E3 A4 }& q" x7 l0 V" K
17
2 Q; s: p+ [" i" t9 w+ f18
; ]8 A; v' ~+ o8 w1 v1 f% O$ S191 O; @+ B5 s0 n1 ?
20
# ~& M" G4 v' r3 w. F; N21
- z# Z* V" X8 y8 j8 p; m( i22
+ a; E5 E; |5 ]4 a' H23
f% o" F; j) w L- F, t24
+ p8 ~2 r/ }& J- V5 t) Z' A/ s4 H25
$ E3 o' t1 ^$ @0 N! U26
/ Z% O: `0 I9 q275 Q& H1 `9 n/ D2 G, \" o% v8 t
28
: ~2 I# l8 ]# ~ p, s# M2 W% u6 a7 x* f290 J" Z& B# z; P+ n7 @/ c- }/ s
30
( k! u# J2 N/ K* L31+ M9 J) X# E) s! @: i4 G) A# f# U* s; Y9 V
32
; @' o/ |8 V. c1 d1 I# h333 M# J/ L4 @/ \4 H3 D
34
" q- A7 E! L# s# f% e/ e" g* o) S353 _' q3 d( v2 l+ _
36% u5 t, m: |; C; F+ L8 F7 c; g
37( _* v3 n1 P2 C1 R ^# X; |- H z# m
38
! j) @( F# H3 ]0 ?39# m w. }4 `# B, K
406 Q3 `, E& T/ c
41
, ?% m, j3 a" R8 t6 D42# e* g2 t& a. `% S- S" q
43
- n N5 ^, U/ P. b0 L44
# l' a1 Z5 S, S) e0 M8 B$ L# ^455 V& k7 g1 Q$ y7 I
归并排序的特性总结:
3 c8 `! |6 U# Y. @( U
( {2 P l( G6 J# E% n归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。 f& F4 L7 U# o9 v# A: V/ S2 p
时间复杂度:O(N*logN)4 L, w$ I) t' J$ r; }
空间复杂度:O(N)* x- ? o0 n2 K3 [
稳定性:稳定
, X [; o* W) j( B/ R3 ~3 g: J ?
0 c: B* O4 K0 _( `/ A————————————————
. J4 q4 T" w" ]8 `7 _8 \版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。6 ^8 t8 d9 e$ O2 S7 e6 _0 f
原文链接:https://blog.csdn.net/weixin_61561736/article/details/1267966574 p! q: L( V/ P; ^% K
$ N9 {. A) M* Q" _0 t3 b9 l* ^
- b- L- {1 _1 K+ x) U3 K; P. q8 Z |
zan
|