8 t# Y/ |0 H2 u" h4 Uvoid MergeSort(int* arr, int left, int right) $ h( i- s* d5 I; T: |) d `{ ! [" ?) Y: @& {2 Z) ~ assert(arr); % G3 v0 I9 t( z$ A% i+ V* ^/ T; Z6 T9 e; d! |/ E
int* tmp = (int*)malloc((right - left + 1) * sizeof(int)); " s5 Z5 w% }+ h X3 G. F* l& v if (tmp == NULL)3 Q9 P8 C/ T3 l/ ]% ]
{ 7 N. z% z6 v) g( T0 j8 A' d6 X' I perror("malloc fail"); 7 o, c3 m7 Z' \2 { return;9 O9 P1 G" i `0 I4 `+ D7 ] P" }7 A
} ) R: ]5 E' _6 H H# y& R+ g7 v( y- h! ?
_MergeSort(arr, tmp, left, right); - R9 ~0 Z, [) U7 E w P E- |) x- d1 D! E free(tmp); , i4 P5 v e& v0 V6 h8 h tmp = NULL;4 T K9 \' e% h v: f
}8 _ L8 G$ J6 C' i
' f; Z' X' j% E& O& x1 , l% g4 Z% R+ }/ b2 " f" a. A# q+ D. S- W3 + c0 k! `+ n! P4 A1 K+ g40 }9 W1 |' e8 `9 r& e6 B/ ~4 m. X! L
5 & k, c4 d% i6 R8 M, T; a4 _# J6 # J+ J$ e/ Y( x5 v! ?. Q7+ }6 x6 F/ f( a. P
8: ~- M* C G# \( b7 f
9 8 f0 }9 `0 L5 D100 B" i' j) Q( X9 Y/ @ L l
11 ) m; v6 S- P6 O- I3 f! j$ ]8 v12% x: L1 B2 B$ e
13 5 g. X$ r9 F* {& v9 I3 G14 ) j1 g6 Q# U* K5 {/ j15 * Y5 |" a+ {" t% [7 ~! j16 $ o' J1 ~: ~: j17 M! y- H: Y( C, l* c! T$ O
18 t* C n# v* P$ D+ l19 ( @. l% }- B& o4 b) q3 W" D, m20: P7 R4 x+ R; b$ @
21 . z( L/ K$ [4 h# [22, y7 f% a* D$ g8 `& Z1 K. s! S
23, z/ `) C+ l# A U
24 " I2 h$ }4 n/ L9 D/ k; s; e; H$ V25& p9 {$ `, z' l) |' z9 z4 O4 K, D
26 [ S0 }7 I$ K; r27 0 Z' s( j( T* _1 G5 d28 6 o# y }0 c* N& F# u' p" E8 p295 L7 W! e: m4 `) n+ h3 f
30 0 Y- Y$ y2 m7 P0 J& H0 Q2 g31) R' {! q, }) y0 g# w
32 * S- j% W* p3 Z5 L3 L& N33 ' Q9 u$ l1 d1 F3 a) g34 + \8 J7 B, \) p353 h* ]# G! d$ D+ q3 m) I( W- F
36 2 q% d9 F" O3 V% e7 S/ i* C37& W9 F/ x0 a9 {2 Y. y5 Q
381 A x0 p1 S0 z9 k9 [
39 + d& m: ~) k6 E( b2 X3 L40" ^ i; e! v0 @5 o9 O% R
419 Y6 ?' Z) V! S
42 - ]4 ]' f7 l: c432 J2 ?# C) o d: x9 N( s
44) U9 m! r" d1 q* {' F
45 ( h7 T7 D) K: f9 ?' G, _* |46; `( @& u V( V, T7 u
477 G; G/ [& t' {5 M1 l3 S/ Q
48! w- I6 [2 [8 B9 i
49 ! c0 m4 n9 q& Y) N50! e& j6 L' s& G1 E- h. x
51 6 k/ \2 p `% E1 k: a& m$ A- t; N, I非递归实现: E# d" @0 C, T
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。& b& E. _% Q( J& q+ W
) w- g* \7 s B 4 t) G) a2 B1 [; t' A) ^+ e- y. I, {, Z* @$ I
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。 + `* [! `: V" e# ]( b' R4 V- a. N# a& l9 m$ q9 ?6 A2 U d
还要注意区间的取值,每个区间就是一组,就有gap个元素。 ) l2 S, q9 T) z7 U" u. P, g7 W' w1 M2 c9 u0 f2 x. N6 G# ?7 b
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。 + M( i5 L5 y; W" G + e. X; y- u7 }6 m9 q- r/ X代码实现* K1 ~, I; c/ V& Q& c& ^
4 ?) n0 p# K3 W+ |) r
void MergeSortNonR(int* arr, int sz)) _' d# W- k4 D2 L8 h$ L, G0 _
{ 4 Z1 a( h& {4 k. L( p6 V& I assert(arr); % v+ m' f J+ E3 S# q$ |( ]8 n! @
int* tmp = (int*)malloc(sz * sizeof(int)); ( E# l, L4 i: @! ^$ @6 d5 T P5 U- g. E if (tmp == NULL)3 N' P& }1 B. h4 ^% L" S- E* u
{ 0 B! o% I( P$ K1 k! |) o2 q perror("malloc fail");0 s2 ]1 T9 ]1 c: V0 v
return; I) g* f/ z9 T! T/ b }2 \3 F8 }# }7 R8 z( d: U* e8 Z' N5 D! ]
$ I' C! I! H& h5 _- N int gap = 1;( h: R4 r, I* V L' g
while (gap < sz) 1 X$ J+ W0 e, b1 D0 k: [! J3 }) _ {2 G5 x8 m. X: |, t
for (int i = 0; i < sz; i += 2 * gap)" m! d, Y% Z7 ?1 X
{ 1 K# w/ G' B3 k& ]6 d } int begin1 = i, end1 = begin1 + gap - 1;5 Y- J- w/ j1 @0 E& |9 Q& H0 A
int begin2 = end1 + 1, end2 = begin2 + gap - 1;# N% v3 C5 @4 _4 E
int j = begin1;8 k3 W/ `% q3 ]- V
4 T& i9 V- |0 ?! [ //归并! s9 B, x2 m/ _. q0 K! m
while (begin1 <= end1 && begin2 <= end2) $ c6 S" _; n1 ~$ d4 U { ! B' R( T- C3 g6 `* Y6 Z if (arr[begin1] < arr[begin2]) ^( S4 I& i8 y% I+ o5 i
tmp[j++] = arr[begin1++]; / ~' a9 w+ a" f# T9 n else - Y8 ]( R }0 B; G3 e tmp[j++] = arr[begin2++];+ w* l" L* ?% Z
} 9 s: [4 M$ q- L5 D3 Z% v- F0 W. m6 H7 i, V1 i+ e" Q/ q. R
while (begin1 <= end1)7 H" j1 J* y: S0 W, Y
tmp[j++] = arr[begin1++];/ a3 B( h* b3 P: i2 P# @5 {
while (begin2 <= end2) 0 T S" ]8 X* H tmp[j++] = arr[begin2++]; 1 p+ c, [4 M3 L$ V. m- `* y # R) T6 Q# [5 I% g //拷贝回原数组——归并哪部分就拷贝哪部分回去 , x; a4 V; L# D0 T3 D# r2 G memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1)); G2 i. m4 ]: ^& e) Y/ v% `, t4 |
}2 d+ `+ T! |1 }* t, B
gap *= 2;& Z; H1 B( o+ o( E
} ' ~! j( V4 k5 |) ?& Z1 e& `4 O7 F- R' L5 ~: u
}. `% D! f9 ?1 o* s# p9 J- K% @; Q
' i' H$ i' O" g% _3 G
1' y5 [1 |% O) j# w
2) H- r! a" X/ n0 x
3( p; `. x# c! U9 H5 u' @
4 9 y% q, w& N" Y& L8 ]5 ) z- G$ N8 y# M" ]6# P9 ?0 S0 ^, S8 {1 U& j
7 # O, x' Q1 U$ A/ P D% ?8 6 i7 T# R- _2 C5 U3 [+ h- z8 C9$ ~( d7 N! C$ Q1 g+ y
10 * }$ }3 j( }: d+ k# U/ M11 3 I, u) b+ j, f* N* {! |( N0 D12 7 ~% L1 g x3 v' I/ u. ~136 M% |! h, v' D0 p" Q" V
14$ o# i* z' a9 W1 k
15 ; p1 @4 p2 y1 F& W2 E4 P: ^160 \& j4 o. l. V' B+ g6 B5 q
170 }5 P9 A- |# s% h( v: d
18- F/ p, s- n- {' Z/ p& V
192 z, u" g& z6 P x0 j
20( l$ Y' o9 x0 ], {! c( W1 X% g
21 : Z; r% y" j' n$ X( Y# r5 u22/ ]3 H. c' r1 Z/ @( D* o6 U4 G
233 Z+ g5 b: c4 r) d3 x
24( [8 L4 W8 i% }7 ^
25 * e* W$ c: [( |9 [ _26 + ?& f- R* n$ p4 m" K: a2 y) X2 i3 ?276 y- ?/ X0 X" {' G3 q
28 8 M, @5 E- [7 y y29 + w. W% ~$ M% h+ Q6 U2 L1 R* }' \30 ( y( Z) {5 H+ Q, Y31 ; C* r5 S7 ^7 D/ u32 % {/ x3 C9 t% m* o3 a- |33: f- d! @, D! F1 |8 O$ ]7 y
34( C3 y" p2 J$ F2 ]
35 + o3 q; \. ~$ @6 N" O/ W36 " d6 Z1 J# B4 N; l( N2 a2 n37) _2 N. g& n5 V+ J9 H3 {% M
38* z! b* j, z I# ~! x% ?* O
39 5 w5 U0 ~6 B9 \408 W% |3 [- U& j( l
41 4 C; y5 v( R+ ~! {5 b边界问题# H$ d# w" w7 x9 J! F) w7 G
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。 " |% U. ^) n8 ~ 0 q) q5 D' c6 t8 K) z2 a0 [举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:% j+ K- ~) Z8 }2 J/ u
0 J& o& W' Y9 |# k- A 7 J. s$ `; }9 |( Z# n 5 T1 D2 f9 G! n# z- F2 o' m由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)3 j" \! k* y' n# a( L2 T
C) |3 S4 {5 k5 v" c4 ~- H
第一组越界(即end1越界) 8 P% J$ n1 @; K 8 `, U( M9 A4 ?( ] I/ U应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。 & S5 M+ H3 ^* V8 f7 s# Z! n 8 \2 @7 h+ q; M. o+ [第二组全部越界(即begin2和end2越界)) D+ P h& k" Y" S) u
R: `# u4 s# Z: D3 e q& p! o
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。 + t9 W" U: o S ) V# a* o4 V$ I, E& }* r" s第二组部分越界(即end2越界) 9 |2 O0 P# s* ~2 T' p+ z0 |! X: |( Y4 q* `' X2 P6 ^0 s+ P
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。& C( k% C# ^% G. }6 ?/ @& {
3 T- ]1 d* z+ \; E$ G9 I
其实第一种情况和第二种情况可以合并为一种情况,原因:; s ]9 i0 V3 w% A9 r
- d. J. X; U0 r+ c+ M% \4 e C end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。 4 u+ r6 ?# B* |( z $ s5 I8 n3 o7 w0 H. f; {/ | B 拿两个数组试一下: 8 g: d$ S: I; w2 L7 _( |/ B" l: }# {1 G" B$ K
0 F- @% n1 O" e
- n6 V8 Y+ u$ u - R6 B$ a+ _$ D; [( V0 [2 e( u% y2 b6 F% L1 _4 y$ k8 }; U
代码实现4 I! S5 \5 T/ ~
1 \/ s1 Q! h* f8 i# V8 K
void MergeSortNonR(int* arr, int sz)* L: q( Q8 E1 e$ ~3 S. n
{9 z# K. I" U5 M2 ^& u
assert(arr);4 J$ u2 J! d, w4 q; I
; T/ X' F; l9 g8 C$ J3 Q7 k2 m int* tmp = (int*)malloc(sz * sizeof(int)); 6 C2 e7 }* g/ |9 h+ f if (tmp == NULL)9 R$ G: v7 _) {; F" O4 q
{- V+ \: k8 H ~7 {$ _
perror("malloc fail"); 9 ]7 }( d7 j& W( _+ y return; t, F: H0 }6 ]5 R
} 1 u. |) O9 ?( u! g" G- I8 {' X& r; ~1 R; Q9 Z2 W2 w# N
int gap = 1;. _; V. d* q1 T R5 E$ C
while (gap < sz) # x* M3 s# q* ?; c7 F# W9 L! v { / u) P; ?' S6 C% k! V, q for (int i = 0; i < sz; i += 2 * gap) ( R- h" K/ D$ L- o {0 x& Q' C, W; d j6 ?
int begin1 = i, end1 = begin1 + gap - 1;" {! N/ Z6 K- g9 v! P
int begin2 = end1 + 1, end2 = begin2 + gap - 1; 8 ^# `$ J6 H D3 ~8 S- K% G2 \+ C$ T int j = begin1;! B% a" g) O* D2 b
//越界检测 9 S+ i9 S% Z: j. G3 f2 w& u7 J if (begin2 >= sz && end2 >= sz)) {8 |% V x" t) \
break;3 h' _8 e6 V2 d q
if (end2 >= sz): i, Y! n/ {4 X% E& r) S% [
end2 = sz - 1;& I8 p, k- {7 C0 k5 t7 p4 z
//归并0 G9 u! G3 h# R _
while (begin1 <= end1 && begin2 <= end2) ! o1 H3 v; S& {3 e { 7 ` X# O/ A* X# [1 @: x if (arr[begin1] < arr[begin2]) + v4 A2 B1 m1 V) S' y! w tmp[j++] = arr[begin1++]; ! L9 I1 j! V6 ]; I- K else * e, V% }) \ Y3 D. i) i% e4 U$ x
tmp[j++] = arr[begin2++]; 1 y2 ]8 R8 n, G5 h6 ^+ e% V2 a7 R1 \ } 4 a+ Q y% N, x4 q. O6 \* T ! ?% O, D/ b7 x1 k3 C. ^& c while (begin1 <= end1) * u) g; t! m" }8 q* S tmp[j++] = arr[begin1++];& N; K, b- G, F$ a7 N6 E( q( X( f
while (begin2 <= end2) * R; S G2 X# c8 W. G+ @ tmp[j++] = arr[begin2++];+ @% l6 x2 H; u) P; c# _0 Y" E. H! |( q
$ a9 i8 ] y' n0 o9 K- K
//拷贝回原数组——归并哪部分就拷贝哪部分回去 ( [+ u5 {1 c1 _) E memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));" t! t3 { X0 I& F
} * H0 w! T" }# M& s5 `. C gap *= 2;" y! S0 F% R% s, |2 g
} . v ] T3 ]7 U: W$ {+ I5 M. ~9 r6 Y( S- T
}4 W H; M' P4 W
! Q0 m1 H9 o4 x1' M/ k% M( Y; R% }+ v
2 & ]0 b8 i/ I5 T32 r+ C9 w( t! R9 }6 D2 l, v
4 % I5 q7 D2 ]4 F: d: m* o6 A5 * J* Z2 j4 i O( f! K" v6 H6 0 R$ _! i L b1 Y1 ?( |7) c# I1 a2 E% V' X
8" N8 V: O* r5 w7 Q: f
9 1 V V0 B6 Z9 ]* H$ l- w% A10 + m: f, T8 ~) K3 d( X0 C. n: s( H110 _& i4 y) o! U( N% s: _3 G4 Y7 E8 K* P
12 3 o8 X; X7 ?3 D0 \7 J13 6 S/ d% L1 M! a- F# E147 ~: }( H+ S0 A
15' h9 [" ?2 d3 [# D8 A! O. k& `
16( I- ?' `+ _. t% n& s
177 r( r/ v9 w ?0 E
18& }, u m6 Y+ T# q3 `1 u8 b
19 . K" t Y% I' Q0 G Z3 [7 w20 ) h' K. h$ \% D' W21 8 A ~7 ~; d U22 4 C8 J4 p7 q$ r+ g8 b233 L' S0 ^& g. l
24 # r$ q- p) t2 W' W3 l' n25! n& K' _: h8 @2 P& F: o& t4 Y
26 ! R [- a8 r2 U! _. a7 W9 [3 R27 ) J5 `' J+ ^) u28 ( e9 K j+ u& q. i- p0 S29 1 d% o+ \0 n' p- ]6 A5 A30 7 D" {2 [' Z+ M318 k! p1 Y3 _; h$ ?( _
32 - R# e8 y3 R9 r9 W& u33 / K1 H, @6 T; i7 Q% k# d8 I34, F9 M+ p7 p9 i+ @* H$ D
35 9 ~ A/ ~. ^ @4 L0 {5 j* Z36 n* X/ s) \& k2 i9 I2 c
37' j# }' Q( _' }5 J) B
38. n1 X1 h4 ^3 N. K
39" A1 q& v% @+ v0 R1 ^/ G6 Z
40 , V0 p! I) x5 f1 k" H41 ! x( ^/ g* V: f. H$ O429 y* e q3 C. c# h& i! t) p* z7 U
43% u y' l+ S2 }
447 X/ T2 N2 C6 W7 g: a
45 4 `8 X% \! P# K" g! o# Y/ \' l归并排序的特性总结: S0 h/ h+ L3 p5 Y0 }. u
, s7 [. E* b/ @
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。 9 q9 s$ Y+ E5 V: D时间复杂度:O(N*logN) * C! s7 W5 M3 h: x1 @& @3 ~( f空间复杂度:O(N), y1 e: q- k+ i, p4 S2 S0 B
稳定性:稳定 : X7 |! P) l' K. I; m; W$ ?4 M; \/ L% _
———————————————— / y# J( u# H# S6 c$ `9 e版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。. f0 C5 B; ?; ~
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657- \ r6 x( @5 w4 I
m3 R" _$ B- B K1 a( ]6 U
" o' ~- }; f4 G